Как я могу вызвать обратный вызов приложения из пакета system_alert_window - PullRequest
0 голосов
/ 09 июля 2020

Я использую https://pub.flutter-io.cn/packages/system_alert_window, и он запускает службу переднего плана. Эта служба переднего плана вызывает следующий обратный вызов, когда событие нажатия кнопки происходит в окне системного предупреждения.

Это мой обратный вызов, это метод stati c

  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);
    }
  });
}

Но я получаю следующее исключение при попытке использовать метод плагина в обратном вызове

[ОШИБКА: flutter / lib / ui / ui_dart_state. cc (157)] Необработанное исключение: MissingPluginException (Не найдено реализации для метода launchApp на канале 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);
        }
    }
}

Похоже, это порождает изоляцию для запуска обратного вызова. Поэтому, когда мой обратный вызов запускается, он будет запущен на отдельном изоляте.

Согласно этому сообщению

сообщение github

Единственный способ справиться при этом следует использовать плагин IsolateHandler. Но разве это тоже не плагин?

Желаемое поведение состоит в том, что я могу вызвать плагин из обратного вызова.

Примечание: это происходит с любым плагином, который я пытаюсь вызвать с обратного звонка

1 Ответ

1 голос
/ 09 июля 2020

Ваша ошибка

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

не принадлежит окну системных предупреждений плагину.

Причина, по которой вы получаете исключение отсутствующего плагина, заключается в том, что, flutter_appavailability плагин не поддерживает фоновое выполнение.

Итак, чтобы это работало, вы должны использовать изолированную связь, чтобы передать обратный вызов от system_alert_window к основному потоку, а затем вызвать этот плагин. Здесь упоминается

Простой способ определить, поддерживает ли плагин фоновое выполнение, - это увидеть, требуется ли регистрировать плагин в application.class или application.kt

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...