Flutter定义了三种不同类型的Channel:
BasicMessageChannel:用于传递字符串和半结构化的信息,持续通信,收到消息后可以回复此次消息,如:Native将遍历到的文件信息陆续传递到Dart,在比如:Flutter将从服务端陆陆续获取到信息交个Native加工,Native处理完返回等;
MethodChannel:用于传递方法调用(method invocation)一次性通信:如Flutter调用Native拍照;
EventChannel: 用于数据流(event streams)的通信,持续通信,收到消息后无法回复此次消息,通过长用于Native向Dart的通信,如:手机电量变化,网络连接变化,陀螺仪,传感器等;
项目当前选择的Channel是BasicMessageChannel作为传输数据的通道。
BasicMessageChannel目前传递数据提供的几种消息类型分别是JSONMessageCodec、StandardMessageCodec、StringCodec、BinaryCodec四种类型。
当前项目选择以JSON格式进行数据传输,所以使用的消息类型是JSONMessageCodec。
JSONMessageCodec在flutter里面可传递的数据类型有5种:
分别是bool,num,String,List,Map
在项目中使用 BasicMessageChannel 通道 Flutter向Android原生接收与发送请求,Android原生向Flutter接收与发送请求则如下:
首先Flutter向Android原生交互需要先注册唯一标识,唯一标识两端必须一致,iOS原生也是一样
当前唯一标识 CHANNEL_NAME = "flutter_to_native_json_basic"
项目Flutter端代码,设置 BasicMessageChannel 消息通道的方式:
/// 指定原生端与flutter之间交互的消息通道
late BasicMessageChannel channel;/// 初始化消息通道
initChannel(Function(String)? toPage) {this.toPage = toPage;/// 创建 Flutter端和原生端的,相互通信的通道channel = const BasicMessageChannel(KtNativeConstant.CHANNEL_NAME, JSONMessageCodec());// 监听来自 原生端 的消息通道,原生端调用了函数,这个handler函数就会被触发channel.setMessageHandler(_handler);
}/// 监听来自 原生端 的消息通道
/// 原生端调用了函数,这个handler函数就会被触发
Future<dynamic> _handler(dynamic message) async {nativeBean = KtNativeBean.formJson(message);KtLog.e("nativeBean: key = ${nativeBean?.key}");/// 接受参数成功返回0给原生端return 0;
}/// flutter向原生端发送消息
flutterSendNativeData(Map<String, String> map) {channel.send(map).then((value) {KtLog.d("原生端接收成功的数据 value = $value");}).catchError((error) {/// 发送消息出现错误异常情况接收回调if (error is MissingPluginException) {KtLog.e("flutterSendNativeData ---- Error:notImplemented --- 未在原生端找到具体实现函数");} else {KtLog.e("flutterSendNativeData ---- Error:$error");}});
}
项目Android原生端代码,设置 BasicMessageChannel 消息通道的方式(原生项目首先需搭建与Flutter通讯的activity):
在 KtFlutterActivity 中 设置:
/**
* 原生端与Flutter交互的实例对象
*/
private var channel: KtJsonBasicMessageChannel? = null/**
* Flutter activity专属回调,在回调中注册与 Flutter 消息传输通道
* @param flutterEngine 项目 Flutter 引擎
*/
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {super.configureFlutterEngine(flutterEngine)// 获取消息通道,并设置 Flutter 引擎channel = KtJsonBasicMessageChannel.getInstance(flutterEngine.dartExecutor.binaryMessenger)// 原生端通过通道发送数据到 Flutterchannel?.androidSendFlutterData(mutableMapOf("key" to "test key","customData" to hashMapOf<String, Any>(),"token" to "test token","epid" to "test epid","appId" to "test appId"))
}
原生端项目自定义的 KtJsonBasicMessageChannel 需继承于
BasicMessageChannel.MessageHandler<Any>
class KtJsonBasicMessageChannel private constructor(messenger: BinaryMessenger) : BasicMessageChannel.MessageHandler<Any>/**
* 项目全局的消息通道
*/
private lateinit var mChannel: BasicMessageChannel<Any>companion object {/*** 原生View 在Flutter引擎上注册的唯一标识,在Flutter端使用时必须一样*/val CHANNEL_NAME = "flutter_to_native_json_basic"/*** 单例对象* 使用 @Volatile 关键字确保instance字段的可见性,防止多线程环境下出现指令重排序导致的问题。*/@Volatileprivate var instance: KtJsonBasicMessageChannel? = null/*** 获取单例对象* @param messenger* @return*/fun getInstance(messenger: BinaryMessenger): KtJsonBasicMessageChannel {// 通过双重检查(Double-Checked)机制,在第一次调用getInstance()时进行加锁,确保只有一个线程能够创建实例。return instance ?: synchronized(this) {instance ?: KtJsonBasicMessageChannel(messenger).also { instance = it }}}
}/**
* 初始化消息通道
* @param messenger
*/
private fun initChannel(messenger: BinaryMessenger) {// 创建 Android端和Flutter端的,相互通信的通道,通道名称,两端必须一致mChannel = BasicMessageChannel(messenger, CHANNEL_NAME, JSONMessageCodec.INSTANCE)// 监听来自 Flutter端 的消息通道,Flutter端调用了函数,这个handler函数就会被触发mChannel.setMessageHandler(this)
}/**
* 监听来自 Flutter端 的消息通道
* @param message Android端 接收到 Flutter端 发来的 数据对象
* @param reply Android端 给 Flutter端 执行回调的接口对象
*/
override fun onMessage(message: Any?, reply: BasicMessageChannel.Reply<Any>) {// 回调结果对象,获取Flutter端传过来的数据val flutterData = KtJsonUtils.fromJson(message.toString(), HashMap::class.java)"flutter message = ${message?.toString() ?: ""}".loge()// 回调状态接口对象,返回给Flutter端reply.reply(message)
}/**
* Android原生端发送消息至Flutter端
* @param data 需要发送的消息
*/
fun androidSendFlutterData(data: MutableMap<String, Any>) {mChannel.send(data) { reply ->JqzLogUtils.eTag(AppConstants.LOG_HTTP_INFO_TAG, "从flutter 返回回来的数据 reply : $reply")}
}