上一篇咱們講解了如何經過 EventChannel 實現 Android -> Flutter 的通訊。git
而且也看到了 Flutter 內部 EventChannel 源碼也是對 MethodChannel 的封裝。github
所以這篇咱們來講下如何經過 MethodChannel 實現 Android -> Flutter 的通訊。less
至於 Flutter -> Android 的通訊,沒看過的小夥伴建議看下以前的文章 Flutter 即學即用系列博客——08 MethodChannel 實現 Flutter 與原生通訊。異步
既然咱們以前寫過 Flutter -> Android 的 MethodChannel,那麼咱們如今要寫 Android -> Flutter 的 MethodChannel,能夠仿照一下原先的寫法。async
步驟以下:ide
第一步:Flutter UI 修改debug
咱們的代碼在上一篇的基礎上作修改,在列上面增長一個文本用於確認收到了 Android 的請求。code
String _arguments = 'unknown'; Text(_arguments),
第二步:在 Android 端寫 invokeMethod 引用 Flutter 方法orm
methodChannel.invokeMethod("getContent", "arguments", new MethodChannel.Result() { @Override public void success(@Nullable Object o) { Log.e(TAG, "success="+o); } @Override public void error(String s, @Nullable String s1, @Nullable Object o) { Log.e(TAG, "error="+s); } @Override public void notImplemented() { Log.e(TAG, "notImplemented"); } });
參數說明:
第一個爲方法名。用於 Flutter 區分 Android 的不一樣請求。
第二個爲參數值。用於 Android 須要給 Flutter 傳遞的額外數據。
第三個爲 Android -> Flutter 請求的結果回調。
回調有三種狀況:
1)調用成功
2)調用失敗
3)Flutter 未實現對應方法blog
第三步:在 Flutter 調用對應 MethodChannel 的 setMethodCallHandler
methodChannel.setMethodCallHandler((MethodCall call){ if (call?.method == 'getContent') { setState(() { _arguments = call?.arguments ?? ''; }); } });
看到這裏的 MethodCall 你應該很熟悉了,經過 call.method 能夠知道 Android 要獲取的方法名,經過 call.arguments 能夠拿到 Android 傳遞過來的數據。
這裏的 getContent 對應 Android 的 invokeMethod。
爲了確認咱們獲取到了,咱們將 Android 傳遞過來的參數顯示出來。
第四步:運行
能夠看到效果以下:
初始顯示 unknown
點擊後顯示原生傳過來的內容
同時控制檯顯示打印信息以下:
success=null
咱們發現 Android 確實回調成功了,可是另外一個問題隨之而來,Flutter 如何將內容回調給 Android?
解決問題一時爽,一直解決問題一直爽。
也是很簡單的,就是咱們寫一個異步方法將信息帶回去便可。
在 setState 方法後面添加下面代碼:
return returnToRaw();
具體方法實現以下:
Future<String> returnToRaw() async { return 'received your message'; }
這個時候再運行點擊按鈕會發現控制檯打印以下信息:
success=received your message
能夠看到成功收到返回值了。
這裏演示返回的是字符串,所以異步方法返回類型是 Future
若是但願回調 notImplemented,不要在 Flutter 調用 MethodChannel 的 setMethodCallHandler 或者 setMethodCallHandler 的參數設置爲 null 便可。
//方法一 // methodChannel.setMethodCallHandler((MethodCall call){ // if (call?.method == 'getContent') { // setState(() { // _arguments = call?.arguments ?? ''; // }); // return returnToRaw(); // } // }); //方法二 methodChannel.setMethodCallHandler(null);
若是但願回調 error,修改 returnToRaw 方法便可。以下:
Future<String> returnToRaw() async { throw PlatformException(code: 'error code'); }
這裏經過拋出 PlatformException 並將錯誤信息帶回去給 Android。
通常錯誤信息除非是手動須要拋,不然源碼會幫咱們處理的。
這裏是爲了演示因此手動拋出異常。
好了,至此 MethodChannel Android-> Flutter 咱們也實現了。
其實不論是 Android -> Flutter 仍是 Flutter-> Android,都是平臺相關代碼。
所以能夠直接到 platform_channel.dart 裏面看看源碼。
除了 EventChannel、MethodChannel,還有 BasicMessageChannel 和 OptionalMethodChannel,這些就交給小夥伴們本身去研究了。
這邊分享一下研究 MethodChannel 實現 Android -> Flutter 的過程遇到的坑。
但願不止是授你們以魚,更是授你們以漁。
坑1:一開始將原生 MethodChannel 寫到外面,致使 Flutter 沒收到請求
由於 Flutter 是在 initState 裏面去 setMethodCallHandler 的,而 debug 模式下可能 Flutter 還沒加載完成,這個時候發送消息,Flutter 就可能沒收到。
後面改爲點擊以後 Flutter -> Android,Android 再發給 Flutter。
這個問題是異步的緣由致使的。
明確以後經過正確的方式就能夠收到請求了。
坑2:Flutter 收到以後,如何回調回消息呢?
首先點擊進入 setMethodCallHandler 源碼,以下:
void setMethodCallHandler(Future<dynamic> handler(MethodCall call)) { BinaryMessages.setMessageHandler( name, handler == null ? null : (ByteData message) => _handleAsMethodCall(message, handler), ); }
再深刻 _handleAsMethodCall,以下:
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) { return codec.encodeErrorEnvelope( code: e.code, message: e.message, details: e.details, ); } on MissingPluginException { return null; } catch (e) { return codec.encodeErrorEnvelope(code: 'error', message: e.toString(), details: null); } }
到這裏就比較明朗了。
能夠看到錯誤基本不用咱們處理,也沒有太多可介入空間。
可是成功回調,這裏核心語句是
await handler(call)
所以咱們上面經過一個異步方法返回字符串給原生。
因爲筆者以前對 Future 不是很熟,所以爲了解決這個問題,看了 dart 源碼👇:
https://www.dartlang.org/tutorials/language/futures
至此,結合系列博客 08 基本就完成了 MethodChannel 相關的雙向通訊講解了。
源碼位置:
https://github.com/nesger/FlutterSample/tree/feature/method_channel_reverse
更多閱讀:
Flutter 即學即用系列博客
Flutter 即學即用系列博客——01 環境搭建
Flutter 即學即用系列博客——02 一個純 Flutter Demo 說明
Flutter 即學即用系列博客——03 在舊有項目引入 Flutter
Flutter 即學即用系列博客——04 Flutter UI 初窺
Flutter 即學即用系列博客——05 StatelessWidget vs StatefulWidget
Flutter 即學即用系列博客——06 超實用 Widget 集錦
Flutter 即學即用系列博客——07 RenderFlex overflowed 引起的思考
Flutter 即學即用系列博客——08 MethodChannel 實現 Flutter 與原生通訊
Flutter 即學即用系列博客——09 EventChannel 實現原生與 Flutter 通訊(一)
Flutter & dart
dart 如何優雅的避空
Flutter map 妙用及 .. 使用