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;@Overridepublic void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) {TestPlugin.channel = new MethodChannel(flutterPluginBinding.getBinaryMessenger(), "test_plugin");TestPlugin.channel.setMethodCallHandler(this);}static public MethodChannel getChannel(){return TestPlugin.channel;}@Overridepublic 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();}}@Overridepublic void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {TestPlugin.channel.setMethodCallHandler(null);}@Overridepublic void onAttachedToActivity(@NonNull ActivityPluginBinding binding) {activity = binding.getActivity();}@Overridepublic void onDetachedFromActivityForConfigChanges() {activity = null;}@Overridepublic void onReattachedToActivityForConfigChanges(@NonNull ActivityPluginBinding binding) {activity = binding.getActivity();}@Overridepublic 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
,果然奏效。
当然,我觉得这个问题应该有更好的解决方案,但是目前没有找到,先使用这个方式解决问题,以作记录。