上一篇咱们讲解了如何经过 EventChannel 实现 Android -> Flutter 的通讯。git
而且也看到了 Flutter 内部 EventChannel 源码也是对 MethodChannel 的封装。github
所以这篇咱们来讲下如何经过 MethodChannel 实现 Android -> Flutter 的通讯。less
至于 Flutter -> Android 的通讯,没看过的小伙伴建议看下以前的文章 Flutter 即学即用系列博客——08 MethodChannel 实现 Flutter 与原生通讯。异步
既然咱们以前写过 Flutter -> Android 的 MethodChannel,那么咱们如今要写 Android -> Flutter 的 MethodChannel,能够仿照一下原先的写法。async
步骤以下:ide
第一步:Flutter UI 修改debug
咱们的代码在上一篇的基础上作修改,在列上面增长一个文本用于确认收到了 Android 的请求。code
String _arguments = 'unknown'; Text(_arguments),
第二步:在 Android 端写 invokeMethod 引用 Flutter 方法orm
methodChannel.invokeMethod("getContent", "arguments", new MethodChannel.Result() { @Override public void success(@Nullable Object o) { Log.e(TAG, "success="+o); } @Override public void error(String s, @Nullable String s1, @Nullable Object o) { Log.e(TAG, "error="+s); } @Override public void notImplemented() { Log.e(TAG, "notImplemented"); } });
参数说明:
第一个为方法名。用于 Flutter 区分 Android 的不一样请求。
第二个为参数值。用于 Android 须要给 Flutter 传递的额外数据。
第三个为 Android -> Flutter 请求的结果回调。
回调有三种状况:
1)调用成功
2)调用失败
3)Flutter 未实现对应方法blog
第三步:在 Flutter 调用对应 MethodChannel 的 setMethodCallHandler
methodChannel.setMethodCallHandler((MethodCall call){ if (call?.method == 'getContent') { setState(() { _arguments = call?.arguments ?? ''; }); } });
看到这里的 MethodCall 你应该很熟悉了,经过 call.method 能够知道 Android 要获取的方法名,经过 call.arguments 能够拿到 Android 传递过来的数据。
这里的 getContent 对应 Android 的 invokeMethod。
为了确认咱们获取到了,咱们将 Android 传递过来的参数显示出来。
第四步:运行
能够看到效果以下:
初始显示 unknown
点击后显示原生传过来的内容
同时控制台显示打印信息以下:
success=null
咱们发现 Android 确实回调成功了,可是另外一个问题随之而来,Flutter 如何将内容回调给 Android?
解决问题一时爽,一直解决问题一直爽。
也是很简单的,就是咱们写一个异步方法将信息带回去便可。
在 setState 方法后面添加下面代码:
return returnToRaw();
具体方法实现以下:
Future<String> returnToRaw() async { return 'received your message'; }
这个时候再运行点击按钮会发现控制台打印以下信息:
success=received your message
能够看到成功收到返回值了。
这里演示返回的是字符串,所以异步方法返回类型是 Future
若是但愿回调 notImplemented,不要在 Flutter 调用 MethodChannel 的 setMethodCallHandler 或者 setMethodCallHandler 的参数设置为 null 便可。
//方法一 // methodChannel.setMethodCallHandler((MethodCall call){ // if (call?.method == 'getContent') { // setState(() { // _arguments = call?.arguments ?? ''; // }); // return returnToRaw(); // } // }); //方法二 methodChannel.setMethodCallHandler(null);
若是但愿回调 error,修改 returnToRaw 方法便可。以下:
Future<String> returnToRaw() async { throw PlatformException(code: 'error code'); }
这里经过抛出 PlatformException 并将错误信息带回去给 Android。
通常错误信息除非是手动须要抛,不然源码会帮咱们处理的。
这里是为了演示因此手动抛出异常。
好了,至此 MethodChannel Android-> Flutter 咱们也实现了。
其实不论是 Android -> Flutter 仍是 Flutter-> Android,都是平台相关代码。
所以能够直接到 platform_channel.dart 里面看看源码。
除了 EventChannel、MethodChannel,还有 BasicMessageChannel 和 OptionalMethodChannel,这些就交给小伙伴们本身去研究了。
这边分享一下研究 MethodChannel 实现 Android -> Flutter 的过程遇到的坑。
但愿不止是授你们以鱼,更是授你们以渔。
坑1:一开始将原生 MethodChannel 写到外面,致使 Flutter 没收到请求
由于 Flutter 是在 initState 里面去 setMethodCallHandler 的,而 debug 模式下可能 Flutter 还没加载完成,这个时候发送消息,Flutter 就可能没收到。
后面改为点击以后 Flutter -> Android,Android 再发给 Flutter。
这个问题是异步的缘由致使的。
明确以后经过正确的方式就能够收到请求了。
坑2:Flutter 收到以后,如何回调回消息呢?
首先点击进入 setMethodCallHandler 源码,以下:
void setMethodCallHandler(Future<dynamic> handler(MethodCall call)) { BinaryMessages.setMessageHandler( name, handler == null ? null : (ByteData message) => _handleAsMethodCall(message, handler), ); }
再深刻 _handleAsMethodCall,以下:
Future<ByteData> _handleAsMethodCall(ByteData message, Future<dynamic> handler(MethodCall call)) async { final MethodCall call = codec.decodeMethodCall(message); try { return codec.encodeSuccessEnvelope(await handler(call)); } on PlatformException catch (e) { return codec.encodeErrorEnvelope( code: e.code, message: e.message, details: e.details, ); } on MissingPluginException { return null; } catch (e) { return codec.encodeErrorEnvelope(code: 'error', message: e.toString(), details: null); } }
到这里就比较明朗了。
能够看到错误基本不用咱们处理,也没有太多可介入空间。
可是成功回调,这里核心语句是
await handler(call)
所以咱们上面经过一个异步方法返回字符串给原生。
因为笔者以前对 Future 不是很熟,所以为了解决这个问题,看了 dart 源码👇:
https://www.dartlang.org/tutorials/language/futures
至此,结合系列博客 08 基本就完成了 MethodChannel 相关的双向通讯讲解了。
源码位置:
https://github.com/nesger/FlutterSample/tree/feature/method_channel_reverse
更多阅读:
Flutter 即学即用系列博客
Flutter 即学即用系列博客——01 环境搭建
Flutter 即学即用系列博客——02 一个纯 Flutter Demo 说明
Flutter 即学即用系列博客——03 在旧有项目引入 Flutter
Flutter 即学即用系列博客——04 Flutter UI 初窥
Flutter 即学即用系列博客——05 StatelessWidget vs StatefulWidget
Flutter 即学即用系列博客——06 超实用 Widget 集锦
Flutter 即学即用系列博客——07 RenderFlex overflowed 引起的思考
Flutter 即学即用系列博客——08 MethodChannel 实现 Flutter 与原生通讯
Flutter 即学即用系列博客——09 EventChannel 实现原生与 Flutter 通讯(一)
Flutter & dart
dart 如何优雅的避空
Flutter map 妙用及 .. 使用