本文列举了项目开发使用Flutter会遇到的问题,以及如何使用Flutter module在现有项目中集成Flutter,并对其原理进行了分析。android
最近在作的一个商业项目,彻底的使用Flutter编写的,这其中的坑,只有写过的人才能体会到。ios
在论述纯Flutter项目问题以前,我先表述下个人观点(仅限于纯Flutter项目,目前时间2018年6月26日,不排除Flutter的发展,让个人观点改观):git
对于使用Flutter的初衷,我相信大部分领导都是出于提升生产力。可是目前就咱们的项目来看,相同的时间,若是改用Native去写,我以为二者进度并无多大的差别,可能Native端反而会更快一些。目前Flutter中很是常见的一些控件功能都没法知足,每每在轮子上须要耗费大量的时间,反而在业务层面花费的时间不多。程序员
适配问题:Flutter说的是跨平台,可是没有很完美的解决各个屏幕差别所带来的问题。实际上仍是须要去作一些适配;github
性能问题:目前看这个问题特别突出,在一些性能低的Android手机上,会出现一些卡顿问题。在一些高端机型上,一些转场动画,效果也不是特别理想,一旦涉及到一些复杂的页面,切换页面就会出现很明显的卡顿问题;web
硬件相关问题:这个也是Flutter须要急需解决的问题,第三方硬件相关插件质量良莠不齐,官方插件质量也堪忧。例如官方的camera插件,各类crash问题。性能优化
生命周期问题:插件层对生命周期的监控,是App级别的,没法针对某一个页面。Flutter中控件也没有很明确的生命周期这一律念,就是两三种状态的切换,没有像React中的生命周期,更不用说像Native中的那样。bash
上面这些问题是在项目中实际遇到的,固然一些问题经过变换实现手段能够规避,一些轮子本身花些时间造。一个新技术的初期,尤为是这种跨平台技术,选择all in的,仍是须要再三考量。app
前面说的一些问题,并非说Flutter很是差劲。若是说生态很是成熟的Flutter,我会很是愿意去使用,这项技术目前看确实挺有吸引力的。抛开写着写着就感受本身像个web开发以外,其实写起来并无太多的负担。异步
移动端技术如今已是处在一个很是成熟平稳的时期,因此跨平台技术才会如此的迫切,单纯的去召集两个team开发两个端,这种成本在目前来看确实比较高,尤为是一些日活较低的产品。
前段时间,炒得沸沸扬扬的Airbnb抛弃RN的新闻,让你们对RN以及跨平台技术产生了一些不肯定。跨平台技术历来都是公司层面的需求,并非程序员我的的需求。何况,任何技术都不能忽略平台背后的商业推进,我不是一个跨平台技术的追求者,我我的也一直以为跨平台是个伪命题。
追求纯粹的跨平台,无疑是条死路,平台差别中追求共通点,这才是大出路。我想这也是为何Flutter要去实现,在现有项目中集成Flutter的缘由吧。
官方一直在努力让Flutter更好的接入现有的移动端(iOS/Android)项目中,这个目的不言而喻。若是这个弄很差,确定不会有太多商业项目愿意去使用Flutter,就像RN同样。
Android端方案目前稍微算是稳定一些,可是性能效率方面仍是堪忧。所以本文主要偏重于介绍Android端目前来讲算是相对稳定的一种方案,也就是采用Flutter module模板的方式。
咱们默认安装的Flutter版本是beta版本,目前(2018年6月29日)版本尚未支持在现有项目中集成Flutter module的模板功能。
flutter channel
通常的用户能够看到输出以下信息:
Flutter channels:
* beta
dev
master
复制代码
所以,咱们切换到master分支。
flutter channel master
而后运行更新命令
flutter upgrade
这个功能是在2018年6月22日发布在master分支的,目前也只是早期的preview版本。咱们在一个Android项目目录同级目录下建立模板工程。
flutter create -t module flutter_module
建立的项目目录下面有两个隐藏文件夹,分别是.android和.ios。其中.android中包含后续咱们须要使用的一些代码,例如封装好的Flutter以及FlutterFragment的Java代码。
修改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项目中了。
使用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代码的全过程了,咱们来梳理一下整个流程:
这个目前是在试验阶段,若是有愿意尝试的,也能够按照官方的例子去走一遍,不过你们最好也得有心理准备,官方文档上说会出现一系列问题,在此笔者不作进一步的尝试了。整个过程并不复杂,也是须要切换到master分支上去进行的。若是这种方案稳定下来,确定会比上面的那种module方式更加的方便。
目前也是试验阶段,若是想要尝试的话,也须要切换到master分支上去进行的。
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进行通讯的。
经过Flutter module中的flutter模块,咱们能够看出其本质上仍是经过MethodChannel进行调用的。这是Flutter官方提供的一种插件能力,并非说只能单向调用,也能够在Native端调用Flutter。
可是呢,这个调用是异步的,目前看,Native端调用Flutter层效果并非很理想。目前笔者也是在debug下进行测试的,release环境下应该会好一点吧。若是须要在Native项目中集成Flutter,则还须要进行优化,例如提早初始化等。
在Flutter module没有被放出以前,其余公司通常都是怎么去实现这种混编的呢。如上面所述,我以为都是利用了FlutterView。若是咱们不依赖Flutter module,在Native中引入Flutter库,直接使用FlutterView进行页面编写,这个自己也不是什么困难的事情。难就难在进行性能优化达到上线的条件。
MethodChannel这种Natvive与Flutter之间的通讯方式,给了这种混编的一种可能性。仍是期待Flutter官方能把这种混编模式完善起来。
最后说一句,Flutter里面造起轮子来,简直就是太没人性了。
笔者建的一个Flutter学习相关的项目,Github地址,里面包含了笔者写的关于Flutter学习相关的一些文章,会按期更新,也会上传一些学习demo,欢迎你们关注。