前言:flutter正式推出已经有很久了,去年看过很多大厂的相关使用,感觉以后将是一个以原生为主跨平台前端为辅的开发模式,所以先尝试并记录flutter的使用历程。ps:去年也做过类似工作,只是没来得及记录下来,这次就当巩固了。
看下动态效果图(上传限制有点模糊),从原生界面点击事件触发跳转到flutter工程,flutter项目也可以单独运行互不干扰,由于flutter也可以运行在ios手机上,所以以后一个模块功能如果用flutter开发的话,ios人员和android人员(都会flutter)一起开发,这样发版工期将缩短一半。
一,相关准备工作
将flutter项目和原有的android原生项目放到同一个本地文件夹下
原生app的gradle里添加依赖
implementation project(':flutter')
二,android跳转并传向flutter传值
/**
* Created by CK on 2019/9/26.
*/
class BaseFlutterActivity : BaseActivity(), MethodChannel.MethodCallHandler {
lateinit var flutterView: FlutterView
var channel = "home"
companion object {
//暴露的跳转方法 参数1:需要去flutter哪个界面的标识
fun start(routeUrl: String, ctx: Context) {
ctx.startActivity(Intent(ctx, BaseFlutterActivity::class.java).apply {
putExtra("routeUrl", routeUrl)
})
}
//参数1:需要去flutter哪个界面的标识
//参数2:android和flutter通信唯一标识
//参数3:给flutter传递的json字符串
fun start(routeUrl: String, channel: String, paramJson: String, ctx: Context) {
ctx.startActivity(Intent(ctx, BaseFlutterActivity::class.java).apply {
putExtra("routeUrl", routeUrl)
putExtra("channel", channel)
putExtra("paramJson", paramJson)
})
}
}
override fun onCreate(arg0: Bundle?) {
super.onCreate(arg0)
setContentView(R.layout.activity_flutter_enter)
content.visibility = View.INVISIBLE
showLoading()//由于跳转会带有白屏现象这里加入loading动画
val map = mutableMapOf<String, String>()
channel = intent.getStringExtra("channel")
//接收参数,并包装参数以json字符串格式
map["path"] = intent.getStringExtra("routeUrl")
map["param"] = intent.getStringExtra("paramJson")
//创建flutterview,传入json数据
flutterView = Flutter.createView(this, lifecycle, Gson().toJson(map))
//添加到xml里
content.addView(flutterView)
//成功跳转后进度条消失,展示flutterview界面
val listeners = arrayOfNulls<FlutterView.FirstFrameListener>(1)
listeners[0] = FlutterView.FirstFrameListener {
content.visibility = View.VISIBLE
dismissLoading()
}
flutterView.addFirstFrameListener(listeners[0])
//注册通信回调监听,这个channel和跳转到的那个flutter界面里的对应
if (channel.isNotEmpty()) {
MethodChannel(flutterView, channel).setMethodCallHandler(this)
}
}
override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {
if (call.method == "tap") {
//如果flutter界面里触发了tap方法并有一个string类型的参数,那么这里将会被回调
var text = call.argument<String>("text")
showToast(text)
}
}
}
点击gif示例里的按钮,事件触发跳转,还记得各个参数吗?分别是去到哪个flutter界面的路由标记,需要互通的标识,携带的json参数,
Map<String,String> map=new HashMap<>();
map.put("title","android过来的标题");
BaseFlutterActivity.Companion.start("news","news", new Gson().toJson(map),mActivity);
更直观的的看下数据传递:
三,flutter接收数据并进行反馈
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: _widgetRoute(window.defaultRouteName),//接收前面的一串json数据,然后开始解析
);
}
}
Widget _widgetRoute(String jsonStr) {
String path = "home";
String param = "[]";
Widget widget;
if (jsonStr != null && jsonStr.isNotEmpty && jsonStr != "/") {
var jsonResponse = jsonDecode(jsonStr);
path = jsonResponse["path"];//获取path,结果是:news
param = jsonResponse["param"];//获取参数,对应的是:{“title”:“android过来的标题”}
path = path != null && path.isNotEmpty ? path : "home";
param = param != null && param.isNotEmpty ? param : "[]";
}
Map<String, dynamic> map = json.decode(param);
switch (path) {
case "home":
widget = MyHomePage(title: 'Flutter Demo Home Page');
break;
case "news"://最终会到这里,
widget = NewsPage(title: map["title"]);//解析{“title”:“android过来的标题”},通过构造传递过去
break;
}
return widget;//返回news对应的flutter界面,这样就是我们看到的新闻列表展示了,如果传递home就是另一番布局展示了
}
在flutter里的新闻界面通过事件把数据传回到原生界面:
最后原生android里的监听会被回调打出toast:
override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {
if (call.method == "tap") {
var text = call.argument<String>("text")
showToast(text)
}
}
结语:文章到此结束了,也是对这块知识点的一个总结吧,如果有什么问题欢迎在评论区提出~