本文首发于微信公众号「Android开发之旅」,欢迎关注 ,获取更多技术干货
咱们在作Flutter混合开发的时候一般须要进行Flutter和Native之间的通讯。 好比Dart调用Native的相册选择图片,Native将电量、GPS信息主动传递给Dart等等。在混合开发中通讯一般有如下几种:segmentfault
第一种通讯方式咱们在讲解原生项目接入Flutter时已经讲解过,有兴趣的同窗能够移步到Flutter混合开发(一):Android项目集成Flutter模块详细指南看下。微信
Flutter与Native端之间的通讯机制是经过Platform Channel来完成。消息使用Channel在Flutter端和Native端进行传递。具体以下图所示:异步
从图中能够看出,两端之间的通讯都是双向的,并且是完成异步传递。Flutter定义了三种不一样类型的Channel:async
下面咱们就来看看这三种Channel通讯方式的具体使用和介绍。ide
BasicMessageChannel(BinaryMessenger messenger, String name, MessageCodec<T> codec)
当咱们须要接受来自Dart端发送的消息时使用setMessageHandler方法:函数
void setMessageHandler(BasicMessageChannel.MessageHandler<T> handler)
参数handler是消息处理器,配合BinaryMessenger来完成对消息的处理。它是一个接口,具体的实如今onMessage方法中:工具
public interface MessageHandler<T> { void onMessage(T message, BasicMessageChannel.Reply<T> reply); }
参数message即为Dart发送的数据, reply是用于回复消息的回调函数,提供reply.reply("")设置回复的内容。this
上面讲的是接受Dart端的消息,那么Native端主动发送消息则是使用send方法,它有两个重载方法:加密
void send(T message) void send(T message, BasicMessageChannel.Reply<T> callback)
参数message即为要发生给Dart的数据,callback回调则是用于接收Dart端收到消息后的回复信息。spa
const BasicMessageChannel(this.name, this.codec);
这里的name和codec和Android端的构造方法参数是同样的,那么是channel的名字也是惟一标识,codec是消息编解码器,两个参数在两端必须统一。
Dart端若是要接受Native端的消息则要设置setMessageHandler方法:
void setMessageHandler(Future<T> handler(T message))
参数handler为消息处理器,配合BinaryMessenger来完成对消息的处理。
经过send方法向Native端发送消息:
Future<T> send(T message)
参数message为要传递的参数。Future<T>为发送消息后等待Native回复的回调函数。
//初始化BasicMessageChannel BasicMessageChannel<String> basicMessageChannel = new BasicMessageChannel<>(flutterView, "BasicMessageChannelPlugin",StringCodec.INSTANCE); //接受消息 basicMessageChannel.setMessageHandler((message, reply) -> { mTvDart.setText(message); reply.reply("收到dart数据:接受成功"); }); //发送消息 basicMessageChannel.send(message, reply -> mTvDart.setText(reply));
//初始化BasicMessageChannel static const BasicMessageChannel<String> _basicMessageChannel = BasicMessageChannel("BasicMessageChannelPlugin", StringCodec()); // 接受消息 void handleBasicMessageChannel() { _basicMessageChannel .setMessageHandler((String message) => Future<String>(() { setState(() { showMessage = message; }); return "收到Native的消息:接受成功"; })); } //发送消息 response = await _basicMessageChannel.send(_controller.text); setState(() { showMessage = response; });
最后效果为下图,红色分割线上部分为Native页面,下部分为Flutter页面。
使用MethodChannel相关方法的参数类型及含义和BasicMessageChannel的参数含义都是相同的,下面就不一一解释了。
MethodChannel(BinaryMessenger messenger, String name) MethodChannel(BinaryMessenger messenger, String name, MethodCodec codec)
第一个构造函数会构造一个StandardMethodCodec.INSTANCE类型的MethodCodec。MethodCodec定义了两种类型:JSONMethodCodec和StandardMethodCodec。
若是想接受来自Dart端的消息则使用:
setMethodCallHandler(@Nullable MethodChannel.MethodCallHandler handler)
MethodCallHandler为接口,回调方法为:
public interface MethodCallHandler { void onMethodCall(MethodCall call, MethodChannel.Result result); }
call参数有两个成员变量,String类型的call.method表示调用的方法名,Object类型的call.arguments表示调用方法所传递的入参。result是回复此消息的回调函数提供了result.success,result.error,result.notImplemented方法调用。
发送消息主动调用Dart代码则使用invokeMethod方法
invokeMethod(@NonNull String method, @Nullable Object arguments) invokeMethod(String method, @Nullable Object arguments, Result callback)
第二个方法多了一个callback,它是用来接受Dart端收到消息后的回复信息。
public interface Result { void success(@Nullable Object result); void error(String errorCode, @Nullable String errorMessage, @Nullable Object errorDetails); void notImplemented(); }
const MethodChannel(this.name, [this.codec = const StandardMethodCodec()])
构造函数默认是使用StandardMethodCodec编解码器。
经过setMethodCallHandler方法接受来自Native的方法调用,经过invokeMethod方法调用Native端的方法。
void setMethodCallHandler(Future<dynamic> handler(MethodCall call))
Future<T> invokeMethod<T>(String method, [ dynamic arguments ])
//初始化MethodChannel MethodChannel methodChannel = new MethodChannel(flutterView, "MethodChannelPlugin"); mBtnTitle.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //调用dart端getPlatform方法 methodChannel.invokeMethod("getPlatform", null, new MethodChannel.Result() { @Override public void success(@Nullable Object result) { mTvDart.setText(result.toString()); } @Override public void error(String errorCode, @Nullable String errorMessage, @Nullable Object errorDetails) { mTvDart.setText(errorCode + "==" + errorMessage); } @Override public void notImplemented() { mTvDart.setText("未实现getPlatform方法"); } }); } }); //接受dart的调用 methodChannel.setMethodCallHandler((call, result) -> { switch (call.method) { case "getBatteryLevel": int batteryLevel = getBatteryLevel(); if (batteryLevel != -1) { result.success("电量为:" + batteryLevel); } else { result.error("1001", "调用错误", null); } break; default: result.notImplemented(); break; } });
// receive void handleMethodChannelReceive() { Future<dynamic> platformCallHandler(MethodCall call) async { switch (call.method) { case "getPlatform": return getPlatformName(); //调用success方法 // return PlatformException(code: '1002',message: "出现异常"); //调用error break; } } _methodChannel.setMethodCallHandler(platformCallHandler); // _methodChannel.setMethodCallHandler(null); //调用notImplemented } //send void handleMethodChannelSend() async { try { response = await _methodChannel.invokeMethod("getBatteryLevel"); print(response); setState(() { showMessage = response; }); } catch (e) { //捕获error和notImplemented异常 setState(() { showMessage = e.message; }); } }
当咱们在使用setMethodCallHandler接受到native的消息时,直接调用相关方法便可调用Native端的success回调。
若是直接抛异常如PlatformException,那么就调用Native端的error回调。
PlatformException(code: '1002',message: "出现异常")
若是咱们直接设置handler为null
_methodChannel.setMethodCallHandler(null);
那么就会调用Native端的notImplemented方法回调。
同理咱们在Dart端使用invokeMethod方法是,须要进行异常捕获以便于咱们接受到Native端调用的error和notImplemented方法回调。
最后效果为下图,红色分割线上部分为Native页面,下部分为Flutter页面。
EventChannel内部实现原理其实也是经过MethodChannel来完成的。
EventChannel(BinaryMessenger messenger, String name) EventChannel(BinaryMessenger messenger, String name, MethodCodec codec)
一样的,也是两个构造,默认codec为StandardMethodCodec,EventChannel和MethodChannel的codec都属于MethodCodec范畴。
经过setStreamHandler来监听Dart端发送的消息,
void setStreamHandler(EventChannel.StreamHandler handler)
其中handler是一个接口:
public interface StreamHandler { void onListen(Object args, EventChannel.EventSink eventSink); void onCancel(Object o); }
args为dart端初始化监听流的参数,eventSink设置了三个回调,分别是success、error和endofStream。分别对应Dart端的ondata、error和onDone回调。
const EventChannel(this.name, [this.codec = const StandardMethodCodec()]);
经过EventChannel初始化一个channel对象。若是从Native中接受数据须要定义一个广播流:
Stream<dynamic> receiveBroadcastStream([ dynamic arguments ])
经过调用Stream的listen方法来完成注册。
EventChannel eventChannel = new EventChannel(flutterView, "EventChannelPlugin"); eventChannel.setStreamHandler(new EventChannel.StreamHandler() { @Override public void onListen(Object arguments, EventChannel.EventSink events) { events.success(arguments.toString() + getBatteryLevel()); //events.error("111","出现错误",""); //events.endOfStream(); } @Override public void onCancel(Object arguments) { } });
//init static const EventChannel _eventChannel = EventChannel("EventChannelPlugin"); //receive void handleEventChannelReceive() { streamSubscription = _eventChannel .receiveBroadcastStream() //能够携带参数 .listen(_onData, onError: _onError, onDone: _onDone); } void _onDone() { setState(() { showMessage = "endOfStream"; }); } _onError(error) { setState(() { PlatformException platformException = error; showMessage = platformException.message; }); } void _onData(message) { setState(() { showMessage = message; }); }
经过event.success方法发送信息,dart端经过监听Stream流来获取信息。当Native端调用events.error时在Dart端的onError回调中须要将error转换为PlatformException才能获取到异常的相关信息。
最后效果为下图,红色分割线上部分为Native页面,下部分为Flutter页面。
主要是讲解了Android端和Dart的三种通讯方式。详细分析了方法构成和具体的实例使用。每一种方式都对应不一样的使用场景,你们能够按需选择,多加练习作到熟能生巧。
文中都是贴的一些代码片断,所有Demo源码已经上传到后台,关注公众号回复「混合开发」便可获取下载连接。
Flutter混合开发(一):Android项目集成Flutter模块详细指南
Flutter混合开发(二):iOS项目集成Flutter模块详细指南