Flutter实战 插件开发:平台通道简介
“平台特定”或“特定平台”中的平台指的就是Flutter应用程序运行的平台,如 Android 或 IOS。我们知道一个完整的 Flutter 应用程序实际上包括原生代码和Flutter代码两部分。由于 Flutter 本身只是一个 UI 系统,它本身是无法提供一些系统能力,比如使用蓝牙、相机、GPS 等,因此要在 Flutter APP 中调用这些能力就必须和原生平台进行通信。为此,Flutter 中提供了一个平台通道(platform channel),用于 Flutter 和原生平台的通信。平台通道正是 Flutter 和原生之间通信的桥梁,它也是 Flutter 插件的底层基础设施。
Flutter 使用了一个灵活的系统,允许您调用特定平台的 API,无论在 Android 上的 Java 或 Kotlin 代码中,还是 iOS 上的 ObjectiveC 或 Swift 代码中均可用。 Flutter 与原生之间的通信依赖灵活的消息传递方式:
- 应用的 Flutter 部分通过平台通道(platform channel)将消息发送到其应用程序的所在的宿主(iOS 或 Android)应用(原生应用)。
- 宿主监听平台通道,并接收该消息。然后它会调用该平台的 API,并将响应发送回客户端,即应用程序的 Flutter 部分。
#平台通道
使用平台通道在 Flutter(client)和原生(host)之间传递消息,如下图所示:
当在Flutter中调用原生方法时,调用信息通过平台通道传递到原生,原生收到调用信息后方可执行指定的操作,如需返回数据,则原生会将数据再通过平台通道传递给 Flutter。值得注意的是消息传递是异步的,这确保了用户界面在消息传递时不会被挂起。
在客户端,MethodChannel API (opens new window)可以发送与方法调用相对应的消息。 在宿主平台上,MethodChannel
在Android API (opens new window)和 FlutterMethodChannel iOS API (opens new window)可以接收方法调用并返回结果。这些类可以帮助我们用很少的代码就能开发平台插件。
注意: 如果需要,方法调用(消息传递)可以是反向的,即宿主作为客户端调用 Dart 中实现的 API。
quick_actions
(opens new window)插件就是一个具体的例子。
#平台通道数据类型支持
平台通道使用标准消息编/解码器对消息进行编解码,它可以高效的对消息进行二进制序列化与反序列化。由于 Dart 与原生平台之间数据类型有所差异,下面我们列出数据类型之间的映射关系。
Dart | Android | iOS |
---|---|---|
null | null | nil (NSNull when nested) |
bool | java.lang.Boolean | NSNumber numberWithBool: |
int | java.lang.Integer | NSNumber numberWithInt: |
int, 如果不足32位 | java.lang.Long | NSNumber numberWithLong: |
int, 如果不足64位 | java.math.BigInteger | FlutterStandardBigInteger |
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
,还可以使用BasicMessageChannel
(opens new window),它支持使用自定义消息编解码器进行基本的异步消息传递。 此外,可以使用专门的BinaryCodec
(opens new window)、StringCodec
(opens new window)和 JSONMessageCodec
(opens new window)类,或创建自己的编解码器。
#如何获取平台信息
Flutter 中提供了一个全局变量defaultTargetPlatform
来获取当前应用的平台信息,defaultTargetPlatform
定义在"platform.dart"中,它的类型是TargetPlatform
,这是一个枚举类,定义如下:
enum TargetPlatform {
android,
fuchsia,
iOS,
}
可以看到目前 Flutter 只支持这三个平台。我们可以通过如下代码判断平台:
if(defaultTargetPlatform==TargetPlatform.android){
// 是安卓系统,do something
...
}
...
由于不同平台有它们各自的交互规范,Flutter Material 库中的一些组件都针对相应的平台做了一些适配,比如路由组件MaterialPageRoute
,它在 android 和 ios 中会应用各自平台规范的切换动画。那如果我们想让我们的 APP 在所有平台都表现一致,比如希望在所有平台路由切换动画都按照 ios 平台一致的左右滑动切换风格该怎么做?Flutter 中提供了一种覆盖默认平台的机制,我们可以通过显式指定debugDefaultTargetPlatformOverride
全局变量的值来指定应用平台。比如:
debugDefaultTargetPlatformOverride=TargetPlatform.iOS;
print(defaultTargetPlatform); // 会输出TargetPlatform.iOS
上面代码即在 Android 中运行后,Flutter APP 就会认为是当前系统是 iOS,Material 组件库中所有组件交互方式都会和 iOS 平台对齐,defaultTargetPlatform
的值也会变为TargetPlatform.iOS
。