一,需要背景:
APP公布到市场后,难免会遇到重大的BUG妨碍用户应用,因而有在不公布新版本APP的状况下应用热更新技术立刻修复BUG需要。原生APP(例如:Android & IOS)的热更新需要曾经比拟成熟,但Flutter技术栈目前还短少相似的技术计划,因而Flutter研发团队,也须要相似的热更新技术。
二,Flutter热更新技术方向剖析:
通过剖析目前可能有三种可行的计划: 1)相似RN框架; 2)页面动静组件框架; 3)Dart虚拟机定制计划;
计划名称 | 原理 | 长处 | 毛病 | 开源计划 |
---|---|---|---|---|
相似RN的计划 | 用JS以Flutter语法写dart,而后用JavaScript把XML DSL转为Flutter的原子widget组件,而后再让Flutter来渲染 | 因为ios零碎内置反对js,ios上齐全能够实现更新 | 1)因为跨语言执行,对于性能有影响;学习老本高 2)Android 端须要额定引入JS库 | 手Q的MXFlutter,58同城的Fair |
页面动静组件计划 | 编译期时插桩/预埋好DynamicWidget到代码中,而后动静下发Json 数据,通过协定好的语义匹配到JSON内的数据,动静替换Widget内容来实现更新 | 能反对Android/iOS 两端的更新 | 1)UI更新绝对较容易,业务逻辑动态化较麻烦; 2)语义解析器开发成本绝对较大,且不易保护 3)须要一整套前后端服务和工具 | 天猫的Tangram,淘宝的DinamicX等 |
Dart虚拟机定制计划 | 通过剖析Dart虚拟机的原理,批改Flutter Engine层Java/C++代码实现热更新的指标; | 性能影响小,动态性很高,技术上能够替换所有Flutter页面(包含UI,逻辑,资源文件) | 因为应用的是定制引擎,须要保护不同版本的Flutter引擎代码; | 未开源 |
因为其余形式都有开源的示例,本案将重点以第三种“Dart虚拟机定制计划”为指标,做计划的钻研解说。
三,准备常识
在开始理解技术计划之前,须要提前理解一些相应的技术概念:
3.1 Flutter编译模式
Flutter开发语言是Dart,它的编译模式来自Dart的编译模式,次要有JIT(Just In Time)和AOT(Ahead Of Time)。
编译模式名称 | 特点 | 长处 | 毛病 |
---|---|---|---|
JIT | 即时编译,典型例子V8,它能够即时编译运行JS,只须要输出源代码字符串,就能够编译运行代码 | 能够动静下发和执行代码,不必管CPU架构,能够提供动态化内容 | 1,大量字符串代码让JIT编译器破费工夫和内存; 2,性能不好; |
AOT | 事后编译,典型例子C/C++,通过GCC编译成二进制代码,而后装置获得权限后才能够加载执行 | 当时编译好的,加载和执行速度快 | 1,编译时辨别CPU架构; 2,生成的二进制代码包比拟大; 3,二进制代码须要获得权限才能够执行,无奈在ios零碎上动静更新 |
Flutter编译模式有:Debug,Release,Profile;
Flutter编译模式 | 特点 |
---|---|
Debug | 对应JIT模式,反对设施和模拟器; 关上了断言,反对疾速开发,反对HotReload; 并未对包大小,执行速度做优化; |
Release | 对应AOT模式,反对真机,不反对模拟器; 禁止了所有断言调试信息; 对包大小,启动和执行速度进行了优化; |
Profile | 相似Release模式,保留了一些调试性能,帮忙性能剖析; |
3.2 Flutter编译产物剖析
Flutter下的iOS/Android工程实质上是一个规范的iOS/Android的工程;IOS平台: Flutter通过在BuildPhase中增加shell(xcode\_backend.sh)来生成和嵌入App.framework和Flutter.framework到ios; Android平台: Flutter通过gradle来增加flutter.jar和编译完的二进制文件增加到Android;
3.2.1 引擎层构造剖析:
3.2.2 Android编译产物的剖析
3.2.3 IOS编译产物的剖析
四,热更新技术计划剖析
4.1 业务代码剖析
依据“3.3.1” ~“3.3.2”的剖析能够确定无论是IOS还是Android APP业务代码都是由四个段组成:kDartVmSnapshotData、kDartVmSnapshotInstructions、kDartIsolateSnapshotData、kDartIsolateSnapshotInstructions;实践上只有能动静替换加载的代码段&数据段代码即可实现目标。
名称 | 正文 | 作用 | 正文 |
---|---|---|---|
kDartIsolateSnapshotData | Dart isolate数据段 | 类信息,全局变量,函数指针等 | 容许动静下发 |
kDartIsolateSnapshotInstructions | Dart isolate指令段 | 蕴含由Dart isolate执行的AOT代码 | IOS不容许动静下发 |
kDartVmSnapshotData | vm isolate数据段 | isolate 之间共享的 Dart 堆 (heap) 的初始状态 | 容许动静下发 |
kDartVmSnapshotInstructions | vm isolate指令段 | 蕴含 VM 中所有 Dart isolate 之间共享的通用程序的 AOT 指令 | IOS不容许动静下发 |
正文: isolate, snapshot, vm isolate含意解释如下:
名称 | 含意 |
---|---|
isolate | Dart是单线程,isolate跟线程差不多,能够了解为 Dart 中的线程。 isolate 与线程的区别:线程与线程之间是共享内存的,而 isolate 和 isolate 之间是内存不共享的。 不存在锁竞争问题,两个Isolate齐全是两条独立的执行线,且每个Isolate都有本人的事件循环,它们之间只能通过发送音讯通信,所以它的资源开销低于线程。 |
snapshot | 将类信息、全局变量、函数指令间接以序列化的形式存在磁盘中,称为 Snapshot(快照)。 |
vm isolate | 同一个过程里能够有很多isolate,但两个 isolate 的堆区是不能共享的,所以官网设计了 VM isolate,也就是 kDartVmSnapshot,用来多个 isolate 之间的交互。 |
4.2 业务代码的加载剖析(运行时)
依照4.1的剖析思路,咱们首先须要理解Flutter运行时代码加载的残缺流程,通过梳理剖析流程如下:
1 )Android- APP业务代码的加载流程:
2)IOS- APP业务代码的加载流程:
4.3 业务代码的编译生成(编译时)
依据以上的剖析,咱们晓得了Flutter业务代码的数据结构,也晓得了在运行时如何加载,因而咱们只须要在编译时做更改,产生本人须要的代码段,和数据段文件。在运行时加载本人的构建产物即可达到目标。
1)在此以 IOS 构建本人的业务代码流程做详细分析:
**有实现构建流程能够剖析,根本流程是“Dart Code(业务代码)” -> (通过Dart编译器gen\_snapshot.cc) 生成 snapshot\_assemble.S 的汇编文件 -> (通过xcrun工具)生成 snapshot\_assemble.o的obj文件 -> (通过xcun clang工具链) 生成了 App.Framework。
2)Android的产物构建流程和IOS相似。因为Android有其余更简略的计划, 因而省略具体的构建流程剖析,大抵如下:
4.4 实现热更新的计划摸索
依据下面的技术剖析后果,曾经能够独立生成本人的代码段,数据段文件。通过需改虚拟机底层代码的形式,也能够动静的加载运行。但因为IOS零碎目前底层的零碎还不能动静加载可读写的代码段数据到内存中,所以还有技术难点须要冲破。但Android端有更简略的门路能够解决,因而上面以Android端为例重点剖析思路,大抵如下图所示:
由上图能够得悉,Android端 热修复外围步骤如下:
1, 批改Flutter Engine代码,加载指定门路的libapp.so和flutter\_aasets,比方公有目录(data/data/files);
2, 编译APK时,利用Gradle Transform插件,依据Flutter SDK的engine version动静替换官网的Flutter engine,最终写入批改后的engine到APK;
3, 生成补丁包:利用BSdiff算法比拟新旧APK文件,生成patch补丁包
4, APP启动时拜访后端接口,依据参数(app的版本号,补丁包版本号,md5,flutter SDK版本号,Engine版本号)拉取补丁包;
5, 合成补丁包:校验md5,app版本号,补丁版本号,安装时间;
6, 自定义Flutter Engine加载指定门路的libapp.so和flutter\_assets资源文件;
作者:京东科技 刘振中、周智
内容起源:京东云开发者社区