前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Flutter 即学即用系列博客——09 MethodChannel 实现原生与 Flutter 通信(二)

Flutter 即学即用系列博客——09 MethodChannel 实现原生与 Flutter 通信(二)

作者头像
AndroidTraveler
发布2019-04-25 15:17:32
1.2K0
发布2019-04-25 15:17:32
举报
文章被收录于专栏:AndroidTravelerAndroidTraveler
前言

上一篇我们讲解了如何通过 EventChannel 实现 Android -> Flutter 的通信。

并且也看到了 Flutter 内部 EventChannel 源码也是对 MethodChannel 的封装。

因此这篇我们来说下如何通过 MethodChannel 实现 Android -> Flutter 的通信。

至于 Flutter -> Android 的通信,没看过的小伙伴建议看下之前的文章 Flutter 即学即用系列博客——08 MethodChannel 实现 Flutter 与原生通信

既然我们之前写过 Flutter -> Android 的 MethodChannel,那么我们现在要写 Android -> Flutter 的 MethodChannel,可以仿照一下原先的写法。

步骤如下:

第一步:Flutter UI 修改

我们的代码在上一篇的基础上做修改,在列上面增加一个文本用于确认收到了 Android 的请求。

代码语言:javascript
复制
String _arguments = 'unknown';Text(_arguments),

第二步:在 Android 端写 invokeMethod 引用 Flutter 方法

代码语言:javascript
复制
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 未实现对应方法

第三步:在 Flutter 调用对应 MethodChannel 的 setMethodCallHandler

代码语言:javascript
复制
methodChannel.setMethodCallHandler((MethodCall call){    if (call?.method == 'getContent') {      setState(() {        _arguments = call?.arguments ?? '';      });    }});

看到这里的 MethodCall 你应该很熟悉了,通过 call.method 可以知道 Android 要获取的方法名,通过 call.arguments 可以拿到 Android 传递过来的数据。

这里的 getContent 对应 Android 的 invokeMethod。

为了确认我们获取到了,我们将 Android 传递过来的参数显示出来。

第四步:运行

可以看到效果如下:

初始显示 unknown

点击后显示原生传过来的内容

同时控制台显示打印信息如下:

代码语言:javascript
复制
success=null

我们发现 Android 确实回调成功了,但是另一个问题随之而来,Flutter 如何将内容回调给 Android?

解决问题一时爽,一直解决问题一直爽。

也是很简单的,就是我们写一个异步方法将信息带回去即可。

在 setState 方法后面添加下面代码:

代码语言:javascript
复制
return returnToRaw();

具体方法实现如下:

代码语言:javascript
复制
Future<String> returnToRaw() async {  return 'received your message';}

这个时候再运行点击按钮会发现控制台打印如下信息:

代码语言:javascript
复制
success=received your message

可以看到成功收到返回值了。

这里演示返回的是字符串,因此异步方法返回类型是 Future<String>。如果你要返回其他类型,可以自行修改。

如果希望回调 notImplemented,不要在 Flutter 调用 MethodChannel 的 setMethodCallHandler 或者 setMethodCallHandler 的参数设置为 null 即可。

代码语言:javascript
复制
    //方法一//    methodChannel.setMethodCallHandler((MethodCall call){//        if (call?.method == 'getContent') {//          setState(() {//            _arguments = call?.arguments ?? '';//          });//          return returnToRaw();//        }//    });    //方法二    methodChannel.setMethodCallHandler(null);

如果希望回调 error,修改 returnToRaw 方法即可。如下:

代码语言:javascript
复制
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 源码,如下:

代码语言:javascript
复制
void setMethodCallHandler(Future<dynamic> handler(MethodCall call)) {  BinaryMessages.setMessageHandler(    name,    handler == null ? null : (ByteData message) => _handleAsMethodCall(message, handler),  );}

再深入 _handleAsMethodCall,如下:

代码语言:javascript
复制
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);  }}

到这里就比较明朗了。

可以看到错误基本不用我们处理,也没有太多可介入空间。

但是成功回调,这里核心语句是

代码语言:javascript
复制
await handler(call)

因此我们上面通过一个异步方法返回字符串给原生。

由于笔者之前对 Future 不是很熟,因此为了解决这个问题,看了 dart 源码?: https://www.dartlang.org/tutorials/language/futures

至此,结合系列博客 08 基本就完成了 MethodChannel 相关的双向通信讲解了。

源码位置: https://github.com/nesger/FlutterSample/tree/feature/method_channel_reverse

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-03-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 安卓小煜 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 后记
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档