Flutter踩坑:原生安卓页面向Flutter通信
前言
在 Flutter APP
的开发过程中,有时不仅需要使用 Flutter
提供的组件,还需要使用原生的组件。
例如在对接外部 SDK
时,如果自己重新实现 SDK
的逻辑,无疑是本末倒置。
前文中我们已经接入并且打开了原生安卓的页面,也就是说主动通信已经完成。
真实的项目中,肯定不可能只有 Flutter
向原生安卓通信,肯定也原生安卓向 Flutter
发送信息。
操作其实很简单,就是将 method channel
的调用,反过来,由原生执行 invokeMethod
,由 Flutter
接收 method
。
但是这里面有很多坑。
执行
在插件中实例化MethodChannel
,并且注册 MethodCallHandler
。
同时将这个 MethodChannel
放到静态变量中,以便在 Java
页面中调用。
这个我在网上搜了很多方式,都是让实例化 Flutter Engine
或者实例化 plugin
插件,但是实际上都没能成功,估计重新实例化的已经不是当前的这个 Flutter Engine
实例或者插件实例了。
// 省略import
public class TestPlugin implements FlutterPlugin, MethodCallHandler,ActivityAware {
static public MethodChannel channel;
private Activity activity;
@Override
public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) {
TestPlugin.channel = new MethodChannel(flutterPluginBinding.getBinaryMessenger(), "test_plugin");
TestPlugin.channel.setMethodCallHandler(this);
}
static public MethodChannel getChannel(){
return TestPlugin.channel;
}
@Override
public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) {
System.out.println( "================ 收到方法调用 ==========");
System.out.println( call.method);
if (call.method.equals("openNativePage")) {
if (activity != null) {
Intent intent = new Intent(activity, MainActivity.class);
activity.startActivity(intent);
result.success("Native page opened");
} else {
result.error("ACTIVITY_NOT_AVAILABLE", "Activity is not available", null);
}
} else {
result.notImplemented();
}
}
@Override
public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
TestPlugin.channel.setMethodCallHandler(null);
}
@Override
public void onAttachedToActivity(@NonNull ActivityPluginBinding binding) {
activity = binding.getActivity();
}
@Override
public void onDetachedFromActivityForConfigChanges() {
activity = null;
}
@Override
public void onReattachedToActivityForConfigChanges(@NonNull ActivityPluginBinding binding) {
activity = binding.getActivity();
}
@Override
public void onDetachedFromActivity() {
activity = null;
}
}
Java
页面中的调用
TestPlugin.getChannel().invokeMethod("onMessageReceived", "这里是发送的信息");
在 Flutter
页面中接收到信息
MethodChannel("test_plugin").setMethodCallHandler((call) async {
print("接到方法调用: ${call.method}");
if (call.method == 'onMessageReceived') {
final String message = call.arguments as String;
print('========aaa Received message from android: $message');
// TODO: 处理接收到的信息
}
});
总结
原生向 Flutter
发送信息时,会遇到许多莫名其妙的问题,网上搜了很多方法,但是都无效。
例如安卓原生页面直接继承 FlutterActivity
,重新拿到 FlutterEngine
实例然后实例化MethodChannel
,但是真机调试时报设备不支持GooglePlay服务。
还有直接实例化插件类等等方式都不能成功。
因此我换用了在插件中直接使用静态变量传递已经初始化好的 MethodChannel
,果然奏效。
当然,我觉得这个问题应该有更好的解决方案,但是目前没有找到,先使用这个方式解决问题,以作记录。