如何从 system_alert_window 包中调用应用范围内的回调

How can I call an app scoped callback from the system_alert_window package

我正在使用 https://pub.flutter-io.cn/packages/system_alert_window,它启动了一个前台服务。当系统警报中发生按钮单击事件时,此前台服务会调用以下回调 window。

这是我的回调,是一个静态方法

  static Future<void> systemOverlayOnClickListner(String value) async {
    if (value == 'button_app_to_foreground') {
      await SystemAlertWindow.closeSystemWindow();
      await AppAvailability.launchApp('com.company_name.app_name');
    }
  }

这是插件中注册回调的方法

  static Future<bool> registerOnClickListener(
      OnClickListener callBackFunction) async {
    final callBackDispatcher =
        PluginUtilities.getCallbackHandle(callbackDispatcher);
    final callBack = PluginUtilities.getCallbackHandle(callBackFunction);
    _channel.setMethodCallHandler((MethodCall call) {
      print("Got callback");
      switch (call.method) {
        case "callBack":
          dynamic arguments = call.arguments;
          if (arguments is List) {
            final type = arguments[0];
            if (type == "onClick") {
              final tag = arguments[1];
              callBackFunction(tag);
            }
          }
      }
      return null;
    });
    await _channel.invokeMethod("registerCallBackHandler",
        <dynamic>[callBackDispatcher.toRawHandle(), callBack.toRawHandle()]);
    return true;
  }

这是调用回调的顶级方法

void callbackDispatcher() {
  // 1. Initialize MethodChannel used to communicate with the platform portion of the plugin
  const MethodChannel _backgroundChannel =
      const MethodChannel(Constants.BACKGROUND_CHANNEL);
  // 2. Setup internal state needed for MethodChannels.
  WidgetsFlutterBinding.ensureInitialized();

  // 3. Listen for background events from the platform portion of the plugin.
  _backgroundChannel.setMethodCallHandler((MethodCall call) async {
    final args = call.arguments;
    // 3.1. Retrieve callback instance for handle.
    final Function callback = PluginUtilities.getCallbackFromHandle(
        CallbackHandle.fromRawHandle(args[0]));
    assert(callback != null);
    final type = args[1];
    if (type == "onClick") {
      final tag = args[2];
      // 3.2. Invoke callback.
      callback(tag);
    }
  });
}

但是在回调中尝试使用插件方法时出现以下异常

[ERROR:flutter/lib/ui/ui_dart_state.cc(157)] Unhandled Exception: MissingPluginException(No implementation found for method launchApp on channel com.pichillilorenzo/flutter_appavailability)

据我所知,这就是问题所在。 registerOnClick 监听器将调用方法通道。此方法通道将执行以下操作

    case "registerCallBackHandler":
        try {
            List arguments = (List) call.arguments;
            if (arguments != null) {
                long callbackHandle = Long.parseLong(String.valueOf(arguments.get(0)));
                long onClickHandle = Long.parseLong(String.valueOf(arguments.get(1)));
                SharedPreferences preferences = mContext.getSharedPreferences(Constants.SHARED_PREF_SYSTEM_ALERT_WINDOW, 0);
                preferences.edit().putLong(Constants.CALLBACK_HANDLE_KEY, callbackHandle)
                        .putLong(Constants.CODE_CALLBACK_HANDLE_KEY, onClickHandle).apply();
                startCallBackHandler(mContext);
                result.success(true);
            } else {
                Log.e(TAG, "Unable to register on click handler. Arguments are null");
                result.success(false);
            }
        }

因此正在调用 startcallback 处理程序

public static void startCallBackHandler(Context context) {
    SharedPreferences preferences = context.getSharedPreferences(Constants.SHARED_PREF_SYSTEM_ALERT_WINDOW, 0);
    long callBackHandle = preferences.getLong(Constants.CALLBACK_HANDLE_KEY, -1);
    Log.d(TAG, "onClickCallBackHandle " + callBackHandle);
    if (callBackHandle != -1) {
        FlutterMain.ensureInitializationComplete(context, null);
        String mAppBundlePath = FlutterMain.findAppBundlePath();
        FlutterCallbackInformation flutterCallback = FlutterCallbackInformation.lookupCallbackInformation(callBackHandle);
        if (sBackgroundFlutterView == null) {
            sBackgroundFlutterView = new FlutterNativeView(context, true);
            if(mAppBundlePath != null && !sIsIsolateRunning.get()){
                if (sPluginRegistrantCallback == null) {
                    Log.i(TAG, "Unable to start callBackHandle... as plugin is not registered");
                    return;
                }
                Log.i(TAG, "Starting callBackHandle...");
                FlutterRunArguments args = new FlutterRunArguments();
                args.bundlePath = mAppBundlePath;
                args.entrypoint = flutterCallback.callbackName;
                args.libraryPath = flutterCallback.callbackLibraryPath;
                sBackgroundFlutterView.runFromBundle(args);
                sPluginRegistrantCallback.registerWith(sBackgroundFlutterView.getPluginRegistry());
                backgroundChannel = new MethodChannel(sBackgroundFlutterView, Constants.BACKGROUND_CHANNEL);
                sIsIsolateRunning.set(true);
            }
        }else {
            if(backgroundChannel == null){
                backgroundChannel = new MethodChannel(sBackgroundFlutterView, Constants.BACKGROUND_CHANNEL);
            }
            sIsIsolateRunning.set(true);
        }
    }
}

这似乎为 运行 回调生成了一个隔离。因此,当我的回调被触发时,它将在单独的隔离中触发。

据此post

github post

处理这个问题的唯一方法是使用 IsolateHandler 插件。不过这不也是个插件吗?

所需的行为是我可以从回调中调用插件。

注意:我尝试从回调中调用的任何插件都会发生这种情况

你的错误

[ERROR:flutter/lib/ui/ui_dart_state.cc(157)] Unhandled Exception: 
MissingPluginException(No implementation found for method launchApp on channel
com.pichillilorenzo/flutter_appavailability)

不属于 system alert window 插件。

您遇到缺少插件异常的原因是,flutter_appavailability插件不支持后台执行。

因此,要使其正常工作,您必须使用隔离通​​信将回调从 system_alert_window 带到主线程,然后调用此插件。其中提到here

如果插件支持后台执行,一个简单的识别方法是查看是否需要在 application.classapplication.kt

中注册插件