Flutter混合開發(三):Android與Flutter之間通訊詳細指南

點擊上方「Android開發之旅,立刻關注javascript


通訊場景css


咱們在作Flutter混合開發的時候一般須要進行Flutter和Native之間的通訊。好比Dart調用Native的相冊選擇圖片,Native將電量、GPS信息主動傳遞給Dart等等。在混合開發中通訊一般有如下幾種:java


  • 初始化Flutter時Native向Dart傳遞數據。typescript

  • Native發送數據給Dart。微信

  • Dart發送數據給Native。app

  • Dart發送數據給Native,而後Native回傳數據給Dart。異步


第一種通訊方式咱們在講解原生項目接入Flutter時已經講解過,有興趣的同窗能夠移步到Flutter混合開發(一):Android項目集成Flutter模塊詳細指南看下。async



通訊機制ide


Flutter與Native端之間的通訊機制是經過Platform Channel來完成。消息使用Channel在Flutter端和Native端進行傳遞。具體以下圖所示:
函數



從圖中能夠看出,兩端之間的通訊都是雙向的,並且是完成異步傳遞。Flutter定義了三種不一樣類型的Channel:


  • BasicMessageChannel:用於傳遞字符串或者半結構化的信息,持續通訊,收到信息後能夠進行回覆。

  • MethodChannel:用於傳遞方法調用,一次性通訊。一般用於Dart調用Native的方法。

  • EventChannel:用於數據流的通訊,持續通訊,收到消息後沒法回覆這次消息。一般用於Native向Dart的通訊。


下面咱們就來看看這三種Channel通訊方式的具體使用和介紹。


BasicMessageChannel


Android端的相關方法:


BasicMessageChannel(BinaryMessenger messenger, String name, MessageCodec<T> codec)


  • messenger參數是消息信使(FlutterView),是消息發送和接受的工具。

  • name參數是channel的名字也是其惟一標識,要和Dart端統一。

  • codec是消息編解碼器,也須要和Dart端統一。它的做用就是將消息在發送的時候進行加密,dart端收到消息後在進行解密,傳遞的都是二進制數據。它有四種類型:BinaryCodec、StringCodec、JSONMessageCodec、StandardMessageCodec,四種類型均屬於MessageCodec範疇。如不指定默認是StandardMessageCodec。


當咱們須要接受來自Dart端發送的消息時使用setMessageHandler方法:


void setMessageHandler(BasicMessageChannel.MessageHandler<T> handler)


參數handler是消息處理器,配合BinaryMessenger來完成對消息的處理。它是一個接口,具體的實如今onMessage方法中:


public interface MessageHandler<T{    void onMessage(T message, BasicMessageChannel.Reply<T> reply);}

參數message即爲Dart發送的數據, reply是用於回覆消息的回調函數,提供reply.reply("")設置回覆的內容。


上面講的是接受Dart端的消息,那麼Native端主動發送消息則是使用send方法,它有兩個重載方法:


void send(T message)void send(T message, BasicMessageChannel.Reply<T> callback)

參數message即爲要發生給Dart的數據,callback回調則是用於接收Dart端收到消息後的回覆信息。


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<T>爲發送消息後等待Native回覆的回調函數。


BasicMessageChannel實戰:


Android端和Flutter端相互發送消息,而且在收到消息後返回對方信息。


Android端代碼:


//初始化BasicMessageChannelBasicMessageChannel<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));

Dart端代碼:


//初始化BasicMessageChannelstatic 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


使用MethodChannel相關方法的參數類型及含義和BasicMessageChannel的參數含義都是相同的,下面就不一一解釋了。


Androd端相關方法:


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();}


Dart端相關方法:


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實戰


Native端調用Dart端的getPlatform方法返回當前的os平臺,Dart端調用Native端的getBatteryLevel方法獲取當前手機電量。


Android端代碼:

//初始化MethodChannelMethodChannel 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; }});


Dart端代碼:


// receivevoid 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}//sendvoid 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


EventChannel內部實現原理其實也是經過MethodChannel來完成的。


Android端相關代碼:


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回調。


Dart端相關代碼:


const EventChannel(this.name, [this.codec = const StandardMethodCodec()]);


經過EventChannel初始化一個channel對象。若是從Native中接受數據須要定義一個廣播流:


Stream<dynamic> receiveBroadcastStream([ dynamic arguments ])


經過調用Stream的listen方法來完成註冊。


EventChannel實戰


Native端主動發送電量信息給Dart端,Dart端收到信息後進行展現。


Android端代碼:



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) { }});


Dart端代碼:

//initstatic const EventChannel _eventChannel = EventChannel("EventChannelPlugin");//receivevoid 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開發必備Dart基礎:Dart快速入門
Flutter混合開發(一):Android項目集成Flutter模塊詳細指南
Flutter混合開發(二):iOS項目集成Flutter模塊詳細指南


 


微信掃一掃,關注個人公衆號


原創不易,若是您以爲有點用,但願能夠隨手轉發或者「在看」,拜謝。


本文分享自微信公衆號 - Android開發之旅(AndroidDevTour)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索