Flutter 做为混合开发,跟native端作一些交互在所不免,好比说调用原生系统传感器、原生端的网络框架进行数据请求就会用到 Flutter 调用android 及android 原生调用 Flutter的方法,这里就涉及到Platform Channels(平台通道)android
Flutter 经过Channel 与客户端之间传递消息,如图:json
图中就是经过MethodChannel的方式实现Flutter 与客户端之间的消息传递。MethodChannel是Platform Channels中的一种,Flutter有三种通讯类型:bash
BasicMessageChannel:用于传递字符串和半结构化的信息
MethodChannel:用于传递方法调用(method invocation)一般用来调用native中某个方法
EventChannel: 用于数据流(event streams)的通讯。有监听功能,好比电量变化以后直接推送数据给flutter端。
复制代码
为了保证UI的响应,经过Platform Channels传递的消息都是异步的。网络
更多关于channel原理能够去看这篇文章:channel原理篇并发
首先定义一个获取手机电量方法app
private int getBatteryLevel() {
return 90;
}
复制代码
这函数是要给Flutter 调用的方法,此时就须要经过 MethodChannel
来创建这个通道了。框架
首先新增一个初始化 MethodChannel
的方法异步
private String METHOD_CHANNEL = "common.flutter/battery";
private String GET_BATTERY_LEVEL = "getBatteryLevel";
private MethodChannel methodChannel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
GeneratedPluginRegistrant.registerWith(this);
initMethodChannel();
getFlutterView().postDelayed(() ->
methodChannel.invokeMethod("get_message", null, new MethodChannel.Result() {
@Override
public void success(@Nullable Object o) {
Log.d(TAG, "get_message:" + o.toString());
}
@Override
public void error(String s, @Nullable String s1, @Nullable Object o) {
}
@Override
public void notImplemented() {
}
}), 5000);
}
private void initMethodChannel() {
methodChannel = new MethodChannel(getFlutterView(), METHOD_CHANNEL);
methodChannel.setMethodCallHandler(
(methodCall, result) -> {
if (methodCall.method.equals(GET_BATTERY_LEVEL)) {
int batteryLevel = getBatteryLevel();
if (batteryLevel != -1) {
result.success(batteryLevel);
} else {
result.error("UNAVAILABLE", "Battery level not available.", null);
}
} else {
result.notImplemented();
}
});
}
private int getBatteryLevel() {
return 90;
}
复制代码
METHOD_CHANNEL
用于和flutter交互的标识,因为通常状况下会有多个channel,在app里面须要保持惟一性async
MethodChannel
都是保存在以通道名为Key的Map中。因此要是设了两个名字同样的channel,只有后设置的那个会生效。ide
onMethodCall
有两个参数,onMethodCall
里包含要调用的方法名称和参数。Result是给Flutter的返回值。方法名是客户端与Flutter统一设定。经过if/switch语句判断 MethodCall.method
来区分不一样的方法,在咱们的例子里面咱们只会处理名为“getBatteryLevel”的调用。在调用本地方法获取到电量之后经过 result.success(batteryLevel)
调用把电量值返回给Flutter。
直接先看一下Flutter端的代码
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
static const platform = const MethodChannel('common.flutter/battery');
void _incrementCounter() {
setState(() {
_counter++;
_getBatteryLevel();
});
}
@override
Widget build(BuildContext context) {
platform.setMethodCallHandler(platformCallHandler);
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.display1,
),
Text('$_batteryLevel'),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
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;
});
}
//客户端调用
Future<dynamic> platformCallHandler(MethodCall call) async {
switch (call.method) {
case "get_message":
return "Hello from Flutter";
break;
}
}
}
复制代码
上面代码解析:
首先,定义一个常量result.success(platform)
,和Android客户端定义的channel一致;
接下来定义一个 result.success(_getBatteryLevel())
方法,用来调用Android 端的方法,result.success(final int result = await platform.invokeMethod('getBatteryLevel');)
这行代码就是经过通道来调用Native(Android)方法了。由于MethodChannel是异步调用的,因此这里必需要使用await关键字。
在上面Android代码中咱们把获取到的电量经过result.success(batteryLevel);
返回给Flutter。这里await表达式执行完成之后电量就直接赋值给result变量了。而后经过result.success(setState);
去改变Text显示值。到这里为止,是经过Flutter端调用原生客户端方法。
MethodChannel
实际上是一个能够双向调用的方法,在上面的代码中,其实咱们也体现了,经过原生客户端调用Flutter的方法。
在原生端经过 methodChannel.invokeMethod
的方法调用
methodChannel.invokeMethod("get_message", null, new MethodChannel.Result() {
@Override
public void success(@Nullable Object o) {
Log.d(TAG, "get_message:" + o.toString());
}
@Override
public void error(String s, @Nullable String s1, @Nullable Object o) {
}
@Override
public void notImplemented() {
}
});
复制代码
在Flutter端就须要给MethodChannel
设置一个MethodCallHandler
static const platform = const MethodChannel('common.flutter/battery');
platform.setMethodCallHandler(platformCallHandler);
Future<dynamic> platformCallHandler(MethodCall call) async {
switch (call.method) {
case "get_message":
return "Hello from Flutter";
break;
}
}
复制代码
以上就是MethodChannel
的相关用法了。
将数据推送给Flutter端,相似咱们经常使用的推送功能,有须要就推送给Flutter端,是否须要去处理这个推送由Flutter那边决定。相对于MethodChannel
是主动获取,EventChannel
则是被动推送。
private String EVENT_CHANNEL = "common.flutter/message";
private int count = 0;
private Timer timer;
private void initEventChannel() {
new EventChannel(getFlutterView(), EVENT_CHANNEL).setStreamHandler(new EventChannel.StreamHandler() {
@Override
public void onListen(Object arguments, EventChannel.EventSink events) {
timer.schedule(new TimerTask() {
@Override
public void run() {
if (count < 10) {
count++;
events.success("当前时间:" + System.currentTimeMillis());
} else {
timer.cancel();
}
}
}, 1000, 1000);
}
@Override
public void onCancel(Object o) {
}
});
}
复制代码
在上面的代码中,咱们作了一个定时器,每秒向Flutter推送一个消息,告诉Flutter咱们当前时间。为了防止一直倒计时,我这边作了个计数,超过10次就中止发送。
String message = "not message";
static const eventChannel = const EventChannel('common.flutter/message');
@override
void initState() {
super.initState();
eventChannel.receiveBroadcastStream().listen(_onEvent, onError: _onError);
}
void _onEvent(Object event) {
setState(() {
message =
"message: $event";
});
}
void _onError(Object error) {
setState(() {
message = 'message: unknown.';
});
}
复制代码
上面的代码就是Flutter端接收原生客户端数据,经过_onEvent
来接收数据,将数据显示Text
。这个实现相对简单,若是要达到业务分类,须要将数据封装成json,经过json数据包装一些对应业务标识和数据来作区分。
BasicMessageChannel (主要是传递字符串和一些半结构体的数据)
private void initBasicMessageChannel() {
BasicMessageChannel<Object> basicMessageChannel = new BasicMessageChannel<>(getFlutterView(), BASIC_CHANNEL, StandardMessageCodec.INSTANCE);
//主动发送消息到flutter 并接收flutter消息回复
basicMessageChannel.send("send basic message", (object)-> {
Log.e(TAG, "receive reply msg from flutter:" + object.toString());
});
//接收flutter消息 并发送回复
basicMessageChannel.setMessageHandler((object, reply)-> {
Log.e(TAG, "receive msg from flutter:" + object.toString());
reply.reply("reply:got your message");
});
}
复制代码
static const basicChannel = const BasicMessageChannel('common.flutter/basic', StandardMessageCodec());
//发送消息到原生客户端 而且接收到原生客户端的回复
Future<String> sendMessage() async {
String reply = await basicChannel.send('this is flutter');
print("receive reply msg from native:$reply");
return reply;
}
//接收原生消息 并发送回复
void receiveMessage() async {
basicChannel.setMessageHandler((msg) async {
print("receive from Android:$msg");
return "get native message";
});
复制代码
上面例子中用到的编解码器为StandardMessageCodec ,例子中通讯都是String,用StringCodec也能够。
以上就是Flutter提供三种platform和dart端的消息通讯方式。