Flutter(七)Flutter与Android通信
因为笔者本身主要从事是Android开发,所以很多角度都是作为一个Android开发者学习Flutter的角度出发,IOS或者H5的开发同学可以选择性阅读
目录
前言
用Flutter这样的跨平台技术进行商业级项目开发时,几乎不可避免的需要和Native进行通信,比如不同平台的底层服务如电量变化、网络连接变化、陀螺仪、传感器等等都有各自不同的实现,以及编译期的一些配置,比如包名、版本号、第三方依赖APPKEY等都需要通过原生的方法去获取。所以学习Native和Flutter的通信方式是非常有必要的
Native和Flutter之间可以通过Platform Channels APIs进行通信,Flutter定义了三种不同类型的Channel
:
-
MethodChannel
:用于传递方法调用(method invocation),一次性通信 -
BasicMessageChannel
:用于传递字符串和半结构化的消息,持续通信可回复 -
EventChannel
: 用于事件流的发送(event streams),持续通信不可回复
MethodChannel通信
MethodChannel
是最常用的Native和Flutter的通信方式,主要用于Flutter调用Native端方法,如调用Native相机功能
为了便于理解,这里我介绍一个前两天在公司项目中实际用到MethodChannel
的场景。基本现在Android APP都会涉及到多渠道打包问题,针对不同的渠道,我们可能会在编译脚本(build文件)中进行一些不同的配置。但是Flutter如何才能拿到Android Gradle中的配置信息呢?其实很简单,也就是我们可以先通过Android代码拿到BuildConfig中的数据,再通过Flutter与Android进行通信拿到数据。这种一次性的调用Android中代码的情况就需要用到MethodChannel
Android端
创建MethodChannel
,通过setMethodCallHandler
接收Flutter端的方法调用
//1.创建android端的MethodChannel
MethodChannel channel = new MethodChannel(messenger, "com.geekholt.hybird/TestMethodChannel");
//2.通过setMethodCallHandler响应Flutter端的方法调用
channel.setMethodCallHandler(new MethodChannel.MethodCallHandler() {
@Override
public void onMethodCall(MethodCall call, MethodChannel.Result result) {
switch (call.method) {
case "getUmAppKey":
//3.返回结果给Flutter端
result.success(BuildConfig.UMENG_APP_KEY);
break;
default:
result.notImplemented();
}
}
});
注:messenger
需要在FlutterActivity
中使用getFlutterEngine().getDartExecutor()
获取
Flutter端
Flutter端同样也有MethodChannel
,可以通过类似方法调用的方式,调用Native层的方法,并拿到返回值
//1.创建Flutter端的MethodChannel
MethodChannel _methodChannel = MethodChannel('com.geekholt.hybird/TestMethodChannel');
//2.通过invokeMethod调用Native方法,拿到返回值
void _getChannel(value) async {
String appKey = await _methodChannel.invokeMethod('getUmAppKey', value);
print("appKey:" + appKey);
}
这里要注意两点:
- ChannelName要与Native端保持一致(即
com.geekholt.hybird/TestMethodChannel
) - MethodName要与Native端保持一致(即
getUmAppKey
)
BasicMessageChannel通信
BasicMessageChannel
用于Native和Flutter互相发送消息,一方给另一方发送消息,收到消息之后给出回复
Android给Flutter发送消息
Android端
创建一个BasicMessageChannel
,通过send
方法发送消息
//1.创建android端的BasicMessageChannel
BasicMessageChannel<String> messageChannel = new BasicMessageChannel<>(messenger, "com.geekholt.hybird/TestBasicMessageChannel", StringCodec.INSTANCE);
//2.向Flutter端发送消息
messageChannel.send(message, new BasicMessageChannel.Reply<String>() {
@Override
public void reply(String reply) {
Log.i(TAG, "收到Flutter的消息回复:" + message);
}
});
发送的消息会以二进制的形式进行处理,所以要针对不同类型的数据进行二进制编码
编码类型 | 消息格式 |
---|---|
BinaryCodec | 发送二进制消息时 |
JSONMessageCodec | 发送Json格式消息时 |
StandardMessageCodec | 发送基本型数据时 |
StringCodec | 发送String类型消息时 |
Flutter端
Flutter端同样也有BasicMessageChannel
,通过setMessageHandler
接收并回复消息
//1.创建Flutter端的BasicMessageChannel
BasicMessageChannel<String> _basicMessageChannel = BasicMessageChannel('com.geekholt.hybird/TestBasicMessageChannel', StringCodec());
//2.接收来自Native的消息,并向Native回复
_basicMessageChannel.setMessageHandler((String message) => Future<String>(() {
return "收到Native的消息:" + message;
}));
Flutter给Android发送消息
Flutter端
在Flutter端我们也可以通过send
方法向Native发送消息,方法的返回值就是Native端的消息回复
注意flutter和Native的通信都是异步的
void _sendMessage(value) async {
String response = await _basicMessageChannel.send(value);
print("收到Native的消息回复:"+ response);
}
Android端
android端通过setMessageHandler
设置消息处理器,处理来自Dart的消息,收到消息后通过reply
进行回复
messageChannel.setMessageHandler(new BasicMessageChannel.MessageHandler<String>() {
@Override
public void onMessage(String message, BasicMessageChannel.Reply<String> reply) {
//通过reply进行回复
reply.reply("BasicMessageChannel收到:" + message);
}
});
EventChannel通信
EventChannel
用于从Native向Flutter发送通知事件,例如Flutter通过其监听Android的重力感应变化等。与MethodChannel
不同,EventChannel
是Native到Flutter的单向调用,调用是一对多的,类似Android的BrodcastReceiver
Android端
创建一个EventChannel
,在StreamHandler#onLister
回调中获取EventSink
引用并保存,当重力感应发送变化时,通过eventSink.success
向Flutter端发送消息
private EventChannel.EventSink eventSink;
void registerWith(BinaryMessenger messenger) {
//1.创建Android端的EventChannel
EventChannel eventChannel = new EventChannel(messenger, "com.geekholt.hybird/TestEventChannel");
//2.在StreamHandler#onLister回调中获取EventSink引用并保存
eventChannel.setStreamHandler(new EventChannel.StreamHandler() {
@Override
public void onListen(Object arguments, EventChannel.EventSink events) {
eventSink = events;
}
@Override
public void onCancel(Object arguments) {
eventSink = null;
}
});
}
//3.调用eventSink.success向Flutter端发送消息
void send(Object params) {
if (eventSink != null) {
eventSink.success(params);
}
}
Flutter端
Flutter端接收消息如下所示,要注意使用EventChannel
时需要在页面销毁时取消监听,防止内存泄漏
//1.创建Flutter端EventChannel
EventChannel _eventChannelPlugin = EventChannel('com.geekholt.hybird/TestEventChannel');
//2.EventChannel#receiveBroadcastStream注册listener,建立监听
StreamSubscription _streamSubscription = _eventChannelPlugin
.receiveBroadcastStream()
.listen(_onEventSuccess, onError: _onEventError);
//3.成功和错误回调
void _onEventSuccess(message) {
print(message);
}
void _onEventError(error) {
print(error);
}
//4.注意:页面销毁时需要取消监听,防止内存泄漏
@override
void dispose() {
if (_streamSubscription != null) {
_streamSubscription.cancel();
_streamSubscription = null;
}
super.dispose();
}