一、前言 今天学习插件开发, Flutter 使用一个灵活的系统,允许调用特定平台(iOS/Android)的API,无论在 Android 上的 Java 或者 Kotlin 代码中,还是 iOS 上的 Object-C 或者 Swift 代码中均可使用。 Flutter 平台特定的 API 支持不依赖于代码生成,而是依...
一、前言
今天学习插件开发,Flutter
使用一个灵活的系统,允许调用特定平台(iOS/Android)的API,无论在Android
上的Java
或者Kotlin
代码中,还是iOS
上的Object-C
或者Swift
代码中均可使用。Flutter
平台特定的API
支持不依赖于代码生成,而是依赖于灵活的消息传递方式:
- 应用的
Flutter
部分通过平台通道(platform channel)将消息发送到应用程序得所在宿主(iOS或Android)。 - 宿主监听的平台通道,并接受该消息,然后它会调用特定于该平台的API(使用原生编程语言)-并响应发送客户端(即应用程序的
Flutter
部分)。
二、插件实例
1.插件的基本原理
要使用和创建一个Flutter
插件,得要首先知道平台通道在客户端(Flutter UI)和宿主(平台)之间传递消息,用官方的图,下图:
上面就是平台通道的结构大致描述,使用MethodChannel
在Flutter客户端
和主机(iOS/Android)
之间传递消息,消息和响应都是异步传递的,这样确保用户界面(UI)保持响应,在Flutter客户端
,Flutter
通过MethodChannel
类发送与方法调用相对应的消息。在平台上,Android
上通过MethodChannel
类接收方法调用并发送结果,iOS
上则可以通过FlutterMethodChannel
类接收方法调用并发送结果。这些类允许开发者开发一个平台插件,在上图可以发现,箭头是双向的,也就是方法调用也可以朝反方向发送,简而言之:可以从Flutter
调用Android/iOS
的代码,也可以从Android/iOS
调用Flutter
。标准平台通道使用的是标准消息解码器,支持简单高效的将JSON
格式的值二进制序列化,如布尔值、数字、字符串、字节缓冲区以及这些数据的列表和映射,发送和接收值会自动对这些值进行序列化和反序列化,下面表格列出展示平台端如何接收Dart
,反过来也是一样。
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: |
int, if 64 bits not enough | 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 |
2.简单例子1-返回数值
了解原理,下面简单实现平台和客户端传递数据的Flutter
平台插件。
2.1.Flutter平台客户端
首先,需要创建Flutter
平台客户端,构建通道,使用具有基本传递数据功能的单平台方法MethodChannel
,通道的客户端和宿主通过通道构造函数中传递的通道名称进行连接,单个应用中使用的所有通道名称必须是唯一的,官方建议是通道名称前加一个唯一的“域名前缀”,例如samoles.flutter.io/battery
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class _PluginTestState extends State<PluginTest> {
//创建通道名称 必须唯一
static const platform = const MethodChannel('sample.flutter.io/data');
}
复制代码
下面在MethodChannel
上调用一个方法,指定通过String
标识符data
调用的具体方法。如果当前平台不支持API
那么调用会失败,因此需要将invokeMethod
调用包含在try-catch
语句中,返回的数值来更新_data
:
class _PluginTestState extends State<PluginTest> {
//创建通道名称 必须唯一
static const platform = const MethodChannel('sample.flutter.io/data');
String _data;
Future<Null> _returndata() async{
String data;
try{
//1.invokeMethod('xxxx') xxx可以自己命名
final int resultData = await platform.invokeMethod('data');
data = "平台返回数值:$resultData";
}catch(e){
data = "错误:${e.message}";
}
//状态更新
setState(() {
_data = data;
});
}
}
复制代码
主界面添加一个返回数值的文本,和一个浮动按钮:
class _PluginTestState extends State<PluginTest> {
@override
Widget build(BuildContext context) {
return new Scaffold(
//appBar
appBar: AppBar(
title: Text("插件例子"),
//标题居中
centerTitle: true,
),
body:new Center(
child: Text("$_data"),
),
floatingActionButton : FloatingActionButton(
onPressed: _returndata,
tooltip: "获取平台返回的值",
child: new Icon(Icons.audiotrack)
),
);
}
}
复制代码
2.2.使用Java添加Android平台特定的实现
首先在Android Studio打开Flutter
应用的Android
部分:
- Android Studio 选择
File > Open
- 定位到自己的项目根目录,然后选择里面的
android文件夹
,点击OK 如下:
3. 在java
目录下打开MainActivity.java
,我打开项目编译报错,没管。 下面,在onCreate
里创建MethodChannel并设置一个MethodCallHandler
。确保使用在Flutter客户端
使用的通道名称相同:
public class MainActivity extends FlutterActivity {
//1.通道名称
private static final String CHANNEL = "sample.flutter.io/data";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//2.创建MethodChannel 并且设置MethodCallHandler
new MethodChannel(getFlutterView(), CHANNEL).setMethodCallHandler(new MethodChannel.MethodCallHandler(){
@Override
public void onMethodCall(MethodCall call, MethodChannel.Result result){
}
});
GeneratedPluginRegistrant.registerWith(this);
}
}
复制代码
编写Java代码,用于调用Android
上的随机函数,和在Android
项目上编写代码完全一样,在MainActivity
方法添加下面方法:
//返回特定的数值
private int getData() {
return 7;
}
复制代码
最后,在完成之前添加的onMethodCall
方法后,还需要处理一个平台方法data
,所以需要在call
参数中测试它,这个方法里面的逻辑只是调用getData
这个方法,并使用response
参数返回成功和错误情况的响应,如果调用未知的方法,会报告错误信息:
new MethodChannel(getFlutterView(), CHANNEL).setMethodCallHandler(new MethodChannel.MethodCallHandler() {
@Override
public void onMethodCall(MethodCall call, MethodChannel.Result result) {
//3.处理一个平台方法data 和在平台上invokeMethod(xxxx)对应
if (call.method.equals("data")) {
int data = getData();
result.success(data);
} else {
result.notImplemented();
}
}
});
复制代码
现在就可以运行这应用程序,点击按钮,就能获取Android
主机返回的数值7
,效果图如下:
查看更多详细内容