什么是 Android 热修复(HotFix)?Tinker 和 AndFix 的原理有何不同?
解读
国内面试问“热修复”时,面试官真正想确认的是:
- 你是否理解线上事故必须“分钟级止血”,而无需用户主动升级;
- 能否把“运行时替换”这件事拆成编译期、分发期、加载期、运行期四个环节,并说出每个环节在国内合规(工信部 164 号文、个人信息保护)与性能(包大小、启动耗时、GC 抖动)上的权衡;
- 能否用一句话指出 Tinker 与 AndFix 的本质差异:前者走“Class 文件全量替换”,后者走“Native 方法指针替换”,并给出线上踩过的坑(小米加固、Android 13 动态加载限制、鸿蒙兼容)。
知识点
- 热修复定义:在进程不重启的前提下,把线上崩溃或业务缺陷以补丁形式覆盖,达到“用户无感知、后台可回滚”的目标。
- 国内合规红线:补丁包必须走 https 下载、签名校验、V3 签名 Scheme、不能动态下发 so 去加密个人敏感信息;应用市场备案时需声明“存在动态更新组件”。
- 触发时机:Application.attachBaseContext → 补丁加载必须在 ContentProvider 安装前完成,否则 Provider 中已缓存的 Class 无法回退。
- Tinker 原理:
- 编译期:Gradle 插件对比新旧 APK,生成差分 dex(bsdiff)+ so(bsdiff)+ 资源(res diff,arsc 格式),合成后生成 patch.apk;
- 加载期:单独进程(TinkerPatchService)做 dexopt,合成完整的新 dex 文件,写入 /data/data/pkg/tinker/;
- 运行期:反射修改 PathList 的 dexElements,把新 dex 插到数组最前面,重启进程后生效;
- 回滚:若新 dex 加载失败,删除 tinker 目录,下次走原 dex。
- AndFix 原理:
- 编译期:注解处理器在需要替换的方法上打 @MethodReplace 标记,生成补丁 jar;
- 加载期:native 层通过 dlopen 打开补丁 so,解析其中 ArtMethod 结构;
- 运行期:利用 Android 4.4-13 不同的 ArtMethod::SetEntryPointFromJni 偏移,把旧方法入口指针直接改写为新方法入口,立即生效,无需重启;
- 限制:只能替换非静态、非抽象、非构造方法,且对 inline、jit 优化敏感,Android 12 之后 inline-cache 导致崩溃概率升高。
- 性能对比:Tinker 合成 dex 过程占用 CPU 1-2 s、ROM 20-40 MB,但兼容性好;AndFix 0 ROM 增量、0 重启,但高版本 ART 结构变化大,需持续维护偏移表。
- 国内大厂落地:微信 Tinker 开源版 1.9.14 支持 Android 13;支付宝 AndFix 已停止维护,内部迁移至 Sophix(类 Tinker 全量替换 + AndFix 即时回退双模);美团 Robust 采用 InstantRun 插桩方案,兼容性好但包体积 +8%。
答案
Android 热修复指在用户无感知、不重新安装 APK 的前提下,通过下发补丁把线上缺陷代码替换为已修复版本,实现“分钟级止血”。
Tinker 与 AndFix 的核心差异体现在“替换粒度”与“生效时机”:
- Tinker 采用“类全量替换”:编译期生成差分 dex,运行期在独立进程合成完整新 dex,通过反射把新 dex 插入 PathList 最前端,下次进程重启后整体生效;优点是兼容性好、可替换 so 与资源,缺点是需要一次重启、占用双倍 ROM。
- AndFix 采用“方法指针替换”:native 层直接修改 ArtMethod 的 entry_point,把旧方法入口指向补丁中的新方法,立即生效、无需重启;优点是零 ROM 增量、用户体验最好,缺点是只能替换 Java 方法,无法处理 so 与资源,且 Android 12 以后 ART 结构变化大,官方已停止维护。
因此,国内线上环境若追求高稳定性与合规,优先采用 Tinker 类全量替换方案;若需秒级修复且方法改动小,可降级使用 AndFix 或 Sophix 双模方案,并预留回滚开关。
拓展思考
- Android 14 引入“restricted 更新签名”机制,补丁包若与 APK 原始签名不在同一旋转链,将被系统拒绝安装,如何改造 Tinker 的签名校验流程?
- 折叠屏多窗口场景下,Application 可能被系统复用而不走完整重启,如何确保补丁加载后 Activity 生命周期重新走一遍?
- 国内厂商加固(腾讯乐固、360 加固)会抽走 dex 并插入壳 Application,导致 Tinker 反射 PathList 失败,有哪些白名单与反射兜底策略?
- 工信部 164 号文要求“热更新能力需在应用市场备案”,如何在 Manifest 中声明并动态关闭热修复,以满足企业合规审计?