Android Tinker 热修复集成与使用指南 1.9.15.2

Tinker 热修复集成与使用指南

版本:Tinker 1.9.15.2AGP 8.2.2Gradle 8.7

目标:讲清环境、引入、集成、日常怎么用,并列出本项目踩过的坑。

项目仓库地址:点击进入

aar修复,请参照项目文件 docs目录下的 old和new .aar文件,关于项目如何打包 .aar,我会出一个新的文档


一、Tinker 能做什么

类型 说明 本项目
Dex 改 Java/Kotlin 业务逻辑 ✅ 已验证
资源 改 strings、colors、layout 等 ✅ 已验证
so 替换 APK 内 lib/<abi>/*.so ✅ 已配置(需自带 native)
本地 AAR 替换 libs/*.aar 后打补丁 ✅ 已验证(zcclib-release.aar
Manifest 新组件 热增 Activity/Service 等 ❌ 未开启

说明: 手机上不会单独替换 .aar 文件,而是把新版 AAR 编译进新 APK,再与基准 APK 做差量生成补丁;用户加载补丁后,AAR 内的 Dex/资源/so 变更会随补丁生效。

不能做的: 不能改 SampleApplication 壳类;不能靠补丁在 Manifest 里注册新的 Activity/Service 等组件。


二、环境搭建

2.1 必备环境

  • JDK 11+ (本项目 sourceCompatibility = 11
  • Android SDKcompileSdk 34
  • Gradle Wrapper 8.7 (不要用 Gradle 9,Tinker 插件会报 GFileUtils 等错误)

2.2 版本对照(与本项目一致)

组件 版本
Gradle 8.7
Android Gradle Plugin 8.2.2
Tinker SDK + 插件 1.9.15.2

2.3 仓库

settings.gradle 中已配置 google()mavenCentral(),并保留 Tinker / 阿里云镜像(拉 SevenZip 等依赖时有用)。


三、引入 Tinker

3.1 根工程 build.gradle

gradle 复制代码
buildscript {
    dependencies {
        classpath 'com.android.tools.build:gradle:8.2.2'
        classpath 'com.tencent.tinker:tinker-patch-gradle-plugin:1.9.15.2'
    }
}

3.2 模块 app/build.gradle

gradle 复制代码
apply plugin: 'com.android.application'
apply plugin: 'com.tencent.tinker.patch'   // 必须在 application 插件之后

dependencies {
    implementation 'com.tencent.tinker:tinker-android-lib:1.9.15.2'
    implementation 'androidx.multidex:multidex:2.0.1'
}

3.3 Release 构建注意

  • multiDexEnabled true
  • minifyEnabled true 时必须有 mapping.txt
  • shrinkResources 必须为 false(Tinker 要求)
  • 配置 Release 签名(基准包与补丁包签名一致)

四、集成步骤(对照本项目)

4.1 核心类分工

复制代码
SampleApplication          ← 壳,不能热修,只做 Tinker 入口
SampleApplicationLike      ← 真正 Application 逻辑,可热修
TinkerManager              ← install / loadPatch / cleanPatch
PatchResultService         ← 合成成功后冷重启
TinkerPatchService         ← :patch 进程合成补丁

4.2 Application 壳

AndroidManifest.xmlandroid:name 指向 SampleApplication ,不要直接写 ApplicationLike

SampleApplication 继承 TinkerApplication,并指定代理类:

java 复制代码
public SampleApplication() {
    super(
        ShareConstants.TINKER_ENABLE_ALL,  // dex + so + res
        "com.example.tinkerdemo.app.SampleApplicationLike",
        "com.tencent.tinker.loader.TinkerLoader",
        false  // 正式环境建议 true:校验补丁 MD5
    );
}

4.3 在 attachBaseContext 安装 Tinker

SampleApplicationLike.onBaseContextAttached() 中:

  1. MultiDex.install(base)
  2. TinkerManager.installTinker(this)

必须在 attachBaseContext 阶段完成 ,不能拖到 onCreate

4.4 AndroidManifest 必配项

  • meta-data TINKER_ID :与 build.gradlemanifestPlaceholders 一致
  • Service (本项目已注册):
    • TinkerPatchService:patch 进程)
    • PatchResultService(主进程,合成后杀进程冷启动)
    • TinkerPatchForeService(Android 8+ 前台保活)

4.5 权限(本地调试补丁路径)

  • READ/WRITE_EXTERNAL_STORAGE
  • Android 11+:MANAGE_EXTERNAL_STORAGE(读 /sdcard/patch_signed_7zip.apk
  • android:requestLegacyExternalStorage="true"(调试方便)

4.6 混淆 proguard-rules.pro

至少保留:

  • com.tencent.tinker.**
  • SampleApplication(loader 白名单)
  • ApplicationLike、Patch/Load Reporter
  • R$* 成员(资源 ID 稳定)

打补丁时使用基准包的 mapping.txtapplyMapping)。

4.7 tinkerPatch 配置要点

gradle 复制代码
def TINKER_ID = "base-1.0.0"
def OLD_APK  = "${rootDir}/patch/base/app-release.apk"
def OLD_MAPPING = "${rootDir}/patch/base/mapping.txt"
def OLD_RESOURCE = "${rootDir}/patch/base/R.txt"

android {
    defaultConfig {
        manifestPlaceholders = [TINKER_ID: TINKER_ID]
    }
}

tinkerPatch {
    oldApk = OLD_APK
    ignoreWarning = true   // 含 Java/AAR 改动时建议 true,见「常见问题」
    useSign = true

    buildConfig {
        applyMapping = OLD_MAPPING
        applyResourceMapping = OLD_RESOURCE
        tinkerId = TINKER_ID
    }

    dex {
        dexMode = "jar"
        pattern = ["classes*.dex"]
        loader = [
            "com.tencent.tinker.loader.*",
            "com.example.tinkerdemo.app.SampleApplication"
        ]
    }
    lib { pattern = ["lib/*/**.so"] }
    res { pattern = ["res/*", "assets/*", "resources.arsc", "AndroidManifest.xml"] }
}

4.8 本地 AAR 与热修复(已验证)

gradle 复制代码
implementation files('libs/zcclib-release.aar')

两种场景不要搞混:

场景 操作
首次接入 AAR(发版) 把 AAR 放进 app/libs/,打基准包 → 更新 patch/base/ → 安装到手机
仅热修 AAR(已上线) 不要动基准包 ;用改好的 .aar 覆盖 app/libs/ 里同名文件 → tinkerPatchRelease → 推补丁

AAR 热修步骤(本项目已验证):

  1. 手机上已是含旧版 AAR 的基准包(patch/base/app-release.apk 与之一致)。
  2. 在外部改好 SDK,重新打包得到新的 zcclib-release.aar(或你的 aar 文件名)。
  3. 将新 AAR 替换app/libs/zcclib-release.aar(路径、依赖方式不变)。
  4. 执行 .\gradlew.bat clean(可选,建议 clean 后打补丁)→ .\gradlew.bat tinkerPatchRelease
  5. 推送 app/build/tmp/tinkerPatch/patch_signed_7zip.apk,App 内加载补丁并冷启动。

补丁日志中通常能看到 Dex 差量 (AAR 内 Java 变更)以及 资源差量 (若 AAR 含 layout、strings 等)。若 AAR 带 jni/*.so,还会走 lib 差量。

注意: 热修 AAR 时仍需使用基准包的 mapping.txtR.txt;若新版 AAR 导致资源 ID 体系变化过大,需评估是否应发新基准包而非打补丁。


五、目录与基准包

复制代码
TinkerClaude/
├── patch/
│   ├── base/                    # 基准包("已上线版本")
│   │   ├── app-release.apk
│   │   ├── mapping.txt
│   │   └── R.txt
│   └── patch_signed_7zip.apk   # 可选:备份最近一次补丁
├── app/build/tmp/tinkerPatch/   # 补丁真正输出目录(推这个)
│   ├── patch_signed_7zip.apk
│   └── patch_signed.apk
└── keystore/tinker_demo.jks     # Release 签名

每次发布新基准包 都要更新 patch/base/ 三件套,并 adb install -r 装到手机。


六、使用流程(推荐顺序)

6.1 发布基准包(模拟上线)

bash 复制代码
# Windows
.\gradlew.bat clean :app:assembleRelease

将产物拷贝到 patch/base/

源文件 目标
app/build/outputs/apk/release/app-release.apk patch/base/app-release.apk
app/build/outputs/mapping/release/mapping.txt patch/base/mapping.txt
app/build/intermediates/runtime_symbol_list/release/R.txt patch/base/R.txt

安装到手机:

bash 复制代码
adb install -r patch/base/app-release.apk

6.2 修改代码 / 资源 / AAR 后打补丁

不改变 patch/base/ 基准包的前提下,任选其一或组合修改:

  • 改 App 内 Java、layout、strings 等
  • 用新版 .aar 覆盖 app/libs/ 下同名文件(AAR 热修,已验证)

然后:

bash 复制代码
.\gradlew.bat tinkerPatchRelease

仅替换 AAR 时:基准包仍是旧 AAR 打进 APK 的那一版;新 AAR 只参与「新 APK」构建,用于和基准做 diff,无需为此重新安装基准包(除非你还改了 Manifest、TINKER_ID 等)。

补丁输出位置(重要):

  • ✅ 使用:app/build/tmp/tinkerPatch/patch_signed_7zip.apk
  • ❌ 不要只推:app/build/outputs/apk/tinkerPatch/release/(可能是旧文件)

6.3 推送到真机并加载

bash 复制代码
adb push app/build/tmp/tinkerPatch/patch_signed_7zip.apk /sdcard/patch_signed_7zip.apk
adb shell stat -c %s /sdcard/patch_signed_7zip.apk   # 校验大小

App 内:从外部存储加载补丁 → 授权「所有文件访问权限」→ 合成成功后会 自动冷重启PatchResultService)。

6.4 验证是否生效

  • 资源演示页 文案/颜色是否变化
  • logcat 过滤 Tinker.TinkerLoader,应出现 tryLoadPatchFiles: load end, ok!
  • 首次装基准包未打补丁时,code=-2(无 tinker 目录)是正常现象

6.5 清除补丁

主界面 清除补丁 → 强制停止 App → 再打开,即回到基准包行为。


七、代码里如何触发补丁

7.1 从 SD 卡加载(Demo 默认)

路径:/storage/emulated/0/patch_signed_7zip.apk(见 PatchFileUtils

java 复制代码
TinkerManager.loadPatch(context, patchPath);

7.2 从 assets 加载(本地演示)

将补丁放入 app/src/main/assets/patch_signed_7zip.apk,点击「从 assets 加载」。

7.3 生产环境建议

用 OkHttp / 下载 SDK 把补丁下到私有目录或 getExternalFilesDir,再调用:

java 复制代码
TinkerInstaller.onReceiveUpgradePatch(context, absolutePath);

合成成功后务必 冷启动 (杀进程或依赖 PatchResultService)。


八、能力边界速查

场景 是否支持
改 Activity / 工具类 Java 代码 ✅ Dex
改/新增 layout、strings(保持 R.txt 稳定) ✅ 资源
覆盖 app/libs/xxx.aar 后打补丁 已验证(Dex/资源/so 差量)
手机上单独拷贝一个 .aar 文件即生效 ❌(须打补丁包并加载)
AAR 仅含 Java,无 so ✅ Dex 补丁即可
AAR 含 layout/资源 ✅ 资源补丁(需 applyResourceMapping
AAR 含 jni/*.so ✅ so 补丁(ABI 与基准一致)
新增 Manifest Activity 并启动
SampleApplication
改 AndroidManifest 里 Service 注册 ❌ 需重装基准包

九、常见问题

9.1 打补丁失败:ShareTinkerInternals loader 类变更

现象: some loader class has been changed in new primary dex

处理: tinkerPatch { ignoreWarning = true }(本项目已开启)。这是 R8 重编译后的无害差异,不影响业务类热修。

9.2 补丁推了但界面不变

  1. 确认推的是 build/tmp/tinkerPatch/ 下最新文件
  2. adb shell stat -c %s 核对大小,不要只看 ls -l 时间
  3. 必须 冷启动,不要只划掉后台
  4. 手机上必须是 基准包,不是已包含新资源的完整 APK
  5. 合成成功后 SD 卡补丁可能被删除,需重新 push

9.3 patch_meta.info / code=-2 日志

  • 首次安装、未加载过补丁:正常
  • 重装基准包后:先 清除补丁 再加载新补丁

9.4 mkdir res_temp/res 报错但显示合成成功

部分机型(如 vivo)常见,若 onPatchResult: success=true 且冷启动后界面已更新,可忽略。

9.5 Gradle 9 构建失败

请使用 Gradle 8.7,不要用 9.x milestone。

9.6 改了 AndroidManifest(新增 Service 等)

Manifest 变更 不能 靠补丁生效,需 重新打基准包并安装

9.7 何时必须更新基准包

  • 新功能首次上线(新的基准 APK)
  • 修改了 Manifest 组件
  • 修改了 TINKER_ID
  • 换了签名或 ABI 策略

仅改业务代码 / 资源 / 覆盖 libs 下 AAR 后打补丁只打补丁,不更新基准。

9.8 AAR 热修后无效果

  1. 确认手机安装的是旧版 AAR 的基准包,而不是已手动集成新 AAR 编出来的完整 APK。
  2. 确认 app/libs/ 里已是新版 aar,且执行过 tinkerPatchRelease(建议先 clean)。
  3. 补丁需从 build/tmp/tinkerPatch/ 推送,加载后 冷启动
  4. 查看构建日志是否有 Gen classes.dex patch(有 Java 变更时应有 Dex 差量)。

十、命令速查

目的 命令
打基准包 .\gradlew.bat :app:assembleRelease
打补丁 .\gradlew.bat tinkerPatchRelease
安装基准 adb install -r patch/base/app-release.apk
推送补丁 adb push app/build/tmp/tinkerPatch/patch_signed_7zip.apk /sdcard/patch_signed_7zip.apk
解决 R8 锁文件 .\gradlew.bat --stopclean 再编

十一、本项目关键文件索引

文件 作用
app/build.gradle Tinker 插件、tinkerPatch、TINKER_ID
app/src/main/AndroidManifest.xml 权限、Service、TINKER_ID
app/.../SampleApplication.java Tinker 壳
app/.../SampleApplicationLike.java MultiDex + installTinker
app/.../TinkerManager.java 安装与加载补丁
app/.../PatchResultService.java 合成成功冷重启
app/.../MainActivity.java 加载/清除补丁、权限
app/.../PatchFileUtils.java 补丁路径
app/proguard-rules.pro 混淆保留规则
patch/base/ 基准 APK + mapping + R.txt

十二、参考链接

相关推荐
2603_954138392 小时前
安卓误删文件先别慌!5个实用小技巧指南教你补救
android·智能手机
波诺波4 小时前
5-SOFA可变形的3D物体 5-elasticity.scn
android
2501_915909065 小时前
iOS应用性能优化:十大策略提升用户体验与开发效率
android·ios·小程序·https·uni-app·iphone·webview
sun0077005 小时前
打通android全链路,网卡驱动, 内核 , 到上层hal, framework
android
awu的Android笔记6 小时前
Android VpnService:如何把所有流量导入用户态
android
plainGeekDev6 小时前
AlertDialog → DialogFragment
android·java·kotlin
流星白龙6 小时前
【MySQL高阶】13.其他存储引擎
android·数据库·mysql
Lyyaoo.6 小时前
【MySQL】SQL优化
android·sql·mysql
ImTryCatchException6 小时前
Android 性能优化实战手册:从理论到落地的完整方法论
android·性能优化