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)
// 原生端通过通道发送数据到 Flutter
channel?.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字段的可见性,防止多线程环境下出现指令重排序导致的问题。
*/
@Volatile
private 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")
}
}