??用Flutter這樣的跨平臺技術(shù)進(jìn)行商業(yè)級項目開發(fā)時从橘,幾乎不可避免的需要和Native進(jìn)行通信,比如不同平臺的底層服務(wù)如電量變化、網(wǎng)絡(luò)連接變化糠悯、陀螺儀、傳感器等等都有各自不同的實現(xiàn)妻往,以及編譯期的一些配置互艾,比如包名、版本號讯泣、第三方依賴APPKEY等都需要通過原生的方法去獲取纫普。所以得學(xué)一哈Native和Flutter的通信方式是非常有必要的
前話
Native和Flutter之間可以通過Platform Channels APIs進(jìn)行通信,
Flutter定義了三種不同類型的Channel:
MethodChannel:用于傳遞方法調(diào)用(method invocation)好渠,適用于一次性通信
BasicMessageChannel:用于傳遞字符串和半結(jié)構(gòu)化的消息昨稼,持續(xù)通信可回復(fù)
EventChannel: 用于事件流的發(fā)送(event streams),持續(xù)通信不可回復(fù)
一拳锚、MethodChannel通信
MethodChannel是最常用的Native和Flutter的通信方式假栓,主要用于Flutter調(diào)用Native端方法,如調(diào)用Native相機(jī)功能
為了便于理解霍掺,這里我介紹一個前兩天在公司項目中實際用到MethodChannel的場景匾荆“柚基本現(xiàn)在Android APP都會涉及到多渠道打包問題,針對不同的渠道牙丽,我們可能會在編譯腳本(build文件)中進(jìn)行一些不同的配置简卧。但是Flutter如何才能拿到Android Gradle中的配置信息呢?其實很簡單烤芦,也就是我們可以先通過Android代碼拿到BuildConfig中的數(shù)據(jù)举娩,再通過Flutter與Android進(jìn)行通信拿到數(shù)據(jù)。這種一次性的調(diào)用Android中代碼的情況就需要用到MethodChannel
1.1 Android端
創(chuàng)建MethodChannel构罗,通過setMethodCallHandler接收Flutter端的方法調(diào)用
private val Method_Channel = "com.example.flutter_test_call/methodChannel"
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
//1.創(chuàng)建android端的MethodChannel
val methodChannel = MethodChannel(flutterEngine.dartExecutor, Method_Channel)
//2.通過setMethodCallHandler響應(yīng)Flutter端的方法調(diào)用
methodChannel.setMethodCallHandler { call, result ->
//判斷調(diào)用的方法名
if(call.method.equals("testMethodCall")){
//獲取傳遞的參數(shù)
Log.e("test", "Have received Test Method Call :${call.arguments}")
//返回結(jié)果給Flutter端
result.success(BuildConfig.DEBUG.toString() + " " +"yes")
}
}
}
1.2 Flutter端
Flutter端同樣也有MethodChannel铜涉,可以通過類似方法調(diào)用的方式,調(diào)用Native層的方法遂唧,并拿到返回值
String Method_Channel = "com.example.flutter_test_call/methodChannel";
Future<void> testMethodCall() async {
//1.創(chuàng)建Flutter端的MethodChannel
MethodChannel _methodChannel = MethodChannel(Method_Channel);
//2.通過invokeMethod調(diào)用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互相發(fā)送消息蠢箩,一方給另一方發(fā)送消息链蕊,收到消息之后給出回復(fù)
2.1 Android給Flutter發(fā)送消息
2.1.1 Android端
創(chuàng)建一個BasicMessageChannel,通過send方法發(fā)送消息
private val Basic_Method_Channel = "com.example.flutter_test_call/basicMethodChannel"
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
//1.創(chuàng)建android端的BasicMessageChannel
val basicMethodChannel = BasicMessageChannel(flutterEngine.dartExecutor, Basic_Method_Channel, StringCodec.INSTANCE)
//2.向Flutter端發(fā)送消息
basicMethodChannel.send("Hello, this is BasicMethodChannel Send msg!") {
replyString ->
Log.i("test", "收到了Flutter端發(fā)來的回復(fù):$replyString")
}
}
發(fā)送的消息會以二進(jìn)制的形式進(jìn)行處理谬泌,所以要針對不同類型的數(shù)據(jù)進(jìn)行二進(jìn)制編碼
編碼類型 | 消息格式 |
---|---|
BinaryCodec | 發(fā)送二進(jìn)制消息 |
JSONMessageCodec | 發(fā)送Json格式消息 |
StandardMessageCodec | 發(fā)送基本型數(shù)據(jù) |
StringCodec | 發(fā)送String類型消息 |
2.1.2 Flutter端
Flutter端同樣也有BasicMessageChannel滔韵,通過setMessageHandler接收并回復(fù)消息
String Basic_Method_Channel = "com.example.flutter_test_call/basicMethodChannel";
initBasicMethodCall(){
//1.創(chuàng)建Flutter端的BasicMessageChannel
basicMessageChannel = BasicMessageChannel(Basic_Method_Channel, StringCodec());
//2.接收來自Native的消息,并向Native回復(fù)
basicMessageChannel.setMessageHandler((message) {
print('test Android端發(fā)來的消息:$message');
return Future.value('黃河黃河掌实,我是長江');
});
}
2.2 Flutter給Android發(fā)送消息
2.2.1 Flutter端
在Flutter端我們也可以通過send方法向Native發(fā)送消息陪蜻,方法的返回值就是Native端的消息回復(fù)
注意flutter和Native的通信都是異步的
testBasicMethodCall() async {
String replyString = await basicMessageChannel?.send("Android, 我是Flutter端!");
print('test Android端回復(fù)的的消息:$replyString');
}
2.2.2 Android端
android端通過setMessageHandler設(shè)置消息處理器贱鼻,處理來自Dart的消息宴卖,收到消息后通過reply進(jìn)行回復(fù)
basicMethodChannel.setMessageHandler { message, reply ->
Log.v("test", "收到了Flutter端發(fā)來的消息:$message")
//通過reply進(jìn)行回復(fù)
reply.reply("長江長江,我是黃河~")
}
三邻悬、EventChannel通信
EventChannel用于從Native向Flutter發(fā)送通知事件症昏,例如Flutter通過其監(jiān)聽Android的重力感應(yīng)變化等。與MethodChannel不同父丰,EventChannel是Native到Flutter的單向調(diào)用肝谭,調(diào)用是一對多的,類似Android的BrodcastReceiver
3.1 Android端
創(chuàng)建一個EventChannel蛾扇,在StreamHandler#onLister回調(diào)中獲取EventSink引用并保存攘烛,當(dāng)重力感應(yīng)發(fā)送變化時,通過eventSink.success向Flutter端發(fā)送消息
private val Event_Channel = "com.example.flutter_test_call/eventChannel"
var eventSink: EventChannel.EventSink? = null
fun registerEventChannel(binaryMessenger: BinaryMessenger){
//1.創(chuàng)建Android端的EventChannel
val eventChannel = EventChannel(binaryMessenger, Event_Channel)
//2.在StreamHandler#onLister回調(diào)中獲取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.調(diào)用eventSink.success向Flutter端發(fā)送消息
eventSink?.success("WIFI")
}else if(info.type == ConnectivityManager.TYPE_MOBILE){
eventSink?.success("Mobile")
}else{
eventSink?.success("Unkonw")
}
}else{
//3.報錯后調(diào)用eventSink.error向Flutter端發(fā)送消息
eventSink?.error("error network", "error network", "error network")
}
}
3.2 Flutter端
Flutter端接收消息如下所示镀首,要注意使用EventChannel時需要在頁面銷毀時取消監(jiān)聽坟漱,防止內(nèi)存泄漏
String eventChannel = 'com.example.flutter_test_call/eventChannel';
StreamSubscription streamSubscription;
testEventChannel(){
//1.創(chuàng)建Flutter端EventChannel
EventChannel _eventChannel = EventChannel(eventChannel);
//2.EventChannel#receiveBroadcastStream注冊listener,建立監(jiān)聽
streamSubscription = _eventChannel.receiveBroadcastStream()
.listen((event) {
print("Network Status : $event");
}, onError: (errorcode){
print('errorcode: $errorcode');
});
}
@override
void dispose() {
// TODO: implement dispose
super.dispose();
//3.頁面銷毀時需要取消監(jiān)聽更哄,防止內(nèi)存泄漏
streamSubscription?.cancel();
}
申明:禁用于商業(yè)用途芋齿,如若轉(zhuǎn)載须眷,請附帶原文鏈接。http://www.reibang.com/p/e376574e2402蟹蟹~
PS: 寫文不易沟突,覺得沒有浪費你時間,請給個關(guān)注和點贊~ ??