Flutter与原生之间的通信依赖灵活的消息传递方式:
应用的Flutter部分通过平台通道(platform channel)将消息发送到其应用程序的所在的宿主(iOS或Android)应用(原生应用)。
宿主监听平台通道,并接收该消息。然后它会调用该平台的API,并将响应发送回客户端,即应用程序的Flutter部分。
MethodChannel // Flutter与原生方法相互调用,用于方法掉用
BasicMessageChannel // Flutter与原生相互发送消息,用于数据传递
EventChannel // 原生发送消息,Flutter接收,用于数据流通信
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.lang.BigInteger | FlutterStandardBigInteger |
double | Java.lang.Double | NSNumber numberWithDouble |
String | java.lang.String | NSString |
Unit8List | 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 |
Android调用Flutter方法:
Android:
初始化MethodChannel
//初始化,传递1. flutterView(MainActivity中getFlutter获取),2. name常量,Flutter中使用同名常量
MethodChannel methodChannel = new MethodChannel(flutterView, “testflutter”);
调用Flutter方法
通过MethodChannel调用invokeMethod("方法名","传递参数",[Flutter返回参数回调,非必须]);
Flutter:
初始化MethodChannel
static const methodChannel = const MethodChannel('testflutter');
复制代码
添加处理方法到MethodChannel
methodChannel.setMethodCallHandler(_addNativeMethod);
处理android调用的方法,根据方法名
Flutter调用Android方法:
Android:
初始化MethodChannel,并添加自定义plugin
MethodChannel methodChannel = new MethodChannel(flutterView, METHOD_CHANNEL);
methodChannel.setMethodCallHandler(plugin);
自定义的plugin实现MethodChannel.MethodCallHandler接口的onMethodCall方法
@Override
public void onMethodCall(MethodCall methodCall, MethodChannel.Result result) {
// Flutter调用Native的方法
if (methodCall.method.equals("getBatteryLevel")) {
int batteryLevel = getBatteryLevel();
if (batteryLevel != -1) {
result.success(batteryLevel);
} else {
result.error("UNAVALIABLE", "battery level unavaliable", null);
}
} else {
result.notImplemented();
}
}
//在onMethodCall中监听Flutter调用什么名字的方法(此处getBatterLevel),通过result返回方法的执行结果。
Flutter:
初始化MethodChannel
static const methodChannel = const MethodChannel('testflutter');
复制代码
调用Android的方法,接收返回数据
//方法通道的方法是异步的
Future _getBatteryLevel() async {
String batteryLevel;
try {
final int result = await methodChannel.invokeMethod('getBatteryLevel');
batteryLevel = 'Battery level $result .';
} on PlatformException catch (e) {
batteryLevel = 'Battery level unknown ${e.message}';
}
setState(() {
_batteryLevel = batteryLevel;
});
}
Android给Flutter发消息:
Android:
初始化BasicMethodChannel
BasicMessageChannel messageChannel =
new BasicMessageChannel<>(flutterView,
"messageChannel", StandardMessageCodec.INSTANCE);
复制代码
调用发送消息的方法
private void sendMessageToFlutter() {
if (this.mBasicMessageChannel != null) {
this.mBasicMessageChannel.send("Message From Native");
}
}
Flutter:
初始化BasicMessageChannel
static const basicMessageChannel = BasicMessageChannel('messageChannel', StandardMessageCodec());
复制代码
添加接收信息处理方法
void _listenMessageFromNative() {
basicMessageChannel.setMessageHandler(_receiveMessageFromNative);
}
处理接收的数据
//Flutter接收Native发来的消息
Future _receiveMessageFromNative(Object result) async {
setState(() {
_messageFromNative = result.toString();
});
}
Flutter给Android发消息:
Android:
初始化BasicMessageChannel并添加plugin给handler
BasicMessageChannel messageChannel = new BasicMessageChannel<>(flutterView, "messageChannel", StandardMessageCodec.INSTANCE);
messageChannel.setMessageHandler(plugin);
plugin实现BasicMessageChannel.MessageHandler接口的onMessage方法,处理接收到的信息
@Override
public void onMessage(Object o, BasicMessageChannel.Reply reply) {
Toast.makeText(mContext, o.toString(), Toast.LENGTH_LONG).show();
reply.reply(o.toString()+" back from native");
}
//reply返回数据给Flutter
Flutter:
初始化BasicMessageChannel
static const basicMessageChannel =
BasicMessageChannel('messageChannel', StandardMessageCodec());
发送消息给Android并接收返回数据
Android:
初始化EventChannel并添加plugin给handler
EventChannel eventChannel = new EventChannel(flutterView, EVENT_CHANNEL);
eventChannel.setStreamHandler(plugin);
plugin实现EventChannel.StreamHandler接口及onListen、onCancel方法
在onListen中通过EventChannel.EventShink的实例发消息给Flutter
@Override
public void onListen(Object o, EventChannel.EventSink eventSink) {
BroadcastReceiver chargingBroadcastReceiver = createChargingBroadcaseReceiver(eventSink);
mContext.registerReceiver(chargingBroadcastReceiver,new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
}
@Override
public void onCancel(Object o) {
}
private BroadcastReceiver createChargingBroadcaseReceiver(EventChannel.EventSink eventSink) {
return new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
if (status == BatteryManager.BATTERY_STATUS_UNKNOWN) {
eventSink.error("UNAVALIABLE", "charging status is unavailable", null);
} else {
boolean isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING;
eventSink.success(isCharging ? "charging" : "disCharging");
}
}
};
}
Flutter:
初始化EventChannel
static const _eventChannel = const EventChannel('charging');
添加接收数据方法
void listenNativeEvent() {
_eventChannel.receiveBroadcastStream().listen(_onEvent, onError: _onError);
}
//接收返回的数据
void _onEvent(Object object) {
String s = "Battery is ${object == 'charging' ? '' : 'dis'}Charging";
setState(() {
_batteryStatus = s;
});
}
Android:
自定义View,继承自PlatformView
实现PlatformViewFactory
public class TextViewFactory extends PlatformViewFactory {
private MessageCodec
注册View给Flutter使用
registrar.platformViewRegistry().registerViewFactory("TextView", new TextViewFactory(new StandardMessageCodec()));
//起名叫TextView,给Flutter用做viewType
Flutter:
使用桥接的View
AndroidView(
viewType: 'TextView',
creationParams: {'text': 'TTTeeeXXXttt'},
creationParamsCodec: new StandardMessageCodec(),
),//其中creationParams,creationParamsCodec必须同时存在或不存在
以上,正文结束;
官方还有一些其他建议
Hosted packages(发布到pub.dartlang.org)
$flutter packages pub publish --dry-run
$flutter packages pub publish
复制代码
在yaml文件和其他dependencies一样使用。
Git packages(远端)
代码上传到Git,并打一个tag
yaml文件引用
dependencies:
flutter_remote_package:
git:
url: git@gitlab....
ref: 0.0.1 //可以是commit、branch、tag
本地
在Flutter App根目录下创建plugins文件夹,把插件移动到plugins下。
以上限于在创建工程的时候,使用的是plugins创建的,有时候会在自己的Android或iOS工程内部开发,就不这么方便分离发布了。
dependencies:flutter_plugin_batterylevel:
path: plugins/flutter_plugin_batterylevel
dependencies:
flutter_plugin_batterylevel:
path: plugins/flutter_plugin_batterylevel
有时候需要到UI thread执行channelMethod,在Android上需要post一个Runnable到Android UI线程。
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run(){
// call the desired channel message here.
}
})
所谓的“传View”的本质是传递纹理ID,我们只需要明白Flutter是通过Presentation实现了外接纹理,在创建Presentation时,传入FlutterView对应的Context和创建出来的一个虚拟显示屏对象,使得Flutter可以直接通过ID找到并使用Native创建出来的纹理数据。
事件处理,从Native传递到Flutter这一阶段Flutter按照自己的规则处理事件,如果AndroidView获取到了事件,事件会被封装成相应的Native端的事件通过方法通道传回Native,Native再处理事件。
对于可能出现的滑动时间冲突,可以参考官方注释:
/// For example, with the following setup vertical drags will not be dispatched to the Android view as the vertical drag gesture is claimed by the parent [GestureDetector].
///
/// GestureDetector(
/// onVerticalDragStart: (DragStartDetails d) {},
/// child: AndroidView(
/// viewType: 'webview',
/// gestureRecognizers: [],
/// ),
/// )
///
/// To get the [AndroidView] to claim the vertical drag gestures we can pass a vertical drag gesture recognizer in [gestureRecognizers] e.g:
///
/// GestureDetector(
/// onVerticalDragStart: (DragStartDetails d) {},
/// child: SizedBox(
/// width: 200.0,
/// height: 100.0,
/// child: AndroidView(
/// viewType: 'webview',
/// gestureRecognizers: [new VerticalDragGestureRecognizer()],
/// ),
/// ),
/// )
https://github.com/damengzai/flutter-test
喜欢 就关注吧,欢迎投稿!