Flutter单纯如是说
Flutter是Google打造出的UI软件包,协助合作开发人员通过两套标识符同时在iOS和Android上构筑相媲美原生植物新体验的精致应用领域。
合作开发人员能采用Flutter开始两个崭新的应用领域,也可以把Flutter认知为应用领域内建的两个发动机,把这个发动机导入到原有的工程建设中。
Flutter架构图如下表所示:
示意图右图,Flutter 架构被组织为第二层结构,每一层都建立在前几层其内。下面泛称 Framework,下面的一切都叫作 Engine。Framework完全采用 Dart 程式设计词汇撰写。Engine的绝大部份采用 C++ 撰写,专用 Android 的部份用 Java 撰写,专用 iOS 的部份则用 Objective-C 撰写。Flutter的网络平台有关层较低,网络平台只是提供两个画笔,余下的所有图形有关的方法论都在Flutter外部,这就使它具备了较好的跨端连续性。
Dart主要由Google负责合作开发和保护的一种强类别、虚拟化的合作开发词汇。具备高劳动生产率、加速高效率、图形界面、初学的OO程式设计艺术风格和原生植物支持积极响应式程式设计等杰出优点。
结语
腾讯新闻报道工程项目这类很巨大,业务多样,全部改成Flutter实现的确是不现实的,在采用Flutter的后期阶段,我们挑选出了相对独立的两个组件,在原有工程建设的基础上对其进行Flutter改建,以渐进的改建形式确保工程项目平稳,下面以Android为例,从以下两个方面如是说下此混和合作开发课堂教学过程:
软件系统形式
合作开发商业模式
工程建设管理
原生植物端与Dart端通讯
混和栈及路由
调试
遇到的问题及解决方案
稳定性确保
Flutter软件系统形式如上如是说说明,合作开发人员能采用Flutter开始两个崭新的应用领域,也能把Flutter作为应用领域的两个module,把这个module导入到原有的工程建设中,因此有如下表所示图的两种接入形式:
腾讯新闻报道采用上图右右图的形式,以原有工程建设为主端的Flutter Module的形式软件系统到原有工程中去,具体软件系统方法可参考https://github.com/flutter/flutter/wiki/Add-Flutter-to-existing-apps,合作开发人员在lib文件下采用Dart词汇撰写相应的业务标识符。
合作开发商业模式
在腾讯新闻报道合作开发中的debug和release两种商业模式下,Flutter的构筑和编译商业模式如下表所示:
debug商业模式下:Flutter的编译是支持JIT的, 对于Dart合作开发人员在主工程的build.gradle中以Compile project
形式接入Flutter工程建设,方便合作开发和调试;
release商业模式下:Flutter的编译商业模式为AOT,业务Dart标识符直接生成二进制指令文件,如下表所示图右图,其中撰写的Dart标识符通过gen_snapshot编译器生成 vm/isolate_snapshot_data/instr,engine 通过Ninja 构筑系统来生成flutter.jar,包括了engine c++部份的标识符(flutter.jar中的libflutter.so),以及两套将Flutter嵌入Android的java类和接口(FlutterMain,FlutterView,FlutterNativeView等),最后通过gradle将这些Flutter有关标识符编译和嵌入到原生植物App中。
通过了解Flutter的构筑和编译商业模式,可知Flutter module的接入最终的产物完全就是两个.aar包, 因此最终我们整个工程建设的release包futter是以.aar形式直接软件系统到原有工程建设中打包的,这样对于目前原有的工程建设的整个生产流程侵入干扰性达到最小。
另外需要注意以下两点:
minSdkVersion 需要至少为16
主工程建设的build gradle插件版本要升级至3.x
工程建设管理下面提到的Flutter module,以git submodule的形式分别导入到Android和iOS两端的主工程建设中
这样对于Flutter Dart端合作开发人员,在本地工程建设目录中保留.gitmodule文件,通过git module保护flutter 标识符,达到dart合作开发人员协同合作开发&调试;
而Android和iOS两端native合作开发人员来说,Flutter module能完全透明, 在运行时Flutter module会以.aar的形式compile到主工程建设,这样对原生植物合作开发人员来说Flutter的接入是无感知的。
原生植物端与Dart端通讯
Flutter虽然是个虚拟化方案,在UI,手势触控,动画及基本的网络请求等上已经基本做到网络平台无关,但是在某些网络平台优点的功能上,还是必须要根据不同的网络平台做处理,且在后期过渡改建阶段,有些业务方法论仍然需要原生植物端的支持,这就设计到与native的通讯。
从上图能看出,dart端与原生植物端的通讯是通过Flutter提供的channel机制达到双向通讯,具体有三种channel:
BasicMessageChannel: 主要是传递字符串和一些半结构体的数据
MethodChannel: 传递方法调用
EventChannel:数据流的通讯
其实通过源码能看出,无论哪种传递,本质上都是数据的传递,通讯都是通过BinaryMessage, 具体实现类是FlutterNativeView,采用的消息格式为二进制格式数据,三种channel只不过是上层包装的逻辑不同而已,具体采用哪个通讯,根据具体业务实现来定。
在腾讯新闻报道工程项目中,对于消息传递,制定了两套统一的消息协议规范,方便Android,iOS原生植物端和Dart端的通讯。
另外官网上提供的Plugin,基本上都是通过channel来调用原生植物能力,合作开发人员可根据需要直接在pubspec.yaml中导入采用,另外在pub库中也有越来越多的plugin, 大家也能自行合作开发通用的plugin采用。
混和栈及路由
以module的形式接入Flutter, 对于要改建的组件或者页面,在Activity或Fragment的onCreateView中创建FlutterView,Activity或者Fragment为FlutterView的两个容器;另Flutter的framework层提供的navigator管理控制Flutter外部的页面, 如下表所示图中pageWidgetC1,C2,C3的都为Dart实现的flutter页面,而它们是处在同两个Activity中的,因此就有了混和栈的问题(原生植物栈和Flutter外部栈同时存在)。
对于混和栈路由的处理,如下表所示图左右图,两个Activity里有多个Flutter页面,Flutter之间的跳转切换由Flutter外部栈管理,不过相应的对于页面跳转动画,手势右滑跟随退出等效果也要同原生植物端效果再实现两套,且需要同Android,iOS原生植物端原有的保持连续性,但Android,iOS两端原有的本来就是不一致的,因此就有了如下表所示右图右图的第二个方案,两个Activitiy对应两个Flutter页面,路由由原生植物保护两套,Flutter页面之间的跳转其实是Native的跳转,比如Flutter page1跳转Flutter Page2,需要page1通过约定的消息协议通知到Native,Native收到跳转Flutter页面的协议后会再开启两个承载FlutterView的Activity来绘制Flutter page2页面,但该方案对于跳转层级比较深的页面,多个FlutterView实例对于性能有一定的损耗,因为每一flutterView的底层对应两个engine,
这两种方案都是可选的,但都不是最优方案,Flutter设计的初衷应该是多以新的纯的Flutter工程建设为出发点来支持虚拟化合作开发的,对于在原有工程建设改建的混和合作开发没有较好的支持,具体采用哪种方案,根据自己工程项目情况来定,或者更改Flutter的engine来优化内存和数据同步等问题。
腾讯新闻报道因为后期选取的改建组件比较独立,两个组件对应两个Activtiy, 该Activtiy里有多个Flutter页面,对于跳转动画,手势右滑跟随退出等效果同Android原生植物端效果一致,且在统一路由跳转处增加配置项,可切换一对一方案,这样能确保iOS的接入与原生植物的交互新体验连续性,后续随着越来越多的业务组件改建,对于原有设计方案,我们会不断更新调整优化。
调试
Flutter hot reload是Flutter的一大亮点,可称之为神器,合作开发人员有任何修改,都不需要重新启动应用领域,即可看到改动效果。进入Flutter module, 输入命令flutter attach。
如上就说明连接成功,只要有改动,键盘敲击R或者r 即可看到更改。
如果你运行命令后一直在waiting,可尝试杀死该应用领域进程后再重新进入有关Flutter页面就可连接上了
遇到的问题及解决方案 SO库兼容性问题
在Flutter官方只提供了4中CPU架构的so库,armeabi-v7a、arm64-v8a、x86和x86-64,其中x86系列只支持Debug商业模式,没有提供armeabi架构的库,而腾讯新闻报道上只保留armeabi的so文件。虽然我们能通过修改engine等配置文件来编译出armeabi架构的so, 但是实际上现在市面上绝大部份手机设备都已经支持armeabi-v7a,其提供的硬件加速浮点运算指令能大大提高Flutter的运行速度,且修改engine需要额外的版本保护,所以我们后期灰度期间在Flutter分支上直接屏蔽掉不支持armeabi-v7a的设备,直接采用armeabi-v7a的so文件。在编译阶段通过gradle构筑将armeabi-v7a下的libflutter.so拷贝到armeabi目录下。
包体大小问题
导入Flutter后,通过上述flutter构筑的图能看出,最终产物so,icu, vm/isolate_snapshot_data/instr大小都是很可观的,对于Android来说,包体增大6M左右,随着业务标识符的增多,包体将会更大,起初,我们采用动态下发这些文件以解决包体大小的问题,并验证了其可行性,但是这样处理有个问题,就是如果这些文件下载失败,该如何处理?此外官方团队也在重点优化包体大小,因此暂时放弃动态下发这一方案。
资源共享问题
在flutter中导入图片资源,需要在lib下建立image包,并需要在pubspec.yaml文件下的assets下声明; 对于混和合作开发来说,如果两端都需要的图片资源,就要存在两套,这样一来增加了包体大小是同一份资源在Android和iOS原生植物端的资源命名不一致,为此合作开发成本较大,带来收益较小,暂放弃本地资源共享这一方案。
稳定性确保
对于稳定性确保采用如下表所示方案:
选取个别渠道上进行灰度测试;
动态接口开关控制用户逐渐放量测试;
通过FlutterError.onError和runZoned捕获异常,异常错误信息用channel机制通过native上报到崩溃收集系统(fabric-Crashlytics)。
上线情况:腾讯新闻报道Flutter用户量由4%逐渐放量到目前10%, 在两个版本的迭代过程中,异常收集达到万分之一,已达到生产标准。
当然我们还在继续,我们iOS也相继接入,实现方案也在不断调整和优化,官