分類簡介
flutter與原生通信主要有三種方式:MethodChannel、EventChannel、BasicMessageChannel,這三種方式均各有適用的場景:MethodChannel用于native與flutter的方法調用,EventChannel用于native單向的向flutter發(fā)送廣播消息,BasicMessageChannel用于native與flutter之間的消息互發(fā)。
詳細使用
MethodChannel
MethodChannel用于雙方之間的方法互調,使用步驟是:
1.創(chuàng)建一個MethodChannel對象,傳入MethodChannel名稱。
2.使用setMethodHandle對對方調用自己的方法進行監(jiān)聽,通過回調中的MethodCall對象方法名判斷、獲取方法參數(shù),并且返回調用結果。
3.使用invokeMethod來調用對方的方法,可傳入方法名,方法參數(shù),以及監(jiān)聽對方的回調結果。
以下是示例:
native
public void registerWith(FlutterEngine flutterEngine) {
methodChannel = new MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), "MethodChannel");
//監(jiān)聽flutter調用
methodChannel.setMethodCallHandler(new MethodChannel.MethodCallHandler() {
@Override
public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
if (call.method.equals("flutterCallNative")) {
result.success("args =" + call.arguments + ",result = 1");
}
}
});
//調用flutter方法
methodChannel.invokeMethod("methodName", "arguments", new MethodChannel.Result() {
@Override
public void success(@Nullable Object result) {
}
@Override
public void error(@NonNull String errorCode, @Nullable String errorMessage, @Nullable Object errorDetails) {
}
@Override
public void notImplemented() {
}
});
}
flutter
Future<void> testMethodCall() async {
var methodChannel = const MethodChannel("MethodChannel");
//監(jiān)聽native調用flutter方法
methodChannel.setMethodCallHandler((methodCall) async {
if (methodCall.method == 'nativeCallFlutterMethod') {
String args = 'nativeCallFlutterMethod 方法被調用了,參數(shù)為${methodCall
.arguments}';
Fluttertoast.showToast(msg: '$args flutterResult');
return '$args flutterResult';
}
});
//調用native方法
String result = await methodChannel.invokeMethod("flutterCallNative", 222);
Fluttertoast.showToast(msg: "native方法返回值:$result");
}
需要注意的是,MethodChannel的名稱需要雙方保持一致,否則就不是同一個MethodChannel了。另外這里的方法調用并不是像Java里面反射那樣去先找到class示例對象再解析到相應的方法,而是將雙方互發(fā)的消息包裝成了MethodCall對象,拿到這個對象后通過MethodCall里面的方法名去判斷要做什么操作,并不是直接就調用了自身(native或flutter)相對應的方法。具體要做什么操作、調用什么方法還是得自己去調用和實現(xiàn)。
EventChannel
EventChannel適用于native向flutter發(fā)送廣播消息,只是單向的消息發(fā)送,native發(fā),flutter收,返過來flutter并不能向native發(fā)送消息。例如native可將定位數(shù)據(jù)不斷的報給flutter,或者錄像數(shù)據(jù)等等,所有基于原生能力產生的數(shù)據(jù)都可以通過EventChannel進行發(fā)送。
步驟:
1.創(chuàng)建一個EventChannel對象,傳入EventChannel名稱。
2.flutter端調用receiveBroadcastStream進行廣播消息注冊,傳入arguments參數(shù)即為廣播名稱,此參數(shù)是告訴native端你要接受的廣播類型,判別是什么廣播發(fā)送的數(shù)據(jù)。
2.native調用setStreamHandler方法進行廣播消息監(jiān)聽,onListen回調里會有一個arguments參數(shù),這里及為flutter注冊的廣播類型,若flutter端沒有注冊,則native端不會收到這個回調,也就無法進行消息發(fā)送。收到flutter端的廣播注冊后,根據(jù)arguments可判斷廣播類型,然后根據(jù)EventChannel.EventSink來進行消息發(fā)送,EventSink.success()即可將消息發(fā)送給flutter端。
3.flutter進行廣播注冊會返回一個streamSubscription類型的對象,該對象可以進行消息的停止,native可在onCancel回調里面收到。
示例如下:
native
public void registerWith(FlutterEngine engine) {
EventChannel eventChannel = new EventChannel(engine.getDartExecutor().getBinaryMessenger(), "eventChannel");
eventChannel.setStreamHandler(new EventChannel.StreamHandler() {
@Override
public void onListen(Object arguments, EventChannel.EventSink events) {
if (arguments.equals("Locations")) {
events.success("");
EventChannelPlugin.this.events = events;
events.success("經(jīng)緯度。。。");
}
}
@Override
public void onCancel(Object arguments) {
}
});
}
flutter
Future<void> testEventChannel() async {
var eventChannel = const EventChannel("eventChannel");
var streamSubscription = eventChannel
.receiveBroadcastStream("Locations")
.listen((event) {
}, onError: (dynamic error) {
}, cancelOnError: true);
streamSubscription.cancel();
}
BasicMessageChannel
BasicMessageChannel就是比較常用的消息互發(fā),使用步驟如下:
1.創(chuàng)建BasicMessageChannel對象,傳入BasicMessageChannel名稱。還需傳入編解碼方式(可以自己實現(xiàn)),系統(tǒng)提供了一些列的編解碼方式,后續(xù)會介紹到。
2.使用setMessageHandler方法進行消息監(jiān)聽,也可進行回復。
3.使用send方法進行消息發(fā)送。
native
public void registerWith(FlutterEngine flutterEngine) {
BasicMessageChannel basicMessageChannel = new BasicMessageChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), "BasicMessageChannel", new MessageCodec() {
@Override
public ByteBuffer encodeMessage(@Nullable Object message) {
return null;
}
@Override
public Object decodeMessage(@Nullable ByteBuffer message) {
return null;
}
});
basicMessageChannel.setMessageHandler(new BasicMessageChannel.MessageHandler() {
@Override
public void onMessage(@Nullable Object message, @NonNull BasicMessageChannel.Reply reply) {
}
});
basicMessageChannel.send("", new BasicMessageChannel.Reply() {
@Override
public void reply(@Nullable Object reply) {
}
});
}
flutter
Future<void> testBasicMsgChannel() async {
var basicMessageChannel = const BasicMessageChannel(
"BasicMessageChannel", StandardMessageCodec());
basicMessageChannel.setMessageHandler((message) async {
return null;
});
Object? test = await basicMessageChannel.send("");
}
編碼方式
無論哪種方式的消息傳遞,最終都是將自定義數(shù)據(jù)轉化為二進制數(shù)據(jù)進行傳遞,flutter提供的編解碼方式分為MethodCodec和MessageCodec兩種,EventChannel和MethodChannel使用的就是MethodCodec,BasicMessageChannel使用的是MessageCodec。MethodCodec其實就是在MessageCodec的基礎上將數(shù)據(jù)包裝了一下,使其轉化為MethodCall對象方便使用。
MethodCodec源碼:
public interface MethodCodec {
/**
* Encodes a message call into binary.
* @param methodCall a {@link MethodCall}.
* @return a {@link ByteBuffer} containing the encoding between position 0 and the current position.
*/
@NonNull
ByteBuffer encodeMethodCall(@NonNull MethodCall methodCall);
/**
* Decodes a message call from binary.
* @param methodCall the binary encoding of the method call as a {@link ByteBuffer}.
* @return a {@link MethodCall} representation of the bytes between the given buffer's current
* position and its limit.
*/
@NonNull
MethodCall decodeMethodCall(@NonNull ByteBuffer methodCall);
}
MethodCodec提供了兩種方式:JSONMethodCodec和StandardMethodCodec,前一種就是JSON和MethodCall對象之間的互轉,后一種則是根據(jù)傳入的數(shù)據(jù)基本類型(String,Integer等)來進行互轉。
MessageCodec則提供了四種方式,如下圖,具體就不詳細講述了,看看名字就知道是怎么回事,可以直接去看源碼。最常用和默認的就是StandardMessageCodec方式。
FlutterPlugin使用方式
從上面的使用方式可以看出,每一種Channel在創(chuàng)建的時候都需要傳遞一個BinaryMessenger,這個接口可以在FlutterEngine里面拿到,因此需要在FlutterActivity里面實現(xiàn)configFlutterEngine方法里面重寫這個方法。FlutterActivity在attach FlutterEngine之后就會調用這個configFlutterEngine方法,通過flutterEngine.getPlugins().add(FlutterPlugin)方法可以FlutterPlugin的回調方法里進行數(shù)據(jù)的初始化和銷毀工作。如下圖
public class MainActivity extends FlutterActivity {
@Override
public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
super.configureFlutterEngine(flutterEngine);
flutterEngine.getPlugins().add(new FlutterPlugin() {
@Override
public void onAttachedToEngine(@NonNull FlutterPluginBinding binding) {
new MethodChannelPlugin().registerWith(binding.getBinaryMessenger());
}
@Override
public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
}
});
}
}
這個回調方法里的FlutterPluginBinding提供了一些我們可能會用到的對象,如下:
public FlutterPluginBinding(
@NonNull Context applicationContext,
@NonNull FlutterEngine flutterEngine,
@NonNull BinaryMessenger binaryMessenger,
@NonNull TextureRegistry textureRegistry,
@NonNull PlatformViewRegistry platformViewRegistry,
@NonNull FlutterAssets flutterAssets) {
this.applicationContext = applicationContext;
this.flutterEngine = flutterEngine;
this.binaryMessenger = binaryMessenger;
this.textureRegistry = textureRegistry;
this.platformViewRegistry = platformViewRegistry;
this.flutterAssets = flutterAssets;
}