推荐阅读
Flutter(二)Android集成Flutter项目并实现跳转到 Flutter 界面
目录
前言
上一篇中,学习了 Android 原生集成 Flutter 并实现了页面跳转,本篇将要学习Flutter与Activity之间的数据交互。
一、Platform Channel
Flutter 定义了三种不同的 Channel;但无论是传递方法还是传递事件,其本质上都是数据的传递;
- MethodChannel:用于传递方法调用。
- EventChannel:用于数据流的通信;用于Flutter和平台端进行事件监听、取消等。
- BasicMessageChannel:用于传递字符串和半结构化的信息;用于Flutter和平台端进行消息数据交换时。
每种 Channel 均包含三个成员变量;
- name:代表 Channel 唯一标识符,Channel 可以包含多个,但 name 为唯一的;
- messager:代表消息发送与接收的工具 BinaryMessenger;
- codec:代表消息的编解码器;
这里我,主要介绍一下MethodChannel的使用,它也是我们开发中最常用的。
二、MethodChannel
在Flutter中调用MethodChannel 的 invokeMethod 方法实现跳转及参数传递到原生Activity页面。原生Activity页面调用MethodChannel的setMethodCallHandler方法实现方法回调,接受Flutter传递的消息。
1、Android 代码
Android端创建MethodChannel需要传递2个参数。第1个是BinaryMessenger接口,代表消息信使,是消息发送与接收的工具;第二个参数是name,表示
Channel的名称,定义了final类型保证唯一,与Flutter的MethodChannel呼应上。
private static final String CHANNEL_NATIVE = "com.example.flutter/native";
private FlutterEngine flutterEngine;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_takeout);
flutterEngine = new FlutterEngine(this);
flutterEngine.getNavigationChannel().setInitialRoute("route1");
flutterEngine.getDartExecutor().executeDartEntrypoint(
DartExecutor.DartEntrypoint.createDefault()
);
flutterView = new FlutterView(this);
FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT);
FrameLayout flContainer = findViewById(R.id.flutter_view);
flContainer.addView(flutterView, lp);
if (flutterEngine!=null){
flutterView.attachToFlutterEngine(flutterEngine);
}
MethodChannel nativeChannel = new MethodChannel(flutterEngine.getDartExecutor()
.getBinaryMessenger(), CHANNEL_NATIVE);
nativeChannel.setMethodCallHandler(new MethodChannel.MethodCallHandler() {
@Override
public void onMethodCall(MethodCall methodCall, MethodChannel.Result result) {
switch (methodCall.method) {
case "jumpToNative": // 跳转原生页面
if (methodCall.arguments != null) {
ToastUtil.show(TAG, methodCall.argument("message"));
} else {
ToastUtil.show(TAG,"回调参数为空");
}
startActivity(new Intent(TAG, MainPageActivity.class));
result.success("Activity -> Flutter 接收回调的返回值成功");
break;
default:
result.notImplemented();
break;
}
}
});
}
@Override
protected void onResume() {
super.onResume();
if (flutterEngine!=null){
flutterEngine.getLifecycleChannel().appIsResumed();
}
}
@Override
protected void onPause() {
super.onPause();
if (flutterEngine!=null){
flutterEngine.getLifecycleChannel().appIsInactive();
}
}
@Override
protected void onStop() {
super.onStop();
if (flutterEngine!=null){
flutterEngine.getLifecycleChannel().appIsPaused();
}
}
2、Flutter代码
在Flutter端同样需要定义一个MethodChannel,使用MethodChannel需要引入services.dart
包,Channel名称要和Android端定义的相同。点击按钮执行调用invokeMethod(),
该方法有2个参数。第1个是呼应Android端的methodCall.method
获取到的方法名。第2个是方法的参数,在Android端通过methodCall.arguments()/
argument()
获取到所有参数或指定名称的参数。
class _MyHomePageState extends State<MyHomePage> {
static const nativeChannel = const MethodChannel('com.example.flutter/native');
String _result = '';
Future<void> _incrementCounter() async {
Map<String, dynamic> result = {'message': '我从Flutter页面回来了'};
try {
_result = await nativeChannel.invokeMethod('jumpToNative', result);
} on PlatformException catch (e) {
_result = "Failed: '${e.message}'.";
}
setState(() {});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text(widget.title), ),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('传递结果:$_result',),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
三、Flutter返回上一页
原生Activity中嵌套FlutterView页面,类似于嵌套一个WebView,每个Flutter页面对应着一个route路由地址,就相当于Url链接地址。我们知道WebView有goBack()方法返回上一个网页;那么,在Flutter页面如何实现返回上一页呢。
实现思路如下:
Flutter调用
Navigator.canPop(context)
判断是否可以返回,true 就调用Navigator.of(context).pop()
返回,false 则说明当前已经是第一个页面了,就返回到Activity。
首先,在Flutter页面中添加一个按钮,点击按钮跳转到SecondPage页面。
RaisedButton(
child: Text('跳转Flutter页面'),
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(builder: (context) {
return SecondPage();
}));
}
),
然后,定义MethodChannel和MethodCallHandler回调,调用Navigator.canPop(context) 进行
判断,是Flutter返回上一页还是回到Activity原生页面。
static const nativeChannel =const MethodChannel('com.example.flutter/native');
static const flutterChannel =const MethodChannel('com.example.flutter/flutter');
@override
void initState() {
super.initState();
Future<dynamic> handler(MethodCall call) async {
switch (call.method) {
case 'goBack':
if (Navigator.canPop(context)) { // 返回上一页
Navigator.of(context).pop();
} else {
nativeChannel.invokeMethod('goBack');
}
break;
}
}
flutterChannel.setMethodCallHandler(handler);
}
在Android端,重写onBackPressed()
方法,将返回键的事件处理交给Flutter端。
private static final String CHANNEL_FLUTTER = "com.example.flutter/flutter";
@Override
public void onBackPressed() {
MethodChannel flutterChannel = new MethodChannel(flutterView, CHANNEL_FLUTTER);
flutterChannel.invokeMethod("goBack", null);
}
最后,编写原生端的MethodCallHandler回调,如果当前Flutter页面是第一个时调用该方法直接finish掉Activity。
nativeChannel.setMethodCallHandler(new MethodChannel.MethodCallHandler() {
@Override
public void onMethodCall(MethodCall methodCall, MethodChannel.Result result) {
switch (methodCall.method) {
case "goBack":
// 返回上一页
finish();
break;
default:
result.notImplemented();
break;
}
参考地址: