通過閱讀 混合開發(一) 和 混合開發(二) ,相信你已經讓一個 原生 + Flutetr 的混合應用執行起來了。
恭喜你 ???!
現在,你可能遇到了 Flutter程式碼 和 原生程式碼 之前無法互相呼叫的難題。
因為 Flutter 作為獨立於原生 Android 的一套開發框架,肯定是不能直接互相呼叫和愉快的交換資訊的。
現在,來看看 Flutter 是如何解決這些問題的。
1.Platform Channels
Flutter 使用 Platform Channels 架構來實現 Flutter 和 原生 之間的通訊。
上圖是其中 MethodChannel 的架構示意圖,Flutter 可以通過 MethodChannel 非同步的傳送和接收資訊。
MethodChannel 是經過封裝的比較方便的通訊方式,Flutter 官網的例子也是通過 MethodChannel 來實現的。
Platform Channels 僅允許以下幾種的資料型別在通訊中使用:
Dart | Android | iOS |
---|---|---|
null | null | nil (NSNull when nested) |
bool | java.lang.Boolean | NSNumber numberWithBool |
int | java.lang.Integer | NSNumber numberWithInt |
int, if 32 bits not enough | java.lang.Long | NSNumber numberWithLong |
double | java.lang.Double | NSNumber numberWithDouble |
String | java.lang.String | NSString |
Uint8List | byte[] | FlutterStandardTypedData typedDataWithBytes |
Int32List | int[] | FlutterStandardTypedData typedDataWithInt32 |
Int64List | long[] | FlutterStandardTypedData typedDataWithInt64 |
Float64List | double[] | FlutterStandardTypedData typedDataWithFloat64 |
List | java.util.ArrayList | NSArray |
Map | java.util.HashMap | NSDictionary |
2.如何使用 MethodChannel
MethodChannel 通過特定的通道,來建立起 Flutter 和 Native 之間通訊橋樑。
當然,我們需要在 Flutter 和 Native 兩端都需要定義相同的通道。
2.1 第一步:定義通訊通道
Flutter 端:
先匯入
import 'package:flutter/services.dart';
包,然後建立一個 MethodChannel。const channel = MethodChannel('foo'); 複製程式碼
Native - Android 端:
MethodChannel channel = new MethodChannel(flutterView, "foo");複製程式碼
Native - iOS 端:
let channel = FlutterMethodChannel( name: "foo", binaryMessenger: flutterView) 複製程式碼
建立一個通訊通道的方式很簡單,只需要使用相同的名稱(比如上面例子中的 "foo"
)建立 MethodChannel 就行。
在一個大型的專案中。你可能會需要建立很多的通訊通道,所以建議統一的管理這些通訊通道。
2.2 Flutter to Native
建立好通訊通道,來看看如何讓 Flutter 主動和 Native 通訊。
Flutter 端:
final String greeting = await channel.invokeMethod('bar', 'world'); print(greeting);複製程式碼
通過
invokeMethod(<標識>, <資料>)
函式可以主動發起和 Native 的一次通訊,且能夠獲得響應,允許的資料型別就是前面表格中列出的資料型別。當然,為了不阻塞 UI,你需要在非同步中進行。
Native - Android 端:
channel.setMethodCallHandler((methodCall, result) -> { if (methodCall.method.equals("bar")) { result.success("success, " + methodCall.arguments); } });複製程式碼
在 Native 端,通過為 MethodChannel 設定一個處理器 MethodCallHandler。
當 Flutter 向 Native 發起通訊時,能夠回撥處理器中的
onMethodCall()
函式。在該回撥中,能夠通過 MethodCall 獲取 Flutter 傳送過來的資訊,通過 MethodChannel.Result 來向 Flutter 傳送響應結果。
Native - iOS 端:
channel.setMethodCallHandler { (call: FlutterMethodCall, result: FlutterResult) -> Void in switch (call.method) { case "bar": result("Hello, \(call.arguments as! String)") default: result(FlutterMethodNotImplemented) } } 複製程式碼
2.3 Native to Flutter
Flutter 端:
設定接收 Native 資訊的處理器:
channel.setMethodCallHandler((MethodCall call) async { switch (call.method) { case 'bar': return 'Hello, ${call.arguments}'; case 'baz': throw PlatformException(code: '400', message: 'This is bad'); default: throw MissingPluginException(); } }) 複製程式碼
通過
setMethodCallHandler
函式設定一個Future<dynamic> handler(MethodCall call)
函式。該函式會在接收到 Native 資訊時被呼叫,從 MethodCall 中能夠獲得 Native 傳送過來的資料。
最後的
return
環節可以返回資料給 Native。Native - Android 端:
channel.invokeMethod("bar", "message", new MethodChannel.Result @Override public void success(@Nullable Object o) { // 傳送成功時回撥 } @Override public void error(String s, @Nullable String s1, @Nullable // 傳送失敗時回撥 } @Override public void notImplemented() { // 如果該通道在Flutter端未實現,會回撥這裡 } }); 複製程式碼
第一個引數是 Flutter 端通過
call.method
獲得的標示。第二個引數是需要傳送的資料。
第三個引數用於監聽通訊是完成狀態。
Native - iOS 端:
channel.invokeMethod(name, arguments: value) { (result: Any?) -> Void in if let error = result as? FlutterError { os_log("%@ failed: %@", type: .error, name, error.message!) } else if FlutterMethodNotImplemented.isEqual(result) { os_log("%@ not implemented", type: .error, name) } else { os_log("%@", type: .info, result as! NSObject) } }複製程式碼