依托于与Skia渲染引擎的深度定制和优化,Flutter提供了高效的渲染支持,能够保证绝对的跨平台渲染一致性。一个完整的App除了UI界面之外,还需要一些原生平台的底层能力,比如数据持久化存储、消息推送、硬件支持等。由于Flutter之接管了渲染层,系统底层能力无法通过Flutter框架支持,目前很多原生系统中已有的相对成熟的库,在Flutter尚未实现。
Flutter为了解决原生系统底层能力的支持以及原生平台代码的调用,Flutter在逻辑层提供了方法通道机制(Method Channel)。基于方法通道,我们可以将原生系统拥有的底层能力,以接口的方式暴露给Dart层,使的Dart在使用原生底层能力、调用原生平台代码的时候,就像是在调用Dart API一样。
方法通道
为了能够访问系统底层原生代码,Flutter提供了一套灵活而轻量的机制,满足Dart和原生代码之间的通信,即方法调用的消息传递机制,而用来传递消息的通道就是方法通道。
一次典型的方法调用过程类似网络请求,由作为客户端的Flutter通过方法通道向作为服务端的原生代码宿主发送方法请求,原生代码宿主在监听到请求之后调用平台相关的方法来处理Flutter的请求,最后将处理的结果通过方法通道回发给Flutter层。
从上图可以看到,方法调用的处理和响应,在Android平台是在FlutterView注册的,在iOS平台是在FlutterViewController注册的。FlutterView和FlutterViewController为Flutter应用提供了一个画板,使得Flutter通过Skia引擎就可以在这个画板上绘制出想要的视觉效果。
FlutterView和FlutterViewController不仅仅是Flutter应用的容器,同时也是Flutter应用的入口,自然也是注册方法调用最合适的地方。
下面以App跳转到应用市场为例,演示方法通道的使用方法。
首先,需要提供一个唯一的字符串作为构造一个方法通道的唯一标识符,然后在这个方法通道上制定调用自定义方法"openAppMarket",来发起一次打开应用商店的请求:
【注意】就像网络请求一样,方法通道的调用也会有异常的情况,所以需要处理异常情况,以免出现方法通道调用异常而引起的App奔溃的情况。
上面的代码实现了Dart层面的自定义方法通道的调用,接下来需要在Android/iOS平台上的通道方法的响应。
Android端的接口实现
在Android平台,方法通道的注册是在Flutter的入口完成的,也就是MainActivity的FlutterView中实现的,因此我们需要找到Flutter应用的Android宿主程序,找到MainActivity.java,并在MainActivity的onCreate方法中添加方法通道的注册和自定义方法的实现。
在MainActivity的onCreate方法中注册方法通道:
iOS端的接口实现
和Android平台一样,方法通道的注册也是在Flutter应用的入口,我们需要在Flutter应用的iOS宿主App中找到AppDelegate.m文件,在didFinishLaunchingWithOptions方法中注册方法通道。
在didFinishLaunchingWithOptions方法中添加方法通道的声明:
这样我们就完成了在Android、iOS平台的方法通道和接口的实现,之后就可以在Flutter层通过方法通道的调用,实现原生代码的调用了。
需要注意的是,我们在原生代码层处理完请求之后,会向Dart层回传一个result。同样的一个回调参数,在Dart、Android、iOS使用了三种不同的数据类型,Android端使用的java.lang.Integer类型,iOS端使用的是NSNumber、在Dart接收到的回传参数全部按照int类型来处理。
这是因为使用通道方法进行方法调用的使用,会涉及到跨系统数据交互,Dart为了解决跨系统数据交互的问题,使用了StandardMessageCodec对通道中传输的数据进行类似JSON的二进制序列化,以统一标准的数据进行通信,不同的系统在发送/接收到传递参数的时候,会根据当前系统的特性对传输参数进行序列化/反序列化。
上面的例子中,原生平台将java.lang.Integer/NSNumber类型的回传参数首先进行序列化,转化为二进制数据之后,再由方法通道进行传输,等数据传递到Dart层的时候,系统会将二进制数据转成int类型的数据。
不同类型的数据在Android、iOS和Dart的对应关系如下:
网友评论