Platform Channel簡介
Flutter引入Platform Channel機制來支持不同平臺的API調(diào)用。在Flutter中,提供了三種Platform Channel用來支持和平臺之間數(shù)據(jù)的傳遞:
- BasicMessageChannel:支持字符串和半結(jié)構(gòu)化的數(shù)據(jù)傳遞,可以通過BasicMessageChannel來獲取Native項目的圖標等資源
- MethodChannel:支持傳遞方法調(diào)用,Flutter主動調(diào)用Native的方法,并獲取相應(yīng)的返回值。既可以從Flutter發(fā)平臺發(fā)起方法調(diào)用,也可以從平臺代碼向Flutter發(fā)起調(diào)用
- EventChannel:支持數(shù)據(jù)流通信,傳遞事件。收到消息后無法回復(fù)此次消息,通常用于Native向Dart的通信
使用方法
BasicMessageChannel
Android端:
BasicMessageChannel mBasicMessageChannel = new BasicMessageChannel(getFlutterView(), "basic_channel", StringCodec.INSTANCE);
mBasicMessageChannel.setMessageHandler(new BasicMessageChannel.MessageHandler() {
//接受消息
@Override
public void onMessage(Object o, BasicMessageChannel.Reply reply) {
Log.e("basic_channel", "接收到來自flutter的消息:"+o.toString());
reply.reply("回饋消息");
}
});
//發(fā)送消息
mBasicMessageChannel.send("向flutter發(fā)送消息");
//發(fā)送消息并接受flutter的回饋
mBasicMessageChannel.send("向flutter發(fā)送消息", new BasicMessageChannel.Reply() {
@Override
public void reply(Object o) {
}
});
Flutter端:
const basicMessageChannel = const BasicMessageChannel('basic_channel', StringCodec());
//接受并回復(fù)消息
basicMessageChannel.setMessageHandler(
(String message) => Future<String>(() {
setState(() {
this.message = message;
});
return "回復(fù)native消息";
}),
);
//發(fā)送消息
basicMessageChannel.send("來自flutter的message");
//flutter并沒有發(fā)送并接受回復(fù)消息的`send(T message, BasicMessageChannel.Reply<T> callback)`方法
MethodChannel
Android端:
MethodChannel mMethodChannel = new MethodChannel(getFlutterView(), "method_channel");
mMethodChannel.setMethodCallHandler(new MethodChannel.MethodCallHandler() {
//響應(yīng)flutter端的調(diào)用
@Override
public void onMethodCall(MethodCall methodCall, MethodChannel.Result result) {
if (methodCall.method.equals("noticeNative")) {
todo()
result.success("接受成功");
}
}
});
//原生調(diào)用flutter
mMethodChannel.invokeMethod("noticeFlutter", "argument", new MethodChannel.Result() {
@Override
public void success(Object o) {
//回調(diào)成功
}
@Override
public void error(String s,String s1, Object o) {
//回調(diào)失敗
}
@Override
public void notImplemented() {
}
});
Flutter端:
const methodChannel = const MethodChannel('method_channel');
Future<Null> getMessageFromNative() async {
//flutter調(diào)原生方法
try {
//回調(diào)成功
final String result = await methodChannel.invokeMethod('noticeNative');
setState(() {
method = result;
});
} on PlatformException catch (e) {
//回調(diào)失敗
}
}
methodChannel.setMethodCallHandler(
(MethodCall methodCall) => Future<String>(() {
//響應(yīng)原生的調(diào)用
if(methodCall.method == "noticeFlutter"){
setState(() {
});
}
}),
);
EventChannel
Android端:
EventChannel eventChannel = new EventChannel(getFlutterView(),"event_channel");
eventChannel.setStreamHandler(new EventChannel.StreamHandler() {
@Override
public void onListen(Object o, EventChannel.EventSink eventSink) {
eventSink.success("成功");
//eventSink.error("失敗","失敗","失敗");
}
@Override
public void onCancel(Object o) {
//取消監(jiān)聽時調(diào)用
}
});
Flutter端:
const eventChannel = const EventChannel('event_channel');
eventChannel.receiveBroadcastStream().listen(_onEvent,onError:_onError);
void _onEvent(Object event) {
//返回的內(nèi)容
}
void _onError(Object error) {
//返回的回調(diào)
}
其中:Object args是傳遞的參數(shù),EventChannel.EventSink eventSink是Native回調(diào)Dart時的會回調(diào)函數(shù),eventSink提供success、error與endOfStream三個回調(diào)方法分別對應(yīng)事件的不同狀態(tài)
源碼初探
Platform Channel基本結(jié)構(gòu)
首先了解一下這三種Channel的代碼:
BasicMessageChannel
class BasicMessageChannel<T> {
const BasicMessageChannel(this.name, this.codec);
final String name;
final MessageCodec<T> codec;
Future<T> send(T message) async {
return codec.decodeMessage(await BinaryMessages.send(name, codec.encodeMessage(message)));
}
void setMessageHandler(Future<T> handler(T message)) {
if (handler == null) {
BinaryMessages.setMessageHandler(name, null);
} else {
BinaryMessages.setMessageHandler(name, (ByteData message) async {
return codec.encodeMessage(await handler(codec.decodeMessage(message)));
});
}
}
void setMockMessageHandler(Future<T> handler(T message)) {
if (handler == null) {
BinaryMessages.setMockMessageHandler(name, null);
} else {
BinaryMessages.setMockMessageHandler(name, (ByteData message) async {
return codec.encodeMessage(await handler(codec.decodeMessage(message)));
});
}
}
}
MethodChannel
class MethodChannel {
const MethodChannel(this.name, [this.codec = const StandardMethodCodec()]);
final String name;
final MethodCodec codec;
void setMethodCallHandler(Future<dynamic> handler(MethodCall call)) {
BinaryMessages.setMessageHandler(
name,
handler == null ? null : (ByteData message) => _handleAsMethodCall(message, handler),
);
}
void setMockMethodCallHandler(Future<dynamic> handler(MethodCall call)) {
BinaryMessages.setMockMessageHandler(
name,
handler == null ? null : (ByteData message) => _handleAsMethodCall(message, handler),
);
}
Future<ByteData> _handleAsMethodCall(ByteData message, Future<dynamic> handler(MethodCall call)) async {
final MethodCall call = codec.decodeMethodCall(message);
try {
return codec.encodeSuccessEnvelope(await handler(call));
} on PlatformException catch (e) {
returun ...
} on MissingPluginException {
return null;
} catch (e) {
return ...
}
}
Future<T> invokeMethod<T>(String method, [dynamic arguments]) async {
assert(method != null);
final ByteData result = await BinaryMessages.send(
name,
codec.encodeMethodCall(MethodCall(method, arguments)),
);
if (result == null) {
throw MissingPluginException('No implementation found for method $method on channel $name');
}
final T typedResult = codec.decodeEnvelope(result);
return typedResult;
}
}
EventChannel
class EventChannel {
const EventChannel(this.name, [this.codec = const StandardMethodCodec()]);
final String name;
final MethodCodec codec;
Stream<dynamic> receiveBroadcastStream([dynamic arguments]) {
final MethodChannel methodChannel = MethodChannel(name, codec);
StreamController<dynamic> controller;
controller = StreamController<dynamic>.broadcast(onListen: () async {
BinaryMessages.setMessageHandler(name, (ByteData reply) async {
...
});
try {
await methodChannel.invokeMethod<void>('listen', arguments);
} catch (exception, stack) {
...
}
}, onCancel: () async {
BinaryMessages.setMessageHandler(name, null);
try {
await methodChannel.invokeMethod<void>('cancel', arguments);
} catch (exception, stack) {
...
}
});
return controller.stream;
}
}
這三種Channel都有兩個成員變量:
- name:表示Channel名字,用于區(qū)分不同Platform Channel的唯一標志,每個Channel使用唯一的name作為其唯一標志
- codec: 表示消息的編解碼器,Flutter采用了二進制字節(jié)流作為數(shù)據(jù)傳輸協(xié)議:發(fā)送方需要把數(shù)據(jù)編碼成二進制數(shù)據(jù),接受方再把數(shù)據(jù)解碼成原始數(shù)據(jù).而負責編解碼操作的就是Codec。
每個Channel中都使用到了BinaryMessages,它起到了信使的作用,負責將信息進行跨平臺的搬運,是消息發(fā)送和接受的工具。
setMessageHandler
在創(chuàng)建好BasicMessageChannel后,讓其接受來自另一平臺的消息,BinaryMessenger調(diào)用它的setMessageHandler方法為其設(shè)置一個消息處理器,配合BinaryMessenger完成消息的處理以及回復(fù);
send
在創(chuàng)建好BasicMessageChannel后,可以調(diào)用它的send方法向另一個平臺傳遞數(shù)據(jù)。
setMethodCallHandler
設(shè)置用于在此MethodChannel上接收方法調(diào)用的回調(diào)
receiveBroadcastStream
設(shè)置廣播流以接收此EventChannel上的事件
Handler
Flutter使用Handler處理Codec解碼后的消息。三種Platform Channel相對應(yīng),Flutter中也定義了三種Handler:
- MessageHandler: 用于處理字符串或者半結(jié)構(gòu)化消息,定義在BasicMessageChannel中.
- MethodCallHandler: 用于處理方法調(diào)用,定義在MethodChannel中.
- StreamHandler: 用于事件流通信,定義在EventChannel中
使用Platform Channel時,需要為其注冊一個對應(yīng)BinaryMessageHandler為其設(shè)置對應(yīng)的Handler。二進制數(shù)據(jù)會被BinaryMessageHanler進行處理,首先使用Codec進行解碼操作,然后再分發(fā)給具體Handler進行處理。
結(jié)語
欲更進一步了解Platform Channel設(shè)計與實現(xiàn),可前往深入Flutter技術(shù)內(nèi)幕:Platform Channel設(shè)計與實現(xiàn),關(guān)注大神博客