上一篇博客主要介绍了MethodChannel的使用方式
Flutter与Native通信的方式:MethodChannel
这篇博客接着讲另外两种通信方式
EventChannel和BasicMessageChannel
EventChannel用于从native向flutter发送通知事件,例如flutter通过其监听Android的重力感应变化等。与MethodChannel不同,EventChannel是native到flutter的单向调用,调用是多播(一对多)的,可以类比成Android的Brodcast。
BasicMessageChannel用于在flutter和native互相发送消息,一方给另一方发送消息,收到消息之后给出回复。它和MethodChannel的区别重在一个消息的回复
首先是Flutter端代码,创建一个EventChannel并约定好字段:
static const EventChannel _channel = EventChannel('tofluttereventchannel');
然后写好被调用的方法:
void _enableEventReceiver() {
//延时3s,先让 Android 端的 EventChannel 进行初始化 , 然后在 Flutter 端注册 EventChannel 监听
//这样才能确保连接成功
Future.delayed(const Duration(milliseconds: 5000), () {
_streamSubscription =
_channel.receiveBroadcastStream().listen((dynamic event) {
print('收到消息 event: $event');
setState(() {
mMessage = event;
});
}, onError: (dynamic error) {
print('出现错误 error: ${error.message}');
setState(() {
errmMessage = error.message;
});
});
});
}
_enableEventReceiver方法可以放到Widget的initState()中初始化
在dispose()中调用以下取消监听的方法:
void _disableEventReceiver() {
if (_streamSubscription != null) {
print("flutter断开连接");
//断开连接,这里也会触发android端的onCancel方法
_streamSubscription?.cancel();
_streamSubscription = null;
}
}
然后来到Android端,定义两个对象
一个是EventChannel,一个是EventSink:
private lateinit var channel: EventChannel
var eventSink: EventChannel.EventSink? = null
继续在configureFlutterEngine方法中做处理:
channel = EventChannel(flutterEngine.dartExecutor, "tofluttereventchannel")
channel.setStreamHandler(
object : EventChannel.StreamHandler {
override fun onListen(arguments: Any?, events: EventChannel.EventSink) {
Log.d("MyFlutterActivity", "已建立连接")
eventSink = events
}
override fun onCancel(arguments: Any?) {
Log.d("MyFlutterActivity", "已断开连接")
}
})
可以看到,其实就是在建立连接后对EventSink对象进行赋值
当eventSink 赋值后,就可以拿他进行消息的发送了
比如:
override fun onResume() {
super.onResume()
//这里延时执行是为了模拟eventSink初始化后,我们在业务里面进行消息的发送
Handler().postDelayed({
eventSink?.success("这是来自安卓的消息")
//执行了endOfStream后,再发送消息就无效了,所以这行代码要放到endOfStream上面执行
eventSink?.error("error code", "这是来自安卓的错误消息", "error details")
//结束通信,这时候onCancel会被调用
eventSink?.endOfStream()
}, 6000)
}
这样EventChannel的使用就介绍完了
在实际运行时,可能会发现不起作用
归根结底是注册和调用顺序问题
所以最好在Flutter先延迟一下注册监听
让 Android 端的 EventChannel 先建立连接,
然后在 Flutter 端注册 EventChannel 监听
这样才能确保连接成功
所以用 Future.delayed 进行延时操作
具体可以参考这篇博客:
Flutter 混合开发报错
MessageChannel重在回调后的消息回复
相对与其他Channel类型的创建,MessageChannel的创建除了channel名以外,还需要指定编码方式。
因为发送的消息会以二进制的形式进行处理,所以要针对不同类型的数进行二进制编码
主要方式有:
下面看具体使用
Flutter端,首先定义BasicMessageChannel
static const messageChannel = BasicMessageChannel('tofluttemessagechannel', StringCodec());
发送消息这样写:
///发送MessageChannel消息,延时一下,确保安卓端先注册了监听才能收到
void _sendMessage() {
Future.delayed(const Duration(milliseconds: 6000), () async {
final String? result = await messageChannel.send('来自flutter主动发送的消息');
print("收到安卓端的返回值:${result}");
});
}
可以看到发送后会拿到返回值result
注册回调,也就是接受消息这样写:
//注册MessageChannel消息监听
messageChannel.setMessageHandler((message) async {
print('收到安卓端的MessageChannel消息 = $message');
setState(() {
forNativeMsg = message ?? "";
});
return '来自flutter返回的消息';
});
//发送MessageChannel消息
可以看到接收到后也会给到Android端一个返回值
利用BasicMessageChannel,我们就很快的完成了消息的发送和接收
并且每一个操作都可以接受或者传送返回值
Android端其实和Flutter端几乎一样
首先是定义BasicMessageChannel
//先注册MessageChannel
val messageChannel = BasicMessageChannel(
flutterEngine.dartExecutor,
"tofluttemessagechannel",
StringCodec.INSTANCE)
发送消息:
//发送消息
Handler().postDelayed({
messageChannel.send("来自安卓端主动发送的消息") { result ->
Log.d("MyFlutterActivity", "收到flutter端的返回值:$result")
}
}, 500)
注册回调,也就是接受消息
//先注册监听
messageChannel.setMessageHandler { message, reply ->
Log.d("MyFlutterActivity", "收到flutter端的MessageChannel消息:"+message)
reply.reply("来自安卓端返回的消息")
}
这里其实也要注意一个顺序问题
总结起来就是:先注册,后发送
先让被回调的那一端注册监听完成后
再去跨端调用,也就是发送消息
最后来总结一下三种方式的区别:
通信方式 | 双端通信 | 指定编码 | 注册顺序 | 使用场景 |
---|---|---|---|---|
MethodChannel | 支持 | 否 | 不需要延时注册 | 方法调用 |
EventChannel | Native单向调用Flutter | 否 | 先建立连接再监听 | 广播通知 |
BasicMessageChannel | 支持 | 是 | 先注册,再监听 | 用于传递字符串和半结构化的消息 |
源码地址:
EventChannel和BasicMessageChannel
这是一份全面 & 详细的Android Native与Flutter的通信方式 学习指南