本文首發於微信公衆號「Android開發之旅」,歡迎關注 ,獲取更多技術乾貨bash
咱們在作Flutter混合開發的時候一般須要進行Flutter和Native之間的通訊。 好比Dart調用Native的相冊選擇圖片,Native將電量、GPS信息主動傳遞給Dart等等。在混合開發中通訊一般有如下幾種:微信
第一種通訊方式咱們在講解原生項目接入Flutter時已經講解過,有興趣的同窗能夠移步到Flutter混合開發(一):Android項目集成Flutter模塊詳細指南看下。異步
Flutter與Native端之間的通訊機制是經過Platform Channel來完成。消息使用Channel在Flutter端和Native端進行傳遞。具體以下圖所示:async
從圖中能夠看出,兩端之間的通訊都是雙向的,並且是完成異步傳遞。Flutter定義了三種不一樣類型的Channel:ide
下面咱們就來看看這三種Channel通訊方式的具體使用和介紹。函數
BasicMessageChannel(BinaryMessenger messenger, String name, MessageCodec<T> codec)
複製代碼
當咱們須要接受來自Dart端發送的消息時使用setMessageHandler方法:工具
void setMessageHandler(BasicMessageChannel.MessageHandler<T> handler)
複製代碼
參數handler是消息處理器,配合BinaryMessenger來完成對消息的處理。它是一個接口,具體的實如今onMessage方法中:post
public interface MessageHandler<T> {
void onMessage(T message, BasicMessageChannel.Reply<T> reply);
}
複製代碼
參數message即爲Dart發送的數據, reply是用於回覆消息的回調函數,提供reply.reply("")設置回覆的內容。ui
上面講的是接受Dart端的消息,那麼Native端主動發送消息則是使用send方法,它有兩個重載方法:this
void send(T message)
void send(T message, BasicMessageChannel.Reply<T> callback)
複製代碼
參數message即爲要發生給Dart的數據,callback回調則是用於接收Dart端收到消息後的回覆信息。
const BasicMessageChannel(this.name, this.codec);
複製代碼
這裏的name和codec和Android端的構造方法參數是同樣的,那麼是channel的名字也是惟一標識,codec是消息編解碼器,兩個參數在兩端必須統一。
Dart端若是要接受Native端的消息則要設置setMessageHandler方法:
void setMessageHandler(Future<T> handler(T message))
複製代碼
參數handler爲消息處理器,配合BinaryMessenger來完成對消息的處理。
經過send方法向Native端發送消息:
Future<T> send(T message)
複製代碼
參數message爲要傳遞的參數。Future爲發送消息後等待Native回覆的回調函數。
//初始化BasicMessageChannel
BasicMessageChannel<String> basicMessageChannel = new BasicMessageChannel<>(flutterView,
"BasicMessageChannelPlugin",StringCodec.INSTANCE);
//接受消息
basicMessageChannel.setMessageHandler((message, reply) -> {
mTvDart.setText(message);
reply.reply("收到dart數據:接受成功");
});
//發送消息
basicMessageChannel.send(message, reply -> mTvDart.setText(reply));
複製代碼
//初始化BasicMessageChannel
static const BasicMessageChannel<String> _basicMessageChannel =
BasicMessageChannel("BasicMessageChannelPlugin", StringCodec());
// 接受消息
void handleBasicMessageChannel() {
_basicMessageChannel
.setMessageHandler((String message) => Future<String>(() {
setState(() {
showMessage = message;
});
return "收到Native的消息:接受成功";
}));
}
//發送消息
response = await _basicMessageChannel.send(_controller.text);
setState(() {
showMessage = response;
});
複製代碼
最後效果爲下圖,紅色分割線上部分爲Native頁面,下部分爲Flutter頁面。
使用MethodChannel相關方法的參數類型及含義和BasicMessageChannel的參數含義都是相同的,下面就不一一解釋了。
MethodChannel(BinaryMessenger messenger, String name)
MethodChannel(BinaryMessenger messenger, String name, MethodCodec codec)
複製代碼
第一個構造函數會構造一個StandardMethodCodec.INSTANCE類型的MethodCodec。MethodCodec定義了兩種類型:JSONMethodCodec和StandardMethodCodec。
若是想接受來自Dart端的消息則使用:
setMethodCallHandler(@Nullable MethodChannel.MethodCallHandler handler)
複製代碼
MethodCallHandler爲接口,回調方法爲:
public interface MethodCallHandler {
void onMethodCall(MethodCall call, MethodChannel.Result result);
}
複製代碼
call參數有兩個成員變量,String類型的call.method表示調用的方法名,Object類型的call.arguments表示調用方法所傳遞的入參。result是回覆此消息的回調函數提供了result.success,result.error,result.notImplemented方法調用。
發送消息主動調用Dart代碼則使用invokeMethod方法
invokeMethod(@NonNull String method, @Nullable Object arguments)
invokeMethod(String method, @Nullable Object arguments, Result callback)
複製代碼
第二個方法多了一個callback,它是用來接受Dart端收到消息後的回覆信息。
public interface Result {
void success(@Nullable Object result);
void error(String errorCode, @Nullable String errorMessage, @Nullable Object errorDetails);
void notImplemented();
}
複製代碼
const MethodChannel(this.name, [this.codec = const StandardMethodCodec()])
複製代碼
構造函數默認是使用StandardMethodCodec編解碼器。
經過setMethodCallHandler方法接受來自Native的方法調用,經過invokeMethod方法調用Native端的方法。
void setMethodCallHandler(Future<dynamic> handler(MethodCall call))
複製代碼
Future<T> invokeMethod<T>(String method, [ dynamic arguments ])
複製代碼
//初始化MethodChannel
MethodChannel methodChannel = new MethodChannel(flutterView, "MethodChannelPlugin");
mBtnTitle.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//調用dart端getPlatform方法
methodChannel.invokeMethod("getPlatform", null, new MethodChannel.Result() {
@Override
public void success(@Nullable Object result) {
mTvDart.setText(result.toString());
}
@Override
public void error(String errorCode, @Nullable String errorMessage, @Nullable Object errorDetails) {
mTvDart.setText(errorCode + "==" + errorMessage);
}
@Override
public void notImplemented() {
mTvDart.setText("未實現getPlatform方法");
}
});
}
});
//接受dart的調用
methodChannel.setMethodCallHandler((call, result) -> {
switch (call.method) {
case "getBatteryLevel":
int batteryLevel = getBatteryLevel();
if (batteryLevel != -1) {
result.success("電量爲:" + batteryLevel);
} else {
result.error("1001", "調用錯誤", null);
}
break;
default:
result.notImplemented();
break;
}
});
複製代碼
// receive
void handleMethodChannelReceive() {
Future<dynamic> platformCallHandler(MethodCall call) async {
switch (call.method) {
case "getPlatform":
return getPlatformName(); //調用success方法
// return PlatformException(code: '1002',message: "出現異常"); //調用error
break;
}
}
_methodChannel.setMethodCallHandler(platformCallHandler);
// _methodChannel.setMethodCallHandler(null); //調用notImplemented
}
//send
void handleMethodChannelSend() async {
try {
response = await _methodChannel.invokeMethod("getBatteryLevel");
print(response);
setState(() {
showMessage = response;
});
} catch (e) {
//捕獲error和notImplemented異常
setState(() {
showMessage = e.message;
});
}
}
複製代碼
當咱們在使用setMethodCallHandler接受到native的消息時,直接調用相關方法便可調用Native端的success回調。
若是直接拋異常如PlatformException,那麼就調用Native端的error回調。
PlatformException(code: '1002',message: "出現異常")
複製代碼
若是咱們直接設置handler爲null
_methodChannel.setMethodCallHandler(null);
複製代碼
那麼就會調用Native端的notImplemented方法回調。
同理咱們在Dart端使用invokeMethod方法是,須要進行異常捕獲以便於咱們接受到Native端調用的error和notImplemented方法回調。
最後效果爲下圖,紅色分割線上部分爲Native頁面,下部分爲Flutter頁面。
EventChannel內部實現原理其實也是經過MethodChannel來完成的。
EventChannel(BinaryMessenger messenger, String name)
EventChannel(BinaryMessenger messenger, String name, MethodCodec codec)
複製代碼
一樣的,也是兩個構造,默認codec爲StandardMethodCodec,EventChannel和MethodChannel的codec都屬於MethodCodec範疇。
經過setStreamHandler來監聽Dart端發送的消息,
void setStreamHandler(EventChannel.StreamHandler handler)
複製代碼
其中handler是一個接口:
public interface StreamHandler {
void onListen(Object args, EventChannel.EventSink eventSink);
void onCancel(Object o);
}
複製代碼
args爲dart端初始化監聽流的參數,eventSink設置了三個回調,分別是success、error和endofStream。分別對應Dart端的ondata、error和onDone回調。
const EventChannel(this.name, [this.codec = const StandardMethodCodec()]);
複製代碼
經過EventChannel初始化一個channel對象。若是從Native中接受數據須要定義一個廣播流:
Stream<dynamic> receiveBroadcastStream([ dynamic arguments ])
複製代碼
經過調用Stream的listen方法來完成註冊。
EventChannel eventChannel = new EventChannel(flutterView, "EventChannelPlugin");
eventChannel.setStreamHandler(new EventChannel.StreamHandler() {
@Override
public void onListen(Object arguments, EventChannel.EventSink events) {
events.success(arguments.toString() + getBatteryLevel());
//events.error("111","出現錯誤","");
//events.endOfStream();
}
@Override
public void onCancel(Object arguments) {
}
});
複製代碼
//init
static const EventChannel _eventChannel = EventChannel("EventChannelPlugin");
//receive
void handleEventChannelReceive() {
streamSubscription = _eventChannel
.receiveBroadcastStream() //能夠攜帶參數
.listen(_onData, onError: _onError, onDone: _onDone);
}
void _onDone() {
setState(() {
showMessage = "endOfStream";
});
}
_onError(error) {
setState(() {
PlatformException platformException = error;
showMessage = platformException.message;
});
}
void _onData(message) {
setState(() {
showMessage = message;
});
}
複製代碼
經過event.success方法發送信息,dart端經過監聽Stream流來獲取信息。當Native端調用events.error時在Dart端的onError回調中須要將error轉換爲PlatformException才能獲取到異常的相關信息。
最後效果爲下圖,紅色分割線上部分爲Native頁面,下部分爲Flutter頁面。
主要是講解了Android端和Dart的三種通訊方式。詳細分析了方法構成和具體的實例使用。每一種方式都對應不一樣的使用場景,你們能夠按需選擇,多加練習作到熟能生巧。
文中都是貼的一些代碼片斷,所有Demo源碼已經上傳到後臺,關注公衆號回覆「混合開發」便可獲取下載連接。
Flutter混合開發(一):Android項目集成Flutter模塊詳細指南
Flutter混合開發(二):iOS項目集成Flutter模塊詳細指南