經過閱讀 混合開發(一) 和 混合開發(二) ,相信你已經讓一個 原生 + Flutetr 的混合應用運行起來了。git
恭喜你 🎉🎉🎉!github
如今,你可能遇到了 Flutter代碼 和 原生代碼 以前沒法互相調用的難題。bash
由於 Flutter 做爲獨立於原生 Android 的一套開發框架,確定是不能直接互相調用和愉快的交換信息的。架構
如今,來看看 Flutter 是如何解決這些問題的。框架
Flutter 使用 Platform Channels 架構來實現 Flutter 和 原生 之間的通訊。異步
上圖是其中 MethodChannel 的架構示意圖,Flutter 能夠經過 MethodChannel 異步的發送和接收信息。async
MethodChannel 是通過封裝的比較方便的通訊方式,Flutter 官網的例子也是經過 MethodChannel 來實現的。ide
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 |
MethodChannel 經過特定的通道,來創建起 Flutter 和 Native 之間通訊橋樑。
固然,咱們須要在 Flutter 和 Native 兩端都須要定義相同的通道。
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 就行。
在一個大型的項目中。你可能會須要創建不少的通訊通道,因此建議統一的管理這些通訊通道。
創建好通訊通道,來看看如何讓 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)
}
}
複製代碼
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)
}
}複製代碼