Flutter烂笔头

Flutter 如何接入 已有Android项目?

2019-06-04  本文已影响17人  RidingWind2023

背景

flutter目前一片火热,相信很多小伙伴都跃跃欲试。但现状是很多公司都有稳定的Android/ios项目,想完全用flutter重写,完全不现实,毕竟,世上没那么多"闲鱼"。

所以我们要思考的是,如何把flutter接入到原生项目当中。
这里主要参考的还是官方文档传送门

主要的执行步骤如下:

1. 在你的Android工程目录同级目录下执行命令

假设你的项目的根目录为/xxx/pro,则需要在/xxx下(主目录的下一级也可以,后续会讲到)执行以下命令

flutter create -t module flutter_module

2. 打开你的Android工程的setting.gradle文件

从setBinding处添加,这里有一点要注意一下,

include ':app'

setBinding(new Binding([gradle: this]))
println("settingsDir.parentFile=" + settingsDir.parentFile)
evaluate(new File(settingsDir.parentFile, 'FlutterHybrid/flutter_module/.android/include_flutter.groovy'))

3. 最后打开你的app目录下的build.gradle

implementation project(':flutter')

使用姿势

准备工作已经完毕,接下来就是拉起一个flutter的页面。
官方提供了两种 原生模块拉起flutter模块的方式:

  1. 直接createView创造一个flutterView,把他添加到你的布局中
    createView方式
    最后一项"/setting" 是对应flutter的路由指向的页面,关于路由这里就暂时放一下,后续会提到。
  2. 使用fragment的方式
    fragment方式
    以上就是两种元素模块应用flutter模块的方式,实际上看过FlutterFragment的源码你就会发现,他也是调用了Flutter.createView返回一个FlutterView,最终都是添加了一个flutterView到原生中而已.

下图可以一图概括android与flutter之间的交互:

混合

flutter调用原生能力

主要参考文档 传送门

MethodChannel
MethodChannel具备双向通信的能力,也就是说他既可以从android调用flutter,也可以从flutter调用android。
首先我们先来看flutter如何通过methodChannel来调用native的,效果图如下:
flutter2native

flutter端代码(发起调用端)如下:

Future<void> requestAdd(callback) async {
        try {
            final int result = await platform.invokeMethod(MNAME_TEST,
                <String, dynamic>{
                     'a': 20,
                     'b': 30,
                   });
            debugPrint('result add = $result .');
            callback(result);
        } on PlatformException catch (e) {
            debugPrint("Failed to get result: '${e.message}'.");
        }

    }

android端代码(接收调用端)如下:

MethodChannel(flutterView, FLUTTER_CHANNEL_NAME).setMethodCallHandler { call, result ->
            if (call.method == "add") {
                Log.d("111", "enter test")
                try {
                    val a = call.argument<Int>("a")
                    val b = call.argument<Int>("b")
                    Log.d("111", "a=$a , b=$b")

                    val res = doRealAdd(a, b)
                    result.success(res)
                } catch (e: ClassCastException) {
                    e.printStackTrace()
                }
            } else {
                result.notImplemented()
            }
        }

以上的样例代码涉及了flutter如何调用native的哪个函数,传递什么参数,可以拿到什么返回值。当然,支持的数据类型也是有限制的。

支持的数据格式

接下来看下native如何通过MethodChannel来调用Flutter能力的:
android端(发起调用端)代码如下:

//这里是native调用dart函数
callDartMethod.setOnClickListener {
    //第二个参数可以约定json,这里为了简化使用了简单的字符串
    methodChannel.invokeMethod("flutter_add", "a=20;b=30", object : MethodChannel.Result{
        override fun notImplemented() {
        }

        override fun error(p0: String?, p1: String?, p2: Any?) {
            showResult("receive dart error = $p0")
        }

        override fun success(p0: Any?) {
            showResult("receive dart result = $p0")
        }
    })
}

dart端(接收响应端)实现代码如下:

void initNativeHandler(){
        platform.setMethodCallHandler((methodCall){
            print("receive native call , methodCall.method = ${methodCall.method}");
            if(methodCall.method == "flutter_add") {
                //此处简化了传参,可以优化使用json, 这里是a=30;b=20的形式
                try {
                    String argument = methodCall.arguments;
                    var arr = argument.split(";");
                    arr.forEach((str){
                        print("dart add str = $str  ");
                    });
                    int result = int.parse(arr[0].split("=")[1]) + int.parse(arr[1].split("=")[1]);
                    print("dart add result = $result");
                    return Future<String>((){
                        return result.toString();
                    });
                } catch (e) {
                    return Future((){
                        return PlatformException(code: 'add err');
                    });
                }

            }
        });
    }

我们要发送自定义类型数据过去如何办?
显然,我们需要转换为dart支持的类型,也许,你可能想到了Object->Json,然后,到了flutter那边,在变为Json对象即可。
不过也有其他的方式,比如,你们恰好使用的是protobuf的话,那么直接传byte[]肯定很不错啦,再者,你还可以实现自定义协议,如果有足够的时间的话。总之传递的数据需要是平台之间都能识别的类型。

EventChannel-原生向flutter发送数据的另一种方式

参考资料 EventChannel
native端代码如下:

native端代码

flutter端代码如下:


flutter端代码

总结

原生拉起flutter做的页面以及flutter调用原生模块以及原生模块推送数据到flutter经过验证都是ok的,因此flutter接入现有的app这条路是可行的。
以上样例代码均已上传到github戳我戳我


如果你觉得这篇文章对你有益,还请帮忙转发和点赞,万分感谢。

Flutter烂笔头
您的关注将是我坚持的动力源泉,再次感谢。
上一篇下一篇

猜你喜欢

热点阅读