Flutter系列博客—09 MethodChannel實現原生與Flutter通信(二)

Flutter系列博客—09 MethodChannel實現原生與Flutter通信(二)

前言

上一篇我們講解了如何通過 EventChannel 實現 Android -> Flutter 的通信。

並且也看到了 Flutter 內部 EventChannel 源碼也是對 MethodChannel 的封裝。

因此這篇我們來說下如何通過 MethodChannel 實現 Android -> Flutter 的通信。

至於 Flutter -> Android 的通信,沒看過的小夥伴建議看下之前的文章 Flutter 即學即用系列博客——08 MethodChannel 實現 Flutter 與原生通信。

既然我們之前寫過 Flutter -> Android 的 MethodChannel,那麼我們現在要寫 Android -> Flutter 的 MethodChannel,可以仿照一下原先的寫法。

步驟如下:

第一步:Flutter UI 修改

我們的代碼在上一篇的基礎上做修改,在列上面增加一個文本用於確認收到了 Android 的請求。

String _arguments = 'unknown';
Text(_arguments),

第二步:在 Android 端寫 invokeMethod 引用 Flutter 方法

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 未實現對應方法

第三步:在 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:

Flutter系列博客—09 MethodChannel實現原生與Flutter通信(二)

初始顯示 unknown

點擊後顯示原生傳過來的內容:

Flutter系列博客—09 MethodChannel實現原生與Flutter通信(二)

點擊後顯示原生傳過來的內容

同時控制檯顯示打印信息如下:

success=null

我們發現 Android 確實回調成功了,但是另一個問題隨之而來,Flutter 如何將內容回調給 Android?

解決問題一時爽,一直解決問題一直爽。

也是很簡單的,就是我們寫一個異步方法將信息帶回去即可。

在 setState 方法後面添加下面代碼:

return returnToRaw();

具體方法實現如下:

Future<string> returnToRaw() async {
return 'received your message';
}
/<string>

這個時候再運行點擊按鈕會發現控制檯打印如下信息:

success=received your message

可以看到成功收到返回值了。

這裡演示返回的是字符串,因此異步方法返回類型是 Future<string> 。如果你要返回其他類型,可以自行修改。/<string>

如果希望回調 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');
}
/<string>

這裡通過拋出 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),
);
}
/<dynamic>

再深入 _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);
}
}
/<dynamic>/<bytedata>

到這裡就比較明朗了。

可以看到錯誤基本不用我們處理,也沒有太多可介入空間。

但是成功回調,這裡核心語句是

await handler(call)

因此我們上面通過一個異步方法返回字符串給原生。

由於筆者之前對 Future 不是很熟,因此為了解決這個問題,看了 dart 源碼:

https://www.dartlang.org/tutorials/language/futures

至此,結合系列博客 08 基本就完成了 MethodChannel 相關的雙向通信講解了。

Flutter系列博客—09 MethodChannel實現原生與Flutter通信(二)

源碼位置:

https://github.com/nesger/FlutterSample/tree/feature/method_channel_reverse


分享到:


相關文章: