文章

Android Tinker

Android Tinker

Android 热修复 tinker 总结

tinker 开源框架地址 https://github.com/Tencent/tinker

tinker 的介绍 https://github.com/Tencent/tinker/wiki

主要记录一下针对 Tinker 框架学习的过程。

先说结论,通过切换到最新的 tinker 热修复分支打包出来的补丁包在 android14,android15 设备上重启几次之后补丁包会失效,目前没有发现导致该问题的原因。另外不支持 jdk 8新特性已被劝退,虽然最终没有使用,但是还是记录一下,方便以后查阅。

关于 tinker需要注意的问题,如果你必须考虑到下面这几种情况,则 tinker 框架不适用你的应用

Tinker的已知问题

由于原理与系统限制,Tinker有以下已知问题:

  1. Tinker不支持修改AndroidManifest.xml,Tinker不支持新增四大组件(1.9.0支持新增非export的Activity);
  2. 由于Google Play的开发者条款限制,不建议在GP渠道动态更新代码;
  3. 在Android N上,补丁对应用启动时间有轻微的影响;
  4. 不支持部分三星android-21机型,加载补丁时会主动抛出"TinkerRuntimeException:checkDexInstall failed"
  5. 对于资源替换,不支持修改remoteView。例如transition动画,notification icon以及桌面图标。
  6. 截止到目前暂时不支持 jdk 8新特性

ART 下方法内联的文章分析,一开始在进行 tinker 框架中dex 加载调研时并没有仔细分析这篇文章,后来在改造迁移时发现一些问题,导致走了一些弯路,回过头来又重新看了这篇文章才弄明白 tinker 为什么这样做而不那样做的原因,开源真的是一件很伟大的事情,我们可以看到有人费尽时间和精力走过无数弯路和填坑之后得到的验证结果无私分享出来。

另外还有一网上有人分享的关于 tinker 非常详细的总结也值得一看,这些总结可以加快我们了解tinker框架。Android 热修复Tinker源码分析

由于业务需要,希望能让 SDK 具备热修复能力,调研对比了市面上所有的热修复框架之后,发现 tinker 框架是目前从维护角度,使用范围角度是最佳选择的热修复框架,于是深入调研了一下 tinker 框架是否可以接入到我们的业务中。由于业务逻辑实现基本都是 java,所以初步计划只需要 java 层的热修复能力即可。

探索流程如下

  1. 直接通过 DexClassLoader 加载生成的补丁dex 文件来进行热修复,尝试进行一些代码修复发现可以正常加载,且完全没有碰到 tinker 遇到的问题,然而梳理了tinker 的文章提出的问题进行测试,果不其然就遇到了方法内联的问题。 那么何为内联?

    Optimizing Compiler的方法内联可以跨多级方法调用进行,若有这样的调用链:method1->method2->method3->method4,则在四个方法都满足内联条件的情况下,最终内联的结果将是method1包含method2,method3,method4的代码,method2包含method3,method4的代码,以此类推。但这种跨调用链内联会受到调用dex2oat时通过--inline-depth-limit参数指定的值的限制,默认为5,即超过5层的调用就不会再被内联到当前方法了。

  2. 那么tinker 框架是如何解决ART 下内联问题的。
    1. 首先为什么通过 ClassLoader 加载的dex 没有生效?

      apk 中 dex,vdex,odex 文件的加载过程

    2. Android Dex 方法内联分析介绍中,有四种热修复的方式,Native 中覆盖,反射,VM 中对 dex 进行排序优先加载 newDex,插桩(其实也是反射)。 为什么最终选择了下发全量dex而非增量dex?因为增量dex 下发的代码与原始 dex 中如果存在内联方法的差异会导致执行的不可控性。全量下发 dex 后首次启动或系统OTA之后主动触发dex2oat.这很可能是导致我的首台智能机(小米5s)手机使用微信时偶尔感觉启动特别卡的问题。全量下发这么大的 dex 还得重新dex2oat能不卡吗?
  3. 看了 tinker 的文章分析之后,发现这个流程太复杂了,如果适配适配到我们业务中,需要针对框架进行改造且只取 dex 这部分即可。从 Git 上拉下来的源码发现代码量巨多,分析了Application 加载流程,发现可以修复加载到内存之前的代码,这里的加载过程确实很巧妙,利用了 Handler 调用时才开始加载的原理。

但是经过多次测试又发现了新的问题,tinker之前提出的方法内联有道理的,无法绕开。在测试过程中观察到下发的增量补丁dex 在 ClassLoader 加载之前,会进行 dex2oat 的操作,那么 dex2oat 是什么?

  1. 网上写的关于 Tinker分析的文章,非常详细值得一看 https://juejin.cn/post/6971232987681652773
  2. 先根据 dex 的加载原理实现了 dex 从加载到执行,除了ApkBuilder编译内联问题,还是不可避免的遇到了 dex2oat?
  3. Android 系统为了提高执行效率,会将 dex 文件编译成本地机器码(oat/odex 文件),这个过程就叫 dex2oat。那么 tinker 是如何处理这个问题的?tinker 加载 dex 流程分析
  4. 按照 tinker 框架原理,理论上是可以适配到我们的业务中的,只支持 dex 热修复,主要改造部分如下
    1. sdk 部分,提取 patch 合并流程,dex 加载流程,dex2oat 流程
    2. gradleTask 差分old.apk 与 new.apk流程
    3. 最低成本接入测试的方式是?
    4. 集成 Tinker 框架,打包测试?
    5. 我们由于业务原因有自己的聚合工具,应用生成会二次打包,主要需要研究差分补丁的流程?
  5. 前期的思路是能否采用脚本而非 gradle 来自动化构建?
    1. 差分原理比较复杂没有过多深入,可以参考Android 热修复Tinker源码分析(一)补丁包的生成
  6. Git clone https://github.com/Tencent/tinker.git
    1. 目前线上最新是 rel_1.9.15,切换分支rel_1.9.15
    2. 打开其中 tinker-sample-android 项目发现构建失败,调整 gradle 构建版本
    3. 主要内容在build.gradle 中,配置了补丁包生成相关插件逻辑
    4. 正常构建一个 demo 包后,然后修改代码尝试构建补丁
1
2
3
4
5
6
7
8
9
1.构建失败
> Task :app:transformClassesAndResourcesWithR8ForRelease FAILED
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':app:transformClassesAndResourcesWithR8ForRelease'.
> com.android.tools.r8.CompilationFailedException: Compilation failed to complete

处理方式 gradle.properties 中增加如下配置
android.enableR8=false
  1. 重新生成补丁,还是报错,jcent 仓库换 maven 阿里云的仓库
1
 maven {url 'https://maven.aliyun.com/repository/public'}
  1. 重新构建后成功(注意要重新生成 apk 原包)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
-----------------------Tinker patch begin-----------------------
configuration: 
oldApk:/Users/GR/GitHub/tinker/tinker-sample-android/app/build/bakApk/app-release-0528-15-40-55.apk
newApk:/Users/GR/GitHub/tinker/tinker-sample-android/app/build/outputs/apk/release/app-release.apk
outputFolder:/Users/GR/GitHub/tinker/tinker-sample-android/app/build/tmp/tinkerPatch
isIgnoreWarning:false
isAllowLoaderClassInAnyDex:false
isRemoveLoaderForAllDex:false
isProtectedApp:false
7-ZipPath:/Users/GR/.gradle/caches/modules-2/files-2.1/com.tencent.mm/SevenZip/1.1.10/cc390e6c704b74496d9ba0e9b46d2cf8a2a96b84/SevenZip-1.1.10-osx-x86_64.exe
useSignAPk:true
package meta fields: 
filed name:patchMessage, filed value:tinker is sample to use
filed name:platform, filed value:all
filed name:patchVersion, filed value:1.0
dex configs: 
dexMode: jar
dexPattern:classes.*\.dex
dexPattern:assets/secondary-dex-.\.jar
dex loader:tinker.sample.android.app.BaseBuildInfo
lib configs: 
libPattern:lib/.*/.*\.so
resource configs: 
resPattern:res/.*
resPattern:AndroidManifest\.xml
resPattern:assets/.*
resPattern:resources\.arsc
resIgnore change:assets/sample_meta\.txt
largeModSize:100kb
useApplyResource:true
ArkHot: arkHot / patch.apk

config: arkHot patch.apkassets/arkHot_meta.txt
Analyze old and new apk files1:
old apk: app-release-0528-15-40-55.apk, size=1502634, md5=9accc47836ca9a5593b9def94716a6ee
new apk: app-release.apk, size=1502612, md5=e6b7915f6d363508e1d8fafd697dfd50


Manifest has no changes, skip rest decode works.
UnZipping apk to /Users/GR/GitHub/tinker/tinker-sample-android/app/build/tmp/tinkerPatch/app-release-0528-15-40-55
UnZipping apk to /Users/GR/GitHub/tinker/tinker-sample-android/app/build/tmp/tinkerPatch/app-release
Check for loader classes in dex: classes.dex
Collect class descriptors in classes.dex
Check if loader classes in classes.dex refer to any classes that is not in loader class patterns.

Gen classes.dex patch file:/Users/GR/GitHub/tinker/tinker-sample-android/app/build/tmp/tinkerPatch/tinker_result/classes.dex, size:333, md5:9bb9a57d7214dbe12c6c69dcc9aaa5fd
Verifying if patched new dex is logically the same as original new dex: app-release/classes.dex ...

Gen classes.dex for dalvik full dex file:/Users/GR/GitHub/tinker/tinker-sample-android/app/build/tmp/tinkerPatch/tempPatchedDexes/classes.dex, size:2184088, md5:5d685dd39d1a50aa767d1caf48978a5b
DexDecoder:write meta file data: classes.dex,,5d685dd39d1a50aa767d1caf48978a5b,5d685dd39d1a50aa767d1caf48978a5b,9bb9a57d7214dbe12c6c69dcc9aaa5fd,426174090,3539929398,jar

Add test install result dex: /Users/GR/GitHub/tinker/tinker-sample-android/app/build/tmp/tinkerPatch/tinker_result/test.dex, size:584
DexDecoder:write test dex meta file data: test.dex,,56900442eb5b7e1de45449d0685e6e00,56900442eb5b7e1de45449d0685e6e00,0,0,0,jar
Generate unsigned apk: patch_unsigned.apk
Signing apk: patch_signed.apk
Signing key algorithm is SHA1withRSA
Try use 7za to compress the patch file: patch_signed_7zip.apk, will cost much more time
Current 7za path:/Users/GR/.gradle/caches/modules-2/files-2.1/com.tencent.mm/SevenZip/1.1.10/cc390e6c704b74496d9ba0e9b46d2cf8a2a96b84/SevenZip-1.1.10-osx-x86_64.exe
Result: final signed patch result: /Users/GR/GitHub/tinker/tinker-sample-android/app/build/tmp/tinkerPatch/patch_signed.apk, size=3376
Result: final signed with 7zip patch result: /Users/GR/GitHub/tinker/tinker-sample-android/app/build/tmp/tinkerPatch/patch_signed_7zip.apk, size=3757
Warning: patch_signed_7zip.apk is bigger than patch_signed.apk 381 byte, you should choose patch_signed.apk at these time!
Tinker patch done, total time cost: 2.612000s
Tinker patch done, you can go to file to find the output /Users/GR/GitHub/tinker/tinker-sample-android/app/build/tmp/tinkerPatch
-----------------------Tinker patch end-------------------------
  1. 在 Android14、15 设备成功加载补丁并生成 oat 文件,注意重启了第三次补丁才正式生效!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
14:41:34.865 21315-21315 Tinker.De...Reporter  I  patch loadReporter onLoadResult: patch load result, path:/data/user/0/tinker.sample.android/tinker, code: -1, cost: 0ms
14:41:34.865 21315-21315 Tinker.Tinker         W  tinker load fail!
14:41:34.865 21315-21315 Tinker.De...tAppLike  D  onCreate
14:41:34.868 21315-21328 Tinker.Ti...hService  I  for system version >= Android O, we just ignore increasingPriority job to avoid crash or toasts.
14:41:34.869 21315-21328 Tinker.De...Reporter  I  patchReporter onPatchServiceStart: patch service start
14:41:34.869 21315-21315 Tinker.TinkerLoader   D  [PendingLog @ 2025-05-29 14:41:34.862] tryLoad test test
14:41:34.869 21315-21315 Tinker.TinkerLoader   W  [PendingLog @ 2025-05-29 14:41:34.863] tryLoadPatchFiles: we don't load patch with :patch process itself, just return
14:41:34.869 21315-21315 Tinker.De...tAppLike  D  [PendingLog @ 2025-05-29 14:41:34.863] onBaseContextAttached:
14:41:34.869 21315-21315 Tinker.Up...tchRetry  W  onPatchRetryLoad retry is not main process, just return
14:41:34.870 21315-21328 Tinker.Up...tchRetry  W  try copy file: /storage/emulated/0/Android/data/tinker.sample.android/files/patch_signed_7zip.apk to /data/user/0/tinker.sample.android/tinker_temp/temp.apk
14:41:34.890 21315-21328 Tinker.UpgradePatch   I  UpgradePatch tryPatch:patchMd5:dbf352a85c371e4e0dd0ab611db224e9
14:41:34.891 21315-21328 Tinker.PatchInfo      W  read property failed, e:java.io.FileNotFoundException: /data/user/0/tinker.sample.android/tinker/patch_meta.info: open failed: ENOENT (No such file or directory)
14:41:34.891 21315-21328 Tinker.PatchInfo      W  read property failed, e:java.io.FileNotFoundException: /data/user/0/tinker.sample.android/tinker/patch_meta.info: open failed: ENOENT (No such file or directory)
14:41:34.891 21315-21328 Tinker.UpgradePatch   I  UpgradePatch tryPatch:patchVersionDirectory:/data/user/0/tinker.sample.android/tinker/patch-dbf352a8
---------------------------- PROCESS STARTED (21315) for package tinker.sample.android ----------------------------
14:41:34.892 21315-21328 Tinker.UpgradePatch   W  UpgradePatch copy patch file, src file: /storage/emulated/0/Android/data/tinker.sample.android/files/patch_signed_7zip.apk size: 3756, dest file: /data/user/0/tinker.sample.android/tinker/patch-dbf352a8/patch-dbf352a8.apk size:3756
14:41:35.362 21315-21328 Tinker.De...Internal  W  success recover dex file: /data/user/0/tinker.sample.android/tinker/patch-dbf352a8/dex/classes.dex.jar, size: 914313, use time: 467
14:41:35.362 21315-21328 Tinker.De...Internal  I  try Extracting /data/user/0/tinker.sample.android/tinker/patch-dbf352a8/dex/test.dex.jar
14:41:35.363 21315-21328 Tinker.De...Internal  I  isExtractionSuccessful: true
14:41:35.389 21315-21328 Tinker.PatchFileUtil  I  safeDeleteFile, try to delete path: /data/user/0/tinker.sample.android/tinker/patch-dbf352a8/dex/test.dex.jar
14:41:35.389 21315-21328 Tinker.PatchFileUtil  I  safeDeleteFile, try to delete path: /data/user/0/tinker.sample.android/tinker/patch-dbf352a8/dex/classes.dex.jar
14:41:35.390 21315-21328 Tinker.De...Internal  I  merge classN dex file /data/user/0/tinker.sample.android/tinker/patch-dbf352a8/dex/tinker_classN.apk, result: true, size: 2185249, use: 26ms
14:41:35.390 21315-21328 Tinker.De...Internal  I  legal files to do dexopt: [/data/user/0/tinker.sample.android/tinker/patch-dbf352a8/dex/tinker_classN.apk]
14:41:35.390 21315-21328 Tinker.Ti...nternals  D  getCurrentInstructionSet:arm64
14:41:35.390 21315-21328 Tinker.De...Internal  I  patch recover, try to optimize dex file count:1, optimizeDexDirectory:/data/user/0/tinker.sample.android/tinker/patch-dbf352a8/odex/
14:41:35.390 21315-21328 Tinker.De...Internal  I  start to parallel optimize dex /data/user/0/tinker.sample.android/tinker/patch-dbf352a8/dex/tinker_classN.apk, size: 2185249
14:41:35.390 21315-21328 Tinker.Ti...nternals  I  class not found exception
14:41:35.390 21315-21328 Tinker.ParallelDex    I  Creating fake odex path structure.
14:41:35.391 21315-21328 System                W  ClassLoader referenced unknown path: 
14:41:35.391 21315-21328 e.android:patch       W  Unsupported class loader
14:41:35.391 21315-21328 e.android:patch       W  Opening an oat file without a class loader. Are you using the deprecated DexFile APIs?
14:41:35.401 21315-21328 Tinker.ParallelDex    I  [+] Hit target device, do dexopt logic now.
14:41:35.401 21315-21328 Tinker.ParallelDex    I  [+] Execute shell cmd, args: [compile, -f, --secondary-dex, -m, verify, tinker.sample.android]
14:41:35.402 21315-21328 Tinker.ParallelDex    I  [+] Execute shell cmd done.
14:41:35.402 21315-21328 Tinker.ParallelDex    I  [+] Execute shell cmd, args: [bg-dexopt-job, tinker.sample.android]
14:41:35.403 21315-21328 Tinker.ParallelDex    I  [+] Execute shell cmd done.
14:41:35.403 21315-21328 e.android:patch       W  Accessing hidden field Landroid/content/pm/IPackageManager$Stub;->TRANSACTION_performDexOptSecondary:I (max-target-o, reflection, denied)
  1. 加载补丁过程中出现异常日志,查了一下在 Android 11 以后 google 已经废弃了该 API,但是我再 tinker 中居然没有查到对于这个问题的处理方式与 issue
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Caused by: java.lang.reflect.InvocationTargetException
                                                  	at java.lang.reflect.Method.invoke(Native Method)
                                                  	at com.tencent.tinker.loader.TinkerDexOptimizer.performDexOptSecondaryByTransactionCode(TinkerDexOptimizer.java:368)
                                                  	at com.tencent.tinker.loader.TinkerDexOptimizer.triggerSecondaryDexOpt(TinkerDexOptimizer.java:320) 
                                                  	at com.tencent.tinker.loader.TinkerDexOptimizer.triggerPMDexOptOnDemand(TinkerDexOptimizer.java:275) 
                                                  	at com.tencent.tinker.loader.TinkerDexOptimizer.access$400(TinkerDexOptimizer.java:68) 
                                                  	at com.tencent.tinker.loader.TinkerDexOptimizer$OptimizeWorker$1.run(TinkerDexOptimizer.java:186) 
                                                  	at com.tencent.tinker.loader.TinkerDexOptimizer$OptimizeWorker.run(TinkerDexOptimizer.java:202) 
                                                  	at com.tencent.tinker.loader.TinkerDexOptimizer.optimizeAll(TinkerDexOptimizer.java:109) 
                                                  	at com.tencent.tinker.loader.TinkerDexOptimizer.optimizeAll(TinkerDexOptimizer.java:84) 
                                                  	at com.tencent.tinker.lib.patch.DexDiffPatchInternal.dexOptimizeDexFiles(DexDiffPatchInternal.java:394) 
                                                  	at com.tencent.tinker.lib.patch.DexDiffPatchInternal.patchDexExtractViaDexDiff(DexDiffPatchInternal.java:201) 
                                                  	at com.tencent.tinker.lib.patch.DexDiffPatchInternal.tryRecoverDexFiles(DexDiffPatchInternal.java:88) 
                                                  	at com.tencent.tinker.lib.patch.UpgradePatch.tryPatch(UpgradePatch.java:178) 
                                                  	at com.tencent.tinker.lib.service.TinkerPatchService.doApplyPatch(TinkerPatchService.java:238) 
                                                  	at com.tencent.tinker.lib.service.TinkerPatchService.onHandleIntent(TinkerPatchService.java:114) 
                                                  	at android.app.IntentService$ServiceHandler.handleMessage(IntentService.java:77) 
                                                  	at android.os.Handler.dispatchMessage(Handler.java:106) 
                                                  	at android.os.Looper.loopOnce(Looper.java:205) 
                                                  	at android.os.Looper.loop(Looper.java:294) 
                                                  	at android.os.HandlerThread.run(HandlerThread.java:67) 
                                                  Caused by: java.lang.NoSuchFieldException: No field TRANSACTION_performDexOptSecondary in class Landroid/content/pm/IPackageManager$Stub; (declaration of 'android.content.pm.IPackageManager$Stub' appears in /system/framework/framework.jar)
  1. 补丁生效后其他异常错误
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
14:44:54.031 21445-21445 Tinker.Tinker         W  tinker patch directory: /data/user/0/tinker.sample.android/tinker
14:44:54.032 21445-21445 Tinker.Tinker         I  try to install tinker, isEnable: true, version: 1.9.15.1
14:44:54.033 21445-21445 Tinker.Ti...adResult  I  parseTinkerResult loadCode:-14, process name:tinker.sample.android, main process:true, systemOTA:false, fingerPrint:google/redfin/redfin:14/UP1A.231105.001.B2/11260668:user/release-keys, oatDir:odex, useInterpretMode:false
14:44:54.033 21445-21445 Tinker.Ti...adResult  I  parseTinkerResult oldVersion:, newVersion:dbf352a85c371e4e0dd0ab611db224e9, current:dbf352a85c371e4e0dd0ab611db224e9
14:44:54.033 21445-21445 Tinker.Ti...adResult  I  Tinker load have exception loadCode:-14
14:44:54.033 21445-21445 Tinker.De...Reporter  E  patch loadReporter onLoadException: tinker dex check fail:Tinker Exception:checkDexInstall failed
14:44:54.036 21445-21445 Tinker.De...Reporter  I  dex exception disable tinker forever with sp
14:44:54.036 21445-21445 Tinker.De...Reporter  E  tinker load exception, welcome to submit issue to us: https://github.com/Tencent/tinker/issues
14:44:54.036 21445-21445 Tinker.De...Reporter  E  tinker load exception  com.tencent.tinker.loader.TinkerRuntimeException: Tinker Exception:checkDexInstall failed
                                                  	at com.tencent.tinker.loader.SystemClassLoaderAdder.installDexes(SystemClassLoaderAdder.java:73)
                                                  	at com.tencent.tinker.loader.TinkerDexLoader.loadTinkerJars(TinkerDexLoader.java:191)
                                                  	at com.tencent.tinker.loader.TinkerLoader.tryLoadPatchFilesInternal(TinkerLoader.java:356)
                                                  	at com.tencent.tinker.loader.TinkerLoader.tryLoad(TinkerLoader.java:57)
                                                  	at java.lang.reflect.Method.invoke(Native Method)
                                                  	at com.tencent.tinker.loader.app.TinkerApplication.loadTinker(TinkerApplication.java:126)
                                                  	at com.tencent.tinker.loader.app.TinkerApplication.onBaseContextAttached(TinkerApplication.java:164)
                                                  	at com.tencent.tinker.loader.app.TinkerApplication.attachBaseContext(TinkerApplication.java:187)
                                                  	at android.app.Application.attach(Application.java:346)
                                                  	at android.app.Instrumentation.newApplication(Instrumentation.java:1283)
                                                  	at android.app.LoadedApk.makeApplicationInner(LoadedApk.java:1458)
                                                  	at android.app.LoadedApk.makeApplicationInner(LoadedApk.java:1395)
                                                  	at android.app.ActivityThread.handleBindApplication(ActivityThread.java:6959)
                                                  	at android.app.ActivityThread.-$$Nest$mhandleBindApplication(Unknown Source:0)
                                                  	at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2236)
                                                  	at android.os.Handler.dispatchMessage(Handler.java:106)
                                                  	at android.os.Looper.loopOnce(Looper.java:205)
                                                  	at android.os.Looper.loop(Looper.java:294)
                                                  	at android.app.ActivityThread.main(ActivityThread.java:8177)
                                                  	at java.lang.reflect.Method.invoke(Native Method)
                                                  	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:552)
                                                  	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:971)
  1. 此时在 issue 中又发现另一个问题,Java8新特性支持时间一直在无限期延迟,这是很大的问题,代码中 jdk 8新特性还是用的比较多的,另外经过多次测试,发现一个严重问题,在 Android14,android 15 系统版本测试反复退出tinker 的 demo,两到三次之后,已经合并的补丁就不生效了。
  2. 因为切换到了美团的 robust 框架,tinker 分析的进度目前卡在这里了。
  3. 接入指南中关于通过命令行差分补丁的流程https://github.com/Tencent/tinker/wiki/Tinker-%E6%8E%A5%E5%85%A5%E6%8C%87%E5%8D%97
1
java -jar tinker-patch-cli.jar -old old.apk -new new.apk -config tinker_config.xml -out output_path

之前好像看到过tinker 框架开发者承诺微信内部用的一定会是和开源版一致的,不知道今天还是不是这样。维护一个开源框架需要耗费大量精力,现在已经有了 ai,效率已经大大提升了却没有出现更加优秀的开源框架,反而老的框架维护慢慢也在放弃,难道未来只有商业化的开源了吗?

本文由作者按照 CC BY 4.0 进行授权