引言
我们通过 plugin 来实现 flutter 端与 native 端的通信。主要体现在方法的相互调用以及数据流的发送监听。今天我们来记录一下这两种交互的实现方式:MethodChannel
和 EventChannel
-
MethodChannel
:用于方法调用 -
EventChannel
:用于数据流(event streams)的通信,(监听,发送)
我们需要一个 demo
创建一个简单的 demo ,页面三个元素:
-
receiveData
文本块:监听显示从 native 端接收到的数据流 -
startTimer
按钮:flutter 端调用 native 端,开启事件轮询 -
stopTimer
按钮:flutter 端调用 native 端,关闭事件轮询
demo 里,flutter 按键通过 methodChannel 调用 native 层方法,开启了 timer 轮询,native 端每隔1秒,将当前时间戳回传到 eventChannel 数据流中。
开始 demo 创建:
-
native 端:
创建 plugin 类继承 FlutterPlugin
class PluginCommunicationDemoPlugin : FlutterPlugin, MethodCallHandler, EventChannel.StreamHandler {
// methodChannel 和 eventChannel 的路径定义,通过这个路径进行通信
companion object {
const val METHOD_CHANNEL_PATH = "rex_method_channel"
const val EVENT_CHANNEL_PATH = "rex_event_channel"
}
private lateinit var methodChannel: MethodChannel
private lateinit var eventChannel: EventChannel
private var eventSink: EventChannel.EventSink? = null
private var mWorker: TimeWorker = TimeWorker(object : TimerWorkCallback {
override fun onResult(data: String) {
sendEventToStream(data)
}
})
override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
methodChannel = MethodChannel(flutterPluginBinding.binaryMessenger, METHOD_CHANNEL_PATH)
methodChannel.setMethodCallHandler(this)
eventChannel = EventChannel(flutterPluginBinding.binaryMessenger, EVENT_CHANNEL_PATH)
eventChannel.setStreamHandler(this)
}
// methodChannel 方法调用
override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) {
when (call.method) {
"startTimer" -> {
result.success(mWorker.startTimer())
}
"stopTimer" -> {
result.success(mWorker.stopTimer())
}
else -> {
result.notImplemented()
}
}
}
//推送消息给Event数据流,flutter层负责监听数据流
fun sendEventToStream(data: String) {
Handler(Looper.getMainLooper()).post {
eventSink?.success(data)
}
}
override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) {
methodChannel.setMethodCallHandler(null)
}
override fun onListen(arguments: Any?, events: EventChannel.EventSink?) {
// eventChannel 建立连接
eventSink = events
}
override fun onCancel(arguments: Any?) {
eventSink = null
}
}
- onMethodCall 方法进行 methodChannel 事件分发,通过 result.success(any) 进行事件结果回传
- 通过 EventChannel.EventSink 将数据注入到 event 数据流中,flutter层进行监听
- TimeWorker 控制的轮询开启停止,下面附上具体代码
class TimeWorker {
private val format = SimpleDateFormat("yyyy-MM-DD HH:mm:ss")
var timer: Timer? = null
var callback: TimerWorkCallback? = null
constructor(callback: TimerWorkCallback?) {
this.callback = callback
}
//开始事件流发送
fun startTimer(): Boolean {
stopTimer()
if (timer == null) {
timer = Timer()
}
timer?.schedule(object : TimerTask() {
@RequiresApi(Build.VERSION_CODES.O)
override fun run() {
callback?.onResult(getCurrentTimeStr())
}
}, Calendar.getInstance().time, 1000)
return true
}
//停止事件流
fun stopTimer(): Boolean {
timer?.cancel()
timer = null
return true
}
private fun getCurrentTimeStr(): String {
return format.format(Calendar.getInstance().time)
}
}
interface TimerWorkCallback {
fun onResult(data: String)
}
-
Flutter 端:
将 methodChannel 、eventChannel 封装成工具类:
import 'package:flutter/services.dart';
abstract class TestPluginTool {
static const MethodChannel _methodChannel = const MethodChannel("rex_method_channel");
static const EventChannel _eventChannel = const EventChannel("rex_event_channel");
//开启 native 轮询
static Future<bool> startTimer() async {
return await _methodChannel.invokeMethod("startTimer");
}
//关闭 native 轮询
static Future<bool> stopTimer() async {
return await _methodChannel.invokeMethod("stopTimer");
}
//监听 native event 数据流
static void onListenStreamData(onEvent, onError) {
_eventChannel.receiveBroadcastStream().listen(onEvent, onError: onError);
}
}
非常简单,一一对应,匹配 methodChannel ,eventChannel 的路径
-
最后一步,完成 UI:
class _MyAppState extends State<MyApp> {
var _receivedData = "";
@override
void initState() {
super.initState();
_onReceiveEventData();
}
// 开启轮询
void _startTimer() {
TestPluginTool.startTimer().then((value) => print("startTimer success"));
}
// 关闭轮询
void _stopTimer() {
TestPluginTool.startTimer().then((value) => print("stopTimer success"));
}
/// 监听 eventChannel 数据流
void _onReceiveEventData() {
TestPluginTool.onListenStreamData((data) {
setState(() {
_receivedData = data;
});
}, (error) {
print("event channel error : $error");
});
}
@override
Widget build(BuildContext context) {
return Container(
alignment: Alignment.center,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text("receiveData : $_receivedData"),
TextButton(
onPressed: () {
_startTimer();
},
child: Text("startTimer")),
TextButton(
onPressed: () {
_stopTimer();
},
child: Text("stopTimer")),
],
),
);
}
}