一,需要背景:
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 资源文件;
作者:京东科技 刘振中、周智
内容起源:京东云开发者社区