Flutter插件开发:平台通道详解

Viewed 0

插件开发:平台通道简介

平台特定或特定平台指的是Flutter运行的平台,如Android或iOS,即应用的原生部分。平台通道是Flutter与原生平台之间通信的桥梁,也是Flutter插件的底层基础设施。

Flutter使用了一个灵活的系统,允许开发者调用特定平台的API,无论是在Android上的Java或Kotlin代码中,还是iOS上的Objective-C或Swift代码中均可用。

Flutter与原生之间的通信依赖灵活的消息传递方式:

  • 应用的Flutter部分通过平台通道将消息发送到其应用程序所在的宿主(iOS或Android)应用,即原生应用。
  • 宿主监听平台通道并接收消息,然后调用该平台的API,并将响应发送回客户端,即应用程序的Flutter部分。

平台通道

平台通道在Flutter(客户端)和原生(宿主)之间传递消息。当在Flutter中调用原生方法时,调用信息通过平台通道传递到原生,原生收到调用信息后执行指定操作,如需返回数据,则原生将数据再通过平台通道传递给Flutter。消息传递是异步的,这确保了用户界面在消息传递时不会被挂起。

在客户端,MethodChannel API可以发送与方法调用相对应的消息。在宿主平台上,Android的MethodChannel和iOS的FlutterMethodChannel可以接收方法调用并返回结果。这些类帮助我们用很少的代码开发平台插件。

注意:方法调用可以是反向的,即宿主作为客户端调用Dart中实现的API,例如quick_actions插件。

平台通道数据类型支持

平台通道使用标准消息编解码器对消息进行编解码,高效地进行二进制序列化与反序列化。由于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

在发送和接收值时,这些值在消息中的序列化和反序列化会自动进行。

开发Flutter插件

使用平台通道调用原生代码,下面通过一个获取电池电量的插件来介绍Flutter插件的开发流程。该插件在Dart中通过getBatteryLevel调用Android BatteryManager API和iOS device.batteryLevel API。

创建一个新的应用程序项目

首先创建一个新的应用程序。在终端中运行:flutter create batterylevel。默认情况下,模板支持使用Java编写Android代码,或使用Objective-C编写iOS代码。要使用Kotlin或Swift,请使用-i和/或-a标志,例如运行:flutter create -i swift -a kotlin batterylevel

创建Flutter平台客户端

该应用的State类拥有当前的应用状态。我们需要扩展它以保持当前的电量。首先,构建通道,使用MethodChannel调用一个方法来返回电池电量。通道的客户端和宿主通过通道构造函数中传递的通道名称进行连接。单个应用中使用的所有通道名称必须是唯一的;建议在通道名称前加一个唯一的“域名前缀”,例如samples.flutter.io/battery。

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

class _MyHomePageState extends State<MyHomePage> {
  static const platform = const MethodChannel('samples.flutter.io/battery');
  String _batteryLevel = 'Unknown battery level.';

  Future<Null> _getBatteryLevel() async {
    String batteryLevel;
    try {
      final int result = await platform.invokeMethod('getBatteryLevel');
      batteryLevel = 'Battery level at $result % .';
    } on PlatformException catch (e) {
      batteryLevel = "Failed to get battery level: '${e.message}'.";
    }

    setState(() {
      _batteryLevel = batteryLevel;
    });
  }

  @override
  Widget build(BuildContext context) {
    return new Material(
      child: new Center(
        child: new Column(
          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
          children: [
            new RaisedButton(
              child: new Text('Get Battery Level'),
              onPressed: _getBatteryLevel,
            ),
            new Text(_batteryLevel),
          ],
        ),
      ),
    );
  }
}

在接下来的部分中,会分别介绍Android和iOS端API的实现。

自定义平台通道和编解码器

除了MethodChannel,还可以使用BasicMessageChannel,它支持使用自定义消息编解码器进行基本的异步消息传递。此外,可以使用专门的BinaryCodec、StringCodec和JSONMessageCodec类,或创建自己的编解码器。

0 Answers