原生Android项目与Flutter工程双向通信

前言: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)
        }
    }

结语:文章到此结束了,也是对这块知识点的一个总结吧,如果有什么问题欢迎在评论区提出~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值