目录传送门:《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)
  }
}复制代码