用Flutter这样的跨平台技术进行商业级项目开发时,几乎不可避免的需要和Native进行通信,比如不同平台的底层服务如电量变化、网络连接变化、陀螺仪、传感器等等都有各自不同的实现,以及编译期的一些配置,比如包名、版本号、第三方依赖APPKEY等都需要通过原生的方法去获取。所以得学一哈Native和Flutter的通信方式是非常有必要的
前话
Native和Flutter之间可以通过Platform Channels APIs进行通信,
Flutter定义了三种不同类型的Channel:
-
MethodChannel:用于传递方法调用(method invocation),适用于一次性通信
-
BasicMessageChannel:用于传递字符串和半结构化的消息,持续通信可回复
-
EventChannel: 用于事件流的发送(event streams),持续通信不可回复
一、MethodChannel通信
MethodChannel是最常用的Native和Flutter的通信方式,主要用于Flutter调用Native端方法,如调用Native相机功能
为了便于理解,这里我介绍一个前两天在公司项目中实际用到MethodChannel的场景。基本现在Android APP都会涉及到多渠道打包问题,针对不同的渠道,我们可能会在编译脚本(build文件)中进行一些不同的配置。但是Flutter如何才能拿到Android Gradle中的配置信息呢?其实很简单,也就是我们可以先通过Android代码拿到BuildConfig中的数据,再通过Flutter与Android进行通信拿到数据。这种一次性的调用Android中代码的情况就需要用到MethodChannel
1.1 Android端
创建MethodChannel,通过setMethodCallHandler接收Flutter端的方法调用
private val Method_Channel = "com.example.flutter_test_call/methodChannel"
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
//1.创建android端的MethodChannel
val methodChannel = MethodChannel(flutterEngine.dartExecutor, Method_Channel)
//2.通过setMethodCallHandler响应Flutter端的方法调用
methodChannel.setMethodCallHandler { call, result ->
//判断调用的方法名
if(call.method.equals("testMethodCall")){
//获取传递的参数
Log.e("test", "Have received Test Method Call :${call.arguments}")
//返回结果给Flutter端
result.success(BuildConfig.DEBUG.toString() + " " +"yes")
}
}
}
1.2 Flutter端
Flutter端同样也有MethodChannel,可以通过类似方法调用的方式,调用Native层的方法,并拿到返回值
String Method_Channel = "com.example.flutter_test_call/methodChannel";
Future<void> testMethodCall() async {
//1.创建Flutter端的MethodChannel
MethodChannel _methodChannel = MethodChannel(Method_Channel);
//2.通过invokeMethod调用Native方法,拿到返回值
String debugString = await _methodChannel.invokeMethod("testMethodCall", "give me debug info");
print('test debugString=$debugString');
}
这里要注意两点:
- ChannelName要与Native端保持一致(即com.example.flutter_test_call/methodChannel)
- MethodName要与Native端保持一致(即testMethodCall)
二、BasicMessageChannel通信
BasicMessageChannel用于Native和Flutter互相发送消息,一方给另一方发送消息,收到消息之后给出回复
2.1 Android给Flutter发送消息
2.1.1 Android端
创建一个BasicMessageChannel,通过send方法发送消息
private val Basic_Method_Channel = "com.example.flutter_test_call/basicMethodChannel"
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
//1.创建android端的BasicMessageChannel
val basicMethodChannel = BasicMessageChannel(flutterEngine.dartExecutor, Basic_Method_Channel, StringCodec.INSTANCE)
//2.向Flutter端发送消息
basicMethodChannel.send("Hello, this is BasicMethodChannel Send msg!") {
replyString ->
Log.i("test", "收到了Flutter端发来的回复:$replyString")
}
}
发送的消息会以二进制的形式进行处理,所以要针对不同类型的数据进行二进制编码
编码类型 | 消息格式 |
---|---|
BinaryCodec | 发送二进制消息 |
JSONMessageCodec | 发送Json格式消息 |
StandardMessageCodec | 发送基本型数据 |
StringCodec | 发送String类型消息 |
2.1.2 Flutter端
Flutter端同样也有BasicMessageChannel,通过setMessageHandler接收并回复消息
String Basic_Method_Channel = "com.example.flutter_test_call/basicMethodChannel";
initBasicMethodCall(){
//1.创建Flutter端的BasicMessageChannel
basicMessageChannel = BasicMessageChannel(Basic_Method_Channel, StringCodec());
//2.接收来自Native的消息,并向Native回复
basicMessageChannel.setMessageHandler((message) {
print('test Android端发来的消息:$message');
return Future.value('黄河黄河,我是长江');
});
}
2.2 Flutter给Android发送消息
2.2.1 Flutter端
在Flutter端我们也可以通过send方法向Native发送消息,方法的返回值就是Native端的消息回复
注意flutter和Native的通信都是异步的
testBasicMethodCall() async {
String replyString = await basicMessageChannel?.send("Android, 我是Flutter端!");
print('test Android端回复的的消息:$replyString');
}
2.2.2 Android端
android端通过setMessageHandler设置消息处理器,处理来自Dart的消息,收到消息后通过reply进行回复
basicMethodChannel.setMessageHandler { message, reply ->
Log.v("test", "收到了Flutter端发来的消息:$message")
//通过reply进行回复
reply.reply("长江长江,我是黄河~")
}
三、EventChannel通信
EventChannel用于从Native向Flutter发送通知事件,例如Flutter通过其监听Android的重力感应变化等。与MethodChannel不同,EventChannel是Native到Flutter的单向调用,调用是一对多的,类似Android的BrodcastReceiver
3.1 Android端
创建一个EventChannel,在StreamHandler#onLister回调中获取EventSink引用并保存,当重力感应发送变化时,通过eventSink.success向Flutter端发送消息
private val Event_Channel = "com.example.flutter_test_call/eventChannel"
var eventSink: EventChannel.EventSink? = null
fun registerEventChannel(binaryMessenger: BinaryMessenger){
//1.创建Android端的EventChannel
val eventChannel = EventChannel(binaryMessenger, Event_Channel)
//2.在StreamHandler#onLister回调中获取EventSink引用并保存
eventChannel.setStreamHandler(object : EventChannel.StreamHandler{
override fun onListen(arguments: Any?, events: EventChannel.EventSink?) {
eventSink = events
}
override fun onCancel(arguments: Any?) {
eventSink = null
}
})
}
fun getNetWorkType(context : Context){
var connectivityManager : ConnectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
var info = connectivityManager.activeNetworkInfo
if(info != null){
if(info?.type == ConnectivityManager.TYPE_WIFI){
//3.调用eventSink.success向Flutter端发送消息
eventSink?.success("WIFI")
}else if(info.type == ConnectivityManager.TYPE_MOBILE){
eventSink?.success("Mobile")
}else{
eventSink?.success("Unkonw")
}
}else{
//3.报错后调用eventSink.error向Flutter端发送消息
eventSink?.error("error network", "error network", "error network")
}
}
3.2 Flutter端
Flutter端接收消息如下所示,要注意使用EventChannel时需要在页面销毁时取消监听,防止内存泄漏
String eventChannel = 'com.example.flutter_test_call/eventChannel';
StreamSubscription streamSubscription;
testEventChannel(){
//1.创建Flutter端EventChannel
EventChannel _eventChannel = EventChannel(eventChannel);
//2.EventChannel#receiveBroadcastStream注册listener,建立监听
streamSubscription = _eventChannel.receiveBroadcastStream()
.listen((event) {
print("Network Status : $event");
}, onError: (errorcode){
print('errorcode: $errorcode');
});
}
@override
void dispose() {
// TODO: implement dispose
super.dispose();
//3.页面销毁时需要取消监听,防止内存泄漏
streamSubscription?.cancel();
}
申明:禁用于商业用途,如若转载,请附带原文链接。https://www.jianshu.com/p/e376574e2402蟹蟹~
PS: 写文不易,觉得没有浪费你时间,请给个关注和点赞~ 😁
网友评论