flutter踩坑记录目录
flutter踩坑记录(一)--项目准备阶段
flutter踩坑记录(三)-- 项目打包
通过上一篇的踩坑记录(一),我相信你此时已经集成flutter模块到原生项目中,也迫不及待去使用flutter和体验flutter与原生的交互(目前大多数使用场景还是要与原生集成混合开发的)
Android
中创建Flutter
UI
Flutter
提供两种方法引入,一个是View
,一个是Fragment
,(目前使用我使用的view方式引用,这种方式也更灵活方法,有一个viewGroup载体就可加载flutterView)
在oncreat中添加view(下面提到的rootLayout即为布局内一个空的ConstraintLayout的viewId,使用kotlin只需要有id就可使用view)
布局文件
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="invisible"
android:id="@+id/rootLayout"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
activity中代码文件
val flutterView = Flutter.createView(this, lifecycle, "home_page")
val layoutParams = ConstraintLayout.LayoutParams(ConstraintLayout.LayoutParams.MATCH_PARENT,
ConstraintLayout.LayoutParams.MATCH_PARENT)
rootLayout.addView(flutterView, layoutParams)
createView方法说明:
第二个参数是Lifecycle
对象,第三个参数是route(flutter页面跳转路径)
,这个参数Flutter
端可以通过window.defaultRouteName
获取
此时原生端加载flutterView载体已经搭建好,我们去看下flutter部分
dart代码的编写
import 'package:flutter/material.dart';
import 'list.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
routes: {
"home_page": (context) => MyHomePage(),
},
);
}
}
此时已经实现了原生页面中加入了flutterView的页面显示,可对于我们来说还远远不够,更重要的原生与flutter交互应该是大部分原生开发者更关心的方面
参考链接
Andriod 原生与flutter交互
google为原生与flutter交互创建了channel渠道来实现,主要有3种,message,method,engine,目前常使用的是前2种
method channel 实现
原生activity内代码:
首先我们先定义channel 名称
private val CHANNEL = "demo.plugin"
method channel 交互使用主要是使用了回调方式,这一点和原生与h5交互很类似,主要可用于flutter调用原生信息,调用方法等
//从flutter中调回原生页面
MethodChannel(flutterView, CHANNEL).setMethodCallHandler { call, result ->
when {
call.method == "interaction" -> {
// val intent = Intent(this@FlutterTestPageActivity,
// PersonalSettingActivity::class.java)
// startActivity(intent)
val id = call.arguments as Int
ToastUtil.show(mContext!!,"收到的id为$id")
}
call.method == "methodId" -> result.success(12)
else -> result.notImplemented()
}
}
flutter部分大部分代码实现
class _MyHomePageState extends State<MyHomePage> {
//原生与flutter部分渠道名一定要统一
final demoPlugin = const MethodChannel('demo.plugin');
num id = 0;
@override
void initState() {
super.initState();
getMethodId();
}
getMethodId() async {
var id = await demoPlugin.invokeMethod('methodId');
setState(() {
this.id = id;
});
}
widget显示部分
Text('需要的id为${this.id}'),
Container(
padding: EdgeInsets.only(top: 10.0),
child: RaisedButton(
child: Text('现在是Flutter'),
onPressed: () {
demoPlugin.invokeMethod('interaction', 123);
},
),
),
方法解释说明:
call.method == "interaction" 用来从flutter给原生发送信息或者打开原生页面的实现
call.method == "methodId" 用来flutter页面初始化从原生处取所需消息
message channel 渠道实现
message channel 交互使用主要是方便实现flutter与原生的消息传递,例如初始化页面时传递token给flutter页面,或者flutter按钮点击操作传递信息回原生页面,主要用于字符串等传递,主要使用 BasicMessageChannel传递
activity部分代码
private val CHANNEL = "demo.plugin"
private var messageChannel: BasicMessageChannel<String>? =null(string是自定义的传递消息的泛型)
val flutterView = Flutter.createView(this,lifecycle,"flutter_view")
val layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.MATCH_PARENT)
linearLayout.addView(flutterView,layoutParams)
/**
* 初始化通信通道
* 参数一:FlutterView实例对象
* 参数二:消息通道名字(key)
* 参数三:消息解码器(用于处理通信消息类型)
*/
messageChannel = BasicMessageChannel(flutterView,CHANNEL, StringCodec.INSTANCE)
//处理来自Flutter中发送的消息
messageChannel!!.setMessageHandler { p0, p1 ->
//具体处理接收到的从Flutter中发送的消息 p0
Log.e("setMessageHandler",p0)
p1?.reply("")
}
//延时发送,确保页面初始化完成后发送数据
Handler().postDelayed({run {
messageChannel?.send(accessToken!!)
}},2000)
此时activity对于message channel的设置已完成
dart部分代码
//注册消息通道
static const BasicMessageChannel<String> platform =
BasicMessageChannel<String>("demo.plugin", StringCodec());
String message = "测试";
widget部分代码
Column(
children: <Widget>[
Text(message),
RaisedButton(
onPressed: () {
platform.send('给原生页面发消息');
},
child: Text('给原生页面发消息'),
),
InkWell(
child: Text('获取ID'),
onTap: () {
_getPicUploadId();
},
)
],
)
具体处理messageHandler逻辑
Future<String> _handleMessage(String message) async {
setState(() {
this.message = message;
// SharePreferencesUtil().setString('token', message);
});
return "";
}
@override
void initState() {
super.initState();
platform.setMessageHandler(_handleMessage);
}
至此已展示两种常用消息通道的基本使用,如需更详细使用可参考Flutter Platform channel详解