背景
flutter目前一片火热,相信很多小伙伴都跃跃欲试。但现状是很多公司都有稳定的Android/ios项目,想完全用flutter重写,完全不现实,毕竟,世上没那么多"闲鱼"。
所以我们要思考的是,如何把flutter接入到原生项目当中。
这里主要参考的还是官方文档传送门。
主要的执行步骤如下:
1. 在你的Android工程目录同级目录下执行命令
假设你的项目的根目录为/xxx/pro,则需要在/xxx下(主目录的下一级也可以,后续会讲到)执行以下命令
flutter create -t module flutter_module
2. 打开你的Android工程的setting.gradle文件
从setBinding处添加,这里有一点要注意一下,
- 假设第一步你创建的flutter_module在你的项目之下,则配置路径时候需要加上你的项目名
FlutterHybrid/flutter_module/.android/include_flutter.groovy - 假设第一步你创建的flutter_module跟你的项目是平级,则配置路径时候不需要加上你的项目名
flutter_module/.android/include_flutter.groovy
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模块的方式:
- 直接createView创造一个flutterView,把他添加到你的布局中
createView方式
最后一项"/setting" 是对应flutter的路由指向的页面,关于路由这里就暂时放一下,后续会提到。 - 使用fragment的方式
fragment方式
以上就是两种元素模块应用flutter模块的方式,实际上看过FlutterFragment的源码你就会发现,他也是调用了Flutter.createView
返回一个FlutterView,最终都是添加了一个flutterView到原生中而已.
下图可以一图概括android与flutter之间的交互:

flutter调用原生能力
主要参考文档 传送门

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

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端代码如下:

flutter端代码如下:

总结
原生拉起flutter做的页面以及flutter调用原生模块以及原生模块推送数据到flutter经过验证都是ok的,因此flutter接入现有的app这条路是可行的。
以上样例代码均已上传到github戳我戳我
如果你觉得这篇文章对你有益,还请帮忙转发和点赞,万分感谢。

您的关注将是我坚持的动力源泉,再次感谢。
网友评论