Tinker与Tinker Patch平台介绍
什么是 Tinker?
Tinker 是一个开源项目(Github链接),它是微信官方的 Android 热补丁解决方案,它支持动态下发代码、So 库以及资源,让应用能够在不需要重新安装的情况下实现更新。
Tinker 的优势
当前市面的热补丁方案有很多,其中比较出名的有阿里的 AndFix、美团的 Robust 以及 QZone 的超级补丁方案。但它们都存在无法解决的问题,具体支持程度如下:
Tinker方案优势
- 不用在构造函数插入代码,防止verify(全量合成Dex以避免verify标志的异常)。
- 支持新增类和资源、so等。
- dexDiff算法使得补丁文件较小。
- gradle支持,再自己定义下可以一键打补丁包。
- 扩展性良好,代码中处处为开发者留出开放接口,简直业界良心。
- 支持多次补丁及补丁清除。
- Application 和其提前加载的类都是可以进行修复的。
Tinker 详细使用文档见 [Tinker Github Wiki]。
Tinker的不足
由于原理与系统限制,Tinker有以下已知问题:
- Tinker不支持修改AndroidManifest.xml,Tinker不支持新增四大组件(1.9.0支持新增非export的Activity);
- 由于Google Play的开发者条款限制,不建议在GP渠道动态更新代码;
- 在Android N上,补丁对应用启动时间有轻微的影响;
- 补丁合成产物比较占手机Rom内存空间。
- 包含多Dex的补丁,需要开启多个进程分别对每个Dex进行合并,比较占用开销。
- 不支持部分三星android-21机型,加载补丁时会主动抛出”TinkerRuntimeException:checkDexInstall failed”;
- 对于资源替换,不支持修改remoteView。例如transition动画,notification icon以及桌面图标。
Tinker的原理及工作流程简述
与其他热更新方案不同的是,tinker使用自研的DexDiff算法生成补丁包(关于DexDiff的亮点见 https://www.zybuluo.com/dodola/note/554061),
然后将补丁包与基线包合并成新的dex文件,从而全量替换原有的dex,而不是像某些热修复方案那样将补丁放到另一个dex中。即全量合成Dex以避免verify标志的异常。
TinkerPatch 平台
使用tinker之后,需要管理自己的补丁包以及对应的基础版本,并且需要开发一套补丁下发的后端服务,并且需要支持开发调试、灰度测试、正式发布等功能,而且需要保证传输安全(毕竟补丁包是直接作用于我们的APP的,被人拦截将是灾难性的打击)。
干这些事情的平台其实有很多,而TinkerPatch平台就是其中之一,而且它是官方推荐的一个平台。它的开发者本身也是来自tinker团队,所以这里面的官方支持程度可想而知。
TinkerPatch 平台帮你做了这些工作,提供了补丁后台托管,版本管理,保证传输安全等功能,让你无需搭建一个后台,无需关心部署操作,只需引入一个 SDK 即可立即使用 Tinker。
此外,通过深入研究 Tinker 源码,TinkerTinkerPatch 平台在 Tinker的基础上加入了以下特性:
- 一键傻瓜式接入;无需理解复杂的热修复原理,一行代码即可接入热修复。实现了自动反射 Appliction 与 Library,使用者无需对自己的项目做任何的改动;
- 补丁管理;实现了热补丁的版本管理,补丁的自动重试与异常时自动回退等功能。同时我们可以简单实现条件下发补丁,在出现异常情况时,我们也可以快速回滚补丁;
- 编译优化;简化了 Tinker 的编译复杂度,实现了备份路径选择,功能开关等功能。
TinkerPatch 平台在 Github 为大家提供了各种各样的 Sample,大家可点击前往 [TinkerPatch Github].
官方对它的优势总结如下:
其他
- 它支持开发预览
- 它支持补丁回滚
- 支持灰度下发、条件下发
- 支持配置具体的补丁拉取策略
- 支持新增Activity,但是不支持新增Service
集成步骤
- 引入tinker patch gradle插件
- 引入tinker patch SDK
- 配置tinker patch
- 在代码中添加支持,设置补丁下发策略、回滚策略、补丁生效机制等等
- 生成基线包,正常打包,由于引入了tinker patch gradle插件,所以打包时会自动生成当前基线包以及附属的文件
- 业务需要、紧急修复,修改代码
- 使用tinkerPatchRelease任务,生成补丁包,该补丁包是相对于指定的基线包而言的
- 在tinker patch后台上传补丁包,选择‘开发调试’模式下发
- 开发调试,测试是否生效,以及是否有其他bug
- 灰度测试
- 正式全量下发
具体实施过程
1. 引入tinker patch gradle插件
在工程根目录
// TinkerPatch 插件
classpath "com.tinkerpatch.sdk:tinkerpatch-gradle-plugin:1.2.8"
2. 引入tinker patch SDK
在moudle的build.gradle文件中加入如下依赖包:
compile "com.android.support:multidex:1.0.3"
//无需引入tinker的任何库,使用tinkerpatch sdk即可
compile("com.tinkerpatch.sdk:tinkerpatch-android-sdk:1.2.8")
3. 配置tinker patch
首先,将官方提供的tinkerpatch.gradle脚本文件放到moudle根目录下(根build.gradle在相同目录),然后在build.gradle中加入:
apply from: 'tinkerpatch.gradle'
configurations.all { resolutionStrategy.cacheChangingModulesFor 0, 'seconds'}
其次,修改tinkerpatch.gralde中的配置:
详细说明见tinkerpatch.gralde文件中的注释。注意,这里面会配置一个appVersion字段,这个字段的值一定要跟在tinker patch平台创建的版本一致
4. 在代码中添加支持,设置补丁下发策略、回滚策略、补丁生效机制等等
首先有两种方式,第一种是修改Application类,将我们的Application类继承DefaultApplicationLike类,然后在其中做配置;第二种是直接在我们现有的Application类中添加代码。
1.获取TinkerPatchApplicationLike对象
tinkerApplicationLike = TinkerPatchApplicationLike.getTinkerPatchApplicationLike();
2.配置:详见官方文档:http://www.tinkerpatch.com/Docs/api
5. 正常打包以生成基线包
注意在打包后,需要将tinker生成的bakApk目录相关文件归档保存。
6. 打补丁包
执行TinkerPatchRelease任务即可。
生成的文件如下:
其中patch_signed_7zip.apk是经过7zip压缩的,不过当补丁文件本身较小的时候,压缩后的包会大于原大小,我们只需要选择最小的那个即可。
7. 上传到tinker patch平台,选择开发调试
其实,集成起来,我们按照上述步骤来就行了。比较简单。关键就是在不同场景需求下能想出对应的解决办法。比如,遇到紧急问题时,我们可以采用上述方式发布补丁,再比如当补丁本身出现问题时,我们可以使用它的回滚功能来回滚补丁。
8. 开发调试
1.首先要将tinkerPatch平台的appkey在代码里设置好
在文件tinkerpatch.gradle中,tinkerpatchSupport后面的闭包里,设置:
2.然后将打好的补丁包上传到tinker patch平台:
http://www.tinkerpatch.com/Apps
上传补丁时选择“开发预览”
是不是简单到你都不想看~~ 那就对了,这就是tinker patch的优势
3.将开发调试工具安装到你要调试的设备上:
以下为官方给的工具及说明:
“由于 Tinker 与代码相关,我们不能通过在代码设置是否为 debug 模式。这里我们提供了 debug 调试工具,它的 Github 地址为 tinkerpatch-debug-tool。 我们也可以通过点击此链接下载。”
4.在debug tool中打开开关,然后重启你的APP,然后你的热更新补丁就会下载、合并到本地。此时可以观察logcat日志,有相关的日志打印出来:
9. 条件下发
1.在代码中添加条件
在发布补丁时,选择条件下发:
注意,在代码中设置条件时,我们设置的是String->String这样的键值对,这里条件下发时,条件写的是test>9,能生效吗?能,因为在比较的时候,tinkerpatch会将之前代码中设置的值转为数值再比较。这里注意两点:
1.代码中设置的条件是可以设置多个的。
2.在选择条件下发时,条件表达式也是可以组合的,具体规则如下:
官方文档中对于条件下发的说明
下发后,在重启APP之后就会有如下的日志打印出来。
然后新的代码就生效了。
另外有个问题
假如,我们在基线包中设置的条件是("test","1"),然后在补丁包中修改了这个值为("test","10"),那么,在下次条件下发补丁的时候,下发条件设置为test>9,这个时候能不能成功下发呢?
答案是,能,因为在前一个补丁中,已经修改了这个值。
10. 补丁回滚
如果我们在下发一个补丁之后,发现修改bug的补丁,自己又产生了bug,也就是改了一个bug之后,同时又写了一个更牛逼的bug😂😂😂,那么这个时候怎么办呢?
有两个办法:
1.如果新的bug只是小问题,而且错误代码的范围是比较小的。那么就简单了。直接再来个补丁就行。
2.但是如果你写的这个bug确实比较牛逼,而且影响范围巨大,比如,合并代码时,合错分支了,而且又比较紧急(比如做了个发红包的活动,。然后如果要修改的话又需要比较久的时间。这个时候如果线上用户再等你修改好再发一个补丁,估计都凉凉了。
虽然tinker很牛逼,但是这种情况还是比较麻烦的。
首先,得在tinker patch后台删除整个基线版本。
然后,在客户端下次重启APP的时候就会执行清理补丁动作,并会将版本回退到基线版本。
然后,等你慢慢整理好代码确保没问题之后,可以使用最新的代码基于最开始的基线版本,重新打个补丁,然后再重新发布。
tinker清除补丁对应日志如下:
参考:https://blog.csdn.net/u010386612/article/details/51077291等等