如何从 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
处理这个问题的唯一方法是使用 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.class
或 application.kt
中注册插件
我正在使用 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
处理这个问题的唯一方法是使用 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.class
或 application.kt