现有项目中集成Flutter
本文列举了项目开发使用flutter会遇到的问题,以及如何使用flutter module在现有项目中集成flutter,并对其原理进行了分析。
最近在做的一个商业项目,完全的使用flutter编写的,这其中的坑,只有写过的人才能体会到。
1. 纯flutter项目的问题
在论述纯flutter项目问题之前,我先表述下我的观点(仅限于纯flutter项目,目前时间2018年6月26日,不排除flutter的发展,让我的观点改观):
- 对于个人开发者,可以使用纯flutter去开发app尝鲜;
- 对于小团队,不推荐使用纯flutter,出了问题,解决不了,浪费时间;
- 对于商业项目,不推荐使用纯flutter,体验不好,埋坑时间不少。
- 与硬件强相关的项目,不推荐使用纯flutter。
对于使用flutter的初衷,我相信大部分领导都是出于提高生产力。但是目前就我们的项目来看,相同的时间,如果改用native去写,我觉得两者进度并没有多大的差异,可能native端反而会更快一些。目前flutter中非常常见的一些控件功能都无法满足,往往在*上需要耗费大量的时间,反而在业务层面花费的时间很少。
1.1 目前存在的一些问题
适配问题:flutter说的是跨平台,但是没有很完美的解决各个屏幕差异所带来的问题。实际上还是需要去做一些适配;
性能问题:目前看这个问题特别突出,在一些性能低的android手机上,会出现一些卡顿问题。在一些高端机型上,一些转场动画,效果也不是特别理想,一旦涉及到一些复杂的页面,切换页面就会出现很明显的卡顿问题;
硬件相关问题:这个也是flutter需要急需解决的问题,第三方硬件相关插件质量参差不齐,官方插件质量也堪忧。例如官方的camera插件,各种crash问题。
生命周期问题:插件层对生命周期的监控,是app级别的,无法针对某一个页面。flutter中控件也没有很明确的生命周期这一概念,就是两三种状态的切换,没有像react中的生命周期,更不用说像native中的那样。
上面这些问题是在项目中实际遇到的,当然一些问题通过变换实现手段可以规避,一些*自己花些时间造。一个新技术的初期,尤其是这种跨平台技术,选择all in的,还是需要再三考量。
1.2 前景
前面说的一些问题,并不是说flutter非常差劲。如果说生态非常成熟的flutter,我会非常愿意去使用,这项技术目前看确实挺有吸引力的。抛开写着写着就感觉自己像个web开发之外,其实写起来并没有太多的负担。
移动端技术现在已经是处在一个非常成熟平稳的时期,所以跨平台技术才会如此的迫切,单纯的去召集两个team开发两个端,这种成本在目前来看确实比较高,尤其是一些日活较低的产品。
前段时间,炒得沸沸扬扬的airbnb抛弃rn的新闻,让大家对rn以及跨平台技术产生了一些不确定。跨平台技术从来都是公司层面的需求,并不是程序员个人的需求。况且,任何技术都不能忽略平台背后的商业推动,我不是一个跨平台技术的追求者,我个人也一直觉得跨平台是个伪命题。
追求纯粹的跨平台,无疑是条死路,平台差异中追求共通点,这才是大出路。我想这也是为什么flutter要去实现,在现有项目中集成flutter的原因吧。
2. 现有的项目中使用flutter
官方一直在努力让flutter更好的接入现有的移动端(ios/android)项目中,这个目的不言而喻。如果这个弄不好,肯定不会有太多商业项目愿意去使用flutter,就像rn一样。
2.1 android端
android端方案目前稍微算是稳定一些,但是性能效率方面还是堪忧。因此本文主要偏重于介绍android端目前来说算是相对稳定的一种方案,也就是采用flutter module模板的方式。
2.1.1 切换flutter分支
我们默认安装的flutter版本是beta版本,目前(2018年6月29日)版本还没有支持在现有项目中集成flutter module的模板功能。
flutter channel
一般的用户可以看到输出如下信息:
flutter channels: * beta dev master
因此,我们切换到master分支。
flutter channel master
然后运行更新命令
flutter upgrade
2.1.2 创建flutter module模板
这个功能是在2018年6月22日发布在master分支的,目前也只是早期的preview版本。我们在一个android项目目录同级目录下创建模板工程。
flutter create -t module flutter_module
创建的项目目录下面有两个隐藏文件夹,分别是.android和.ios。其中.android中包含后续我们需要使用的一些代码,例如封装好的flutter以及flutterfragment的java代码。
2.1.3 添加flutter module到android项目中
修改android项目根目录的settings.gradle,将flutter module作为一个子工程添加到项目中
include ':app' // assumed existing content setbinding(new binding([gradle: this])) // new evaluate(new file( // new settingsdir.parentfile, // new 'flutter_module/.android/include_flutter.groovy' // new )) // new
sync一下,可以发现添加了两个module到项目中了。其中一个是flutter的module,其中包含了一些简单的封装,供java代码调用。另一个是package_info的module,是一个flutter插件,其代码非常简单,就是获取app名称、包名、版本等信息。
在app的build.gradle中添加依赖
dependencies { implementation project(':flutter')
sync一下,不出意外的话,应该不会有什么错误,到此,这个flutter module就被添加到了android项目中了。
2.1.4 java代码调用flutter module
使用flutter module中的java api,添加一个flutter view到页面上。
val flutterview = flutter.createview( this@mainactivity, lifecycle, "route1" ) val layout = framelayout.layoutparams(600, 800) layout.leftmargin = 100 layout.topmargin = 200 addcontentview(flutterview, layout)
上面代码是添加到一个文本的点击事件中的,其中flutterview可以看作是flutter代码展示的容器。展示的宽600高800的部分,实际上是flutter的代码生成的。其中的route1则是写在flutter中的,生成了一个绿色背景的container。代码如下
case 'route1': return container( child: center(child: text('route 1\n${packageinfo.appname}')), color: colors.green, );
在真机上运行,效果挺差劲的,点击了文本过后,会先黑一下屏,然后将这个flutterview添加到页面上,整个过程也很缓慢,这样子肯定是没法在项目中使用。
到此,已经完成了android调用flutter代码的全过程了,我们来梳理一下整个流程:
- 切换flutter分支到master,目前beta分支上没有包含模板工程;
- 生成flutter module工程;
- 修改android代码的配置,将flutter module添加到android项目中;
- 在模板工程的lib下编写相关的flutter代码,在android中调用。
2.2 将flutter项目转换为module
这个目前是在试验阶段,如果有愿意尝试的,也可以按照官方的例子去走一遍,不过大家最好也得有心理准备,官方文档上说会出现一系列问题,在此笔者不做进一步的尝试了。整个过程并不复杂,也是需要切换到master分支上去进行的。如果这种方案稳定下来,肯定会比上面的那种module方式更加的方便。
2.3 ios端
目前也是试验阶段,如果想要尝试的话,也需要切换到master分支上去进行的。
2.4 关于flutterview
flutterview在插件层面比较常见,是flutter层的一个java api。实际上可以把它看是android端的一个view,只不过里面包含的是flutter的内容。例如将相机封装成一个flutter控件,就需要借助flutterview,将预览输出到flutterview上。
在native项目中集成flutter,flutterview也起到了很重要的作用。flutter层内容的输出,也都是通过flutterview来实现的。
flutterview继承自surfaceview,它像是一个大杂烩,它包含了或者监听了尽可能多的事件,例如键盘、物理按键、生命周期、广播、surface回调、横竖屏切换等等。基本上把android端一个view可能存在的一些事件或者状态,都添加上去,让flutter层能够得知尽可能多的状态和回调。
flutterview除去各种监听事件,内部实际的工作是由flutternativeview去实现的。其本质也是一个插件接口,只不过是native调用flutter层的,它们之间通过methodchannel进行通信的。
2.5 原理
通过flutter module中的flutter模块,我们可以看出其本质上还是通过methodchannel进行调用的。这是flutter官方提供的一种插件能力,并不是说只能单向调用,也可以在native端调用flutter。
但是呢,这个调用是异步的,目前看,native端调用flutter层效果并不是很理想。目前笔者也是在debug下进行测试的,release环境下应该会好一点吧。如果需要在native项目中集成flutter,则还需要进行优化,例如提前初始化等。
3. 其他方法
在flutter module没有被放出之前,其他公司一般都是怎么去实现这种混编的呢。如上面所述,我觉得都是利用了flutterview。如果我们不依赖flutter module,在native中引入flutter库,直接使用flutterview进行页面编写,这个本身也不是什么困难的事情。难就难在进行性能优化达到上线的条件。
methodchannel这种natvive与flutter之间的通信方式,给了这种混编的一种可能性。还是期待flutter官方能把这种混编模式完善起来。
最后说一句,flutter里面造起*来,简直就是太没人性了。
4. 后话
笔者建的一个flutter学习相关的项目,github地址,里面包含了笔者写的关于flutter学习相关的一些文章,会定期更新,也会上传一些学习demo,欢迎大家关注。
5. 参考
推荐阅读
-
.NET程序员项目开发必知必会—Dev环境中的集成测试用例执行时上下文环境检查(实战)
-
iOS项目中集成Flutter的最新适配升级
-
现有项目中集成Flutter
-
React Native集成到现有Android Studio项目
-
集成 React Native 到现有Android项目
-
【IntelliJ IDEA】〖集成〗如何将Maven项目管理工具集成到IntelliJ IDEA开发环境中
-
Android Studio项目/Flutter 案例中Gradle报错通用解决方案(包括Unable to tunnel through proxy问题)
-
在原生项目中集成Flutter
-
Mac下flutter项目导入、编译、本地及网络插件集成
-
现有项目中集成Flutter