Unable to take screenshot in V2 Flutter using native code, it was working well in V1 Flutter
Asked Answered
D

1

14

We are building an SDK that will take screenshots of an app once it is integrated. We are able to take screenshots for Native Android, Native iOS, Cordova, IONIC, React Native, Xamarin platforms. However unable to take a snapshot in V2 Flutter. The code was working fine until V1 Flutter as well. But when the same native code when executed on V2 Flutter returns a BLACK screenshot of the app.

The issue here is that V1's FlutterView was publicly available to third party plugins using a method called registrar.view(), in V2 this view is not exposed to any plugins now! https://api.flutter.dev/javadoc/io/flutter/plugin/common/PluginRegistry.Registrar.html Using V1's FlutterView we were able to capture the screenshot of the view(s) using PixelCopy, we are not able to get V2's FlutterView and we did not find any solution to capture that as well.

We have tried the following, but with no success. Can someone help me out here?

  1. Tried to get the activity from context we pass in our SDK initialization, we took view from activity and tried to paint it, blank screenshots being captured
  2. Tried to migrate the SDK Flutter Plugin to V2 using https://flutter.dev/docs/development/packages-and-plugins/plugin-api-migration
  3. Tried to traverse view hierarchy and paint the views using Activity context, blank screenshots being captured
  4. Tried to paint the view received from FlutterActivity.getWindow().getDecorView().getRootView(), blank screenshots being captured.
Dichlamydeous answered 26/5, 2020 at 12:9 Comment(1)
Did you solve it ?Marthena
E
1

You can look at how the Screenshoot package code on its GitHub is doing it. The package is up-to-date to Flutter v2.

The package uses:

  • Gets the render object of the current widget thanks to GlobalKey. GlobalKey _containerKey = GlobalKey().currentContext?.findRenderObject();
  • Then it converts to RenderRepaintBoundary. RenderRepaintBoundary boundary = findRenderObject as RenderRepaintBoundary;
  • It gets the pixel ratio of the device. pixelRatio = pixelRatio ?? MediaQuery.of(context).devicePixelRatio;
  • Finally, it creates the image. ui.Image image = await boundary.toImage(pixelRatio: pixelRatio ?? 1);

See the whole code below:

Future<ui.Image?> captureAsUiImage(
      {double? pixelRatio: 1,
      Duration delay: const Duration(milliseconds: 20)}) {
    //Delay is required. See Issue https://github.com/flutter/flutter/issues/22308
    return new Future.delayed(delay, () async {
      try {
        var findRenderObject =
            this._containerKey.currentContext?.findRenderObject();
        if (findRenderObject == null) {
          return null;
        }
        RenderRepaintBoundary boundary =
            findRenderObject as RenderRepaintBoundary;
        BuildContext? context = _containerKey.currentContext;
        if (pixelRatio == null) {
          if (context != null)
            pixelRatio = pixelRatio ?? MediaQuery.of(context).devicePixelRatio;
        }
        ui.Image image = await boundary.toImage(pixelRatio: pixelRatio ?? 1);
        return image;
      } catch (Exception) {
        throw (Exception);
      }
    });
  }

Edmondedmonda answered 1/10, 2021 at 11:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.