jiusanzhou / flutter_floatwing

A Flutter plugin that makes it easier to make floating/overlay window for Android with pure Flutter. 一个可以用纯粹的Flutter来开发Android浮动窗口的插件。
Other
169 stars 28 forks source link

Open window with data shared from parent app #24

Open rorystephenson opened 5 months ago

rorystephenson commented 5 months ago

Thanks for this plugin @jiusanzhou.

I have a use case where I want to open a window and immediately show some data passed from the parent app to the window. I don't want to start FloatwingPlugin until the user actually needs to see the window because some users never use windows so it is unnecessary to have it always running.

I am using the following code to start the app and show the window:

  Future<void> _initAsyncState() async {
    await FloatwingPlugin().initialize();

    // get permission first
    if (!await FloatwingPlugin().checkPermission()) {
      FloatwingPlugin().openPermissionSetting();
      return Future.value(false);
    }

    await FloatwingPlugin().isServiceRunning().then((running) async {
      if (!running)
        await FloatwingPlugin().startService().then((_) {
          print("start the background service success.");
        });
    });
    final existingWindow = FloatwingPlugin().windows[_window.id];
    if (existingWindow != null) {
      _window.share(
        'Re-opened at ${DateTime.now().second % 60}',
        name: 'myOverlayData',
      );
    } else {
      _window.on(EventType.WindowStarted, (window, data) {
        _window.share(
          'Opened at ${DateTime.now().second % 60}',
          name: 'myOverlayData',
        );
      });
      await _window.create(start: true);
    }
  }

My window is run via an entrypoint:

@pragma("vm:entry-point")
void overlayMain() {
  WidgetsFlutterBinding.ensureInitialized();
  runApp(NormalView().floatwing(app: true));
}

The NormalView widget listens to shared data in the initState like so:

  @override
  void initState() {
    super.initState();

    WidgetsBinding.instance.addPostFrameCallback((_) {
      _window = Window.of(context);
      _window?.onData((source, name, data) async {
        if (name != 'myOverlayData') return;

        debugPrint('*' * 80);
        debugPrint('Got data: $data, from: $source, name: $name');
        debugPrint('*' * 80);
        setState(() => _data = data);
      });
    });
  }

When I open the window the data is null, probably because the onData listener is registered after _window.share() gets called so it misses the data. If I run _initAsyncState() again it successfully passes the data with the 'Re-opened...' message, so the data sharing is working.

Is there a way to make sure the window is ready to receive the data instead so it doesn't get missed whilst the window is opening? If not, one potential solution for this problem would be to add a new EventType.WindowListen event which gets triggered when the window starts listening to data, then the shareData call can be placed in this callback.

WDYT?