Skip to content

部署数据与影响分析 ​

增量编译生成 DEX、资源、Manifest 和 native lib 后,Jugg 还不能立即把“发生变化的文件”原样发送到设备。它需要先判断未修改的调用方是否仍兼容新的 class 结构,再把最终产物按设备上的生效方式分类。

这一步连接增量编译和增量部署:影响分析决定是否继续补编译源码,部署数据决定本轮使用 Apply Changes、Hot Fix、SO hot update、APK 更新还是兼容部署。

class 结构变化会把流程送回编译阶段 ​

如果类 A 删除方法或修改字段签名,只重新编译 A 仍会在旧 APK 中留下按旧签名调用的类 B。本轮编译虽然成功,B 运行到旧调用时仍会抛出 NoSuchMethodError 或 NoSuchFieldError。

text
A 的新 class 生成
  -> 对比 APK 基线中的旧 class
  -> 查询旧调用方、字段访问方和子类
  -> 命中的源码加入下一轮编译
  -> 没有新的受影响源码后再生成最终部署数据

方法、字段、继承和泛型结构的传播规则见重编译 / 扩散编译。编译期常量被内联后没有普通运行时引用,由常量引用分析单独找回使用方。本页不重复这两套编译机制。

最终产物按生效方式分类 ​

影响传播结束后,Jugg 把可部署内容分成几类:

部署数据判断来源生效方式
可在线修改的 class新旧 class 结构保持兼容作为 modified class 进入 Apply Changes
新增 classAPK 和已部署历史中不存在作为 new class 进入 Apply Changes
需要 Hot Fix 的 class结构变化、library dex、multi-dex 或其它在线替换边界重启 App 后由运行时加载
资源与 assets overlay资源增量编译结果Apply Changes 或 Direct Overlay
SO hot update 文件开关开启时已经生成的 native lib进入对应 APK 的 overlay,重启 App 后加载
APK 更新文件Manifest、配套资源表,以及关闭 SO hot update 时的 native lib写回对应 APK 并重新签名安装

同一个源码修改可能同时产生多类数据。例如修改 Manifest 引用的资源时,Manifest 和配套资源表进入 APK 更新,普通资源和 class 仍可在安装后继续通过 overlay 下发。

首次资源部署需要完整 overlay ​

设备第一次接收资源 overlay 时,只有本轮变化文件不足以形成完整的新资源视图。Jugg 会从 APK 基线和本轮产物中补齐资源集合,再生成第一次 full resource overlay。

后续成功部署已经建立资源历史,Jugg 才继续发送相对上轮状态的变化。部署失败时不会提前提交这份历史,因此下一轮仍能重新生成完整结果,而不会把未成功的资源当成设备已有内容。

多 APK 只裁剪传输数据 ​

base、split、test APK 可能拥有同名的 resources.arsc、DEX 或 overlay 路径。每项部署数据会记录真实目标 APK,单次传输前再按 applicationId 和 APK 归属裁剪。

裁剪结果只用于当前 APK 的一次下发。部署历史必须在所有目标完成后使用整轮原始数据提交,不能用某个 APK 的局部结果推进全局状态。否则下一轮可能错误认为其它 APK 的变化也已经部署。

分类如何决定部署结果 ​

text
最终部署数据
  -> 存在 APK 更新文件:先更新并安装 APK
  -> 存在需要 Hot Fix 的 class:重启 App
  -> 只有普通 class / overlay:Apply Changes 并重建 Activity
  -> 设备需要兼容部署:转换为重启后加载的产物
  -> 设备未 ready 且状态可校验:可使用 Direct Overlay 传输

分类决定产物应该怎样生效,但不能跳过设备状态校验。本地历史、deployment cache 和设备 overlay ID 不一致时,Jugg 会先 Recover;状态恢复完成后才使用本轮数据。

历史只能在部署成功后提交 ​

影响分析和部署分类得到的都是本轮暂存结果。只有全部编译、目标 APK 更新、设备传输和生命周期动作成功后,新的 class 结构、文件历史和 overlay ID 才会成为下一轮基线。

部署中途失败或用户取消时,暂存结果不会伪装成已经生效。下一次运行仍基于上一轮成功状态重新计算影响和部署数据。

相关页面 ​