Flutter 與原生插件主要是透過通道來溝通,除了 Flutter 官網上所展示的 MethodChannel 外, 還有 EventChannel 及 MessageChannel. 他們之間的最大不同點是: EventChanel 僅能單向從原生插件端往 Flutter 平台推送資料流, 也就是說原生插件是主動發送端, Fultter 處於被動的接收資料流, 而 MethodChannel 主動權是在 Flutter 端, 原生插件處在被動回應的角色, 嚴格來說是半雙工通道(需求發送完要等待回應), 至於 MessageChannel, 視情況兩端都能各自指定為主動端或是被動端, 是一個全雙工的通道(發送與接收分開同時運作)在互相傳輸資料, 理論上來說 MessageChannel 是可以取代上述兩種通道的, 只是運作介面之不同而已.通常要馬上回應的溝通管道直接使用 MethodChannel, 需長時間的回應就就交由 EventChannel, 比方說錄影時要馬上回應機器狀態, 就直接通過 MethodChannele 溝通與控制, 當錄影開始到結束需要花費較長時間,不可能讓程序長時間等待,就可以另闢 EventChannel 管道,後續用廣播方式作通知. 用 EventChannl 與 MethodChannel 就能滿足大部份文字訊息溝通的需求, 關於 EventChannel 與 MessageChannel 的使用方式,參考範例程式:
// 原生 flutter plugin 端 kotlin 原始碼
import android.os.Bundle
import io.flutter.app.FlutterActivity
import io.flutter.plugin.common.StringCodec
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.EventChannel
import io.flutter.plugin.common.BasicMessageChannel
import io.flutter.plugins.GeneratedPluginRegistrant // ...
var stream : EventChannel.EventSink? = null
EventChannel(flutterView , "com.example.event").setStreamHandler(//事件通道註冊
object: EventChannel.StreamHandler { // 繼承 StreamHandler 並實現
override fun onCancel(arguments: Any?) { stream = null }
override fun onListen(arguments: Any?, sink: EventChannel.EventSink?) {
stream = sink
stream?.success("init complete") // 資料流非同步發送一個事件
}
})
//... async send event
stream?.success("event !") // 資料流非同步再發送一個事件
val msg = BasicMessageChannel<String>(flutterView, "channel", StringCodec.INSTANCE)//簡單訊息通道註冊
msg.send("Hello!") { reply: String? -> println(reply); } // 簡單訊息通道發送一則訊息
msg.setMessageHandler { req, reply -> reply.reply("$req: plugin") }// 同時能回應訊息
// ...
// Flutter 端 dart 原始碼
final _event = EventChannel('com.example.event'); //事件通道註冊
_event.receiveBroadcastStream().listen((onData) { //監聽資料流所發生的事件
print('$onData');
});
final _msg = BasicMessageChannel<String>('channel', StringCodec());//簡單訊息通道
_msg.setMessageHandler( (String onData) async { // 簡單訊息通道等待接收訊息
print('receive: $onData');
return 'hi'; // 回應資料
});
_msg.send('who').then(( x) => print('answer:$x')); // 簡單訊息通道同時能傳送訊息
總結來說, EventChannel 專用於插件的廣播頻道, MethodChannel 專用於插件的回應需求通道, 而 MessageChannel 則是一個通用的全雙工溝通管道.
使用 BinaryMessenger 通道傳輸, 參考文章:
https://medium.com/flutter/flutter-platform-channels-ce7f540a104e
底下使用 android 端的 Kotlin 原始碼: android platform -> flutter 溝通:
import android.os.Bundle
import io.flutter.app.FlutterActivity
io.flutter.plugin.common.BinaryMessenger
import io.flutter.plugin.common.StringCodec
import java.nio.ByteBuffer
import java.nio.ByteOrder
// import io.flutter.plugin.common.BinaryCodec
// import io.flutter.plugin.common.StandardMessageCodec
// 若要接收監聽處理範例:
flutterView.setMessageHandler("binary") { buffer: ByteBuffer?, reply ->
buffer?.order(ByteOrder.nativeOrder())
buffer?.putDouble(3.1415)
buffer?.putInt(123456789)
reply.reply(buffer)
}
// 若要傳送並等待處理範例
val buffer = ByteBuffer.allocateDirect(12)
buffer.putDouble(3.1415)
buffer.putInt(123456789)
flutterView.send("binary", buffer) { _ -> } // 忽略回傳值
// { x: ByteBuffer? -> val y = BinaryCodec.INSTANCE.decodeMessage(x) }//處理回傳值
底下使用 Flutter 端的 dart 原始碼: flutter -> android platform 溝通:
// 若要接收監聽處理範例:
BinaryMessages.setMessageHandler('binary', (ByteData buffer) async {
final readBuffer = ReadBuffer(buffer);
final x = readBuffer.getFloat64( );
final n = readBuffer.getInt32( );
print('Received $x and $n');
return null;
});
// 若要傳送並等待處理範例
final writeBuffer = WriteBuffer( ) ..
putFloat64(3.1415) ..
putInt32(12345678);
final buffer = writeBuffer.done();
await BinaryMessages.send('binary', buffer);
上述 BinaryMessages 通道若是透過 StringCodec( ), 就能用字串加以溝通:
// 若要接收監聽處理範例:
final codec = StringCodec( );
BinaryMessages.setMessageHandler('binary', (ByteData buffer) async {
print('${codec.decodeMessage(buffer)}');
return codec.encodeMessage('Hi');
});
// 若要傳送並等待處理範例:
final reply = await BinaryMessages.send('binary', codec.encodeMessage('Hello'))
print(codec.decodeMessage(reply));