阅读 1282

22.原生项目和Flutter的混合开发(三)

目录传送门:《Flutter快速上手指南》先导篇

通过阅读 混合开发(一)混合开发(二) ,相信你已经让一个 原生 + Flutetr 的混合应用运行起来了。

恭喜你 🎉🎉🎉!

现在,你可能遇到了 Flutter代码 和 原生代码 之前无法互相调用的难题。

因为 Flutter 作为独立于原生 Android 的一套开发框架,肯定是不能直接互相调用和愉快的交换信息的。

现在,来看看 Flutter 是如何解决这些问题的。

1.Platform Channels

Flutter 使用 Platform Channels 架构来实现 Flutter 和 原生 之间的通信。

上图是其中 MethodChannel 的架构示意图,Flutter 可以通过 MethodChannel 异步的发送和接收信息。

MethodChannel 是经过封装的比较方便的通信方式,Flutter 官网的例子也是通过 MethodChannel 来实现的。

Platform Channels 仅允许以下几种的数据类型在通信中使用:

DartAndroidiOS
nullnullnil (NSNull when nested)
booljava.lang.BooleanNSNumber numberWithBool
intjava.lang.IntegerNSNumber numberWithInt
int, if 32 bits not enoughjava.lang.LongNSNumber numberWithLong
doublejava.lang.DoubleNSNumber numberWithDouble
Stringjava.lang.StringNSString
Uint8Listbyte[]FlutterStandardTypedData typedDataWithBytes
Int32Listint[]FlutterStandardTypedData typedDataWithInt32
Int64Listlong[]FlutterStandardTypedData typedDataWithInt64
Float64Listdouble[]FlutterStandardTypedData typedDataWithFloat64
Listjava.util.ArrayListNSArray
Mapjava.util.HashMapNSDictionary

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)
      }
    }复制代码

目录传送门:《Flutter快速上手指南》先导篇

如何找到我?

传送门:CoorChice 的主页

传送门:CoorChice 的 Github