目录传送门:《Flutter快速上手指南》先导篇
通过阅读 混合开发(一) 和 混合开发(二) ,相信你已经让一个 原生 + Flutetr
恭喜你 ???!
现在,你可能遇到了 Flutter代码 和 原生代码 之前无法互相调用的难题。
因为 Flutter 作为独立于原生 Android 的一套开发框架,肯定是不能直接互相调用和愉快的交换信息的。
现在,来看看 Flutter 是如何解决这些问题的。
1.Platform Channels
Flutter 使用 Platform Channels
上图是其中 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
- 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
最后的 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)
}
}复制代码