标签(空格分隔): Android 热更新
Tinker概述
开源地址https://github.com/Tencent/tinker
Tinker是什么
Tinker是微信官方的Android热补丁解决方案,它支持动态下发代码、So库以及资源,让应用能够在不需要重新安装的情况下实现更新。当然,你也可以使用Tinker来更新你的插件。
为什么使用Tinker
当前市面的热补丁方案有很多,其中比较出名的有阿里的AndFix、美团的Robust以及QZone的超级补丁方案。但它们都存在无法解决的问题,这也是正是我们推出Tinker的原因。
-----|Tinker | QZone | AndFix | Robust
-----| ---- | ---- | ----
类替换 |yes |yes |no| no
So替换 |yes |no |no |no
资源替换| yes| yes| no| no
全平台支持 |yes |yes |yes |yes
即时生效 |no| no| yes |yes
性能损耗 |较小 |较大 |较小 |较小
补丁包大小 |较小 |较大 |一般 |一般
开发透明 |yes |yes |no |no
复杂度 |较低 |较低 |复杂 |复杂
gradle支持 |yes |no |no |no
Rom体积 |较大 |较小|较小 |较小
成功率 |较高 |较高 |一般 |最高
总的来说:
-
AndFix
作为native解决方案,首先面临的是稳定性与兼容性问题,更重要的是它无法实现类替换,它是需要大量额外的开发成本的; - Robust兼容性与成功率较高,但是它与AndFix一样,无法新增变量与类只能用做的bugFix方案;
- Qzone方案可以做到发布产品功能,但是它主要问题是插桩带来Dalvik的性能问题,以及为了解决Art下内存地址问题而导致补丁包急速增大的。
-
Tinker
热补丁方案不仅支持类、So以及资源的替换,它还是2.X-7.X的全平台支持。利用Tinker
我们不仅可以用做bugfix,甚至可以替代功能的发布。
PS:
Tinker
可以回退成Qzone
的方案。
Tinker的已知问题
- Tinker不支持修改AndroidManifest.xml,Tinker不支持新增四大组件;
- 由于Google Play的开发者条款限制,不建议在GP渠道动态更新代码;
- 在Android N上,补丁对应用启动时间有轻微的影响;
- 不支持部分三星android-21机型,加载补丁时会主动抛出"TinkerRuntimeException:checkDexInstall failed";
- tinker的一般模式并不支持加固,需要使用usePreGeneratedPatchDex模式,即提前生成补丁模式。某些加固工具可能会将非exported的四大组件类名替换,这些类将无法修改。
流程
1.集成
1.添加gradle依赖
在项目的build.gradle中,添加tinker-patch-gradle-plugin的依赖
buildscript {
dependencies {
classpath ('com.tencent.tinker:tinker-patch-gradle-plugin:1.7.3')
}
}
然后在app的gradle文件app/build.gradle,我们需要添加tinker的库依赖以及apply tinker的gradle插件.
dependencies {
//可选,用于生成application类
provided('com.tencent.tinker:tinker-android-anno:1.7.3')
//tinker的核心库
compile('com.tencent.tinker:tinker-android-lib:1.7.3')
}
...
...
//apply tinker插件
apply plugin: 'com.tencent.tinker.patch'
2.重写Application
1.因为我们的App中自定义了自己的Application,所有需要将自己的Application所有的实现移动到HaibaoApplicationLike,并继承Tinker的DefaultApplicationLike
,并将写上对应的注解。
可见代码如下:
-public class YourApplication extends Application {
+public class HaibaoApplicationLike extends DefaultApplicationLike {
2.需要将自己的Application继承TinkerApplication。需要自己定义一个空构造方法。
这里我们得使用ShareConstants.TINKER_ENABLE_ALL
,对dex
支持和Library
支持。
public class HaibaoApplicationApplication extends TinkerApplication {
public SampleApplication() {
super(
//tinkerFlags, which types is supported
//dex only, library only, all support
ShareConstants.TINKER_ENABLE_ALL,
// This is passed as a string so the shell application does not
// have a binary dependency on your ApplicationLifeCycle class.
//使用自己的ApplicationLike
"tinker.sample.android.app.HaibaoApplicationLike");
}
}
3.使用对应的注解。将Application和ApplicationLike。
@DefaultLifeCycle(
application = "tinker.sample.android.app.HaibaoApplicationApplication ", //application name to generate
flags = ShareConstants.TINKER_ENABLE_ALL) //tinkerFlags above
public class HaibaoApplicationLikeextends DefaultApplicationLike
4.混淆proguard
tinker会自动为你混淆
暂时对更多的配置还不了解,更多的配置见gradle配置。
发布
1.部署方案
Android使用自搭建服务的方式。
处理连续闪退的方案,流程图如下:
需要注意的有如下几点:
1.Anroid在安转补丁后,会清除对应的补丁。
2.补丁包的历史记录和最新补丁的配置文件(如是否强制安转的字段,是否下载完成的字段),建议配置到SD卡的环境中,不会随着APP删除而消失。
- 补丁包需要重启才能生效。为了尽量做到用户无感知。官方的最佳实践:在应用在后台,或者锁屏时,强制杀死APP,使补丁包生效
2.APP版本更新记录
用户热更新是否成功需要返回相应的结果给服务器
2.版本控制
客户端根据当前的版本号,获取对应的patch包。
一个版本可以对应多次的补丁包。每次校验请求得到的是最新的补丁包。
如:本次终端发布的版本是:2.4.0,那在上传脚本文件时,就可以将脚本文件的名称定义为:patch2_4_0_V_1.aby(补丁为apk文件,下载到本地时,修改名字进行安装。)
3.版本回退
安装补丁出现异常。
当设置的重试安装次数达到上限时,进行清除补丁。并向服务器发起一次补丁的请求。安装补丁后出现异常。某些场景出现异常。
对应对应的LOG,进行正常的BUGFIX程序。
即对照log日志,下发新版本的patch文件,供App安装。安装补丁后,APP CRASH无法启动。
具体的实现如下:
- 在Application 的OnCreate方法时启动计数,在CrashHandler中读取计数。如果时间计数小于5s,则Crash计数+1。
- Crash计数>2,开启应急程序。首先校验当前APP是否安装了补丁版本,如果存在则清除安装。并再次重启App.
- 如果当前APP未安转补丁,则开启新的IntentService,向服务器请求补丁文件,如果存在最新的补丁文件,则进入下载。并标记为强制安装。
- App重启时,会先校验本地是否存在下载完成的强制安装补丁。进入补丁安转程序。
- App正常启动程序。
一些回退的代码实现如下:
//当补丁出现异常或者某些情况,我们可能希望清空全部补丁,调用方法为:
Tinker.with(context).cleanPatch();
//当然我们也可以选择卸载某个版本的补丁文件:
Tinker.with(context).cleanPatchByVersion();
在升级版本时我们也无须手动去清除补丁,框架已经为我们做了这件事情。需要注意的是,在补丁已经加载的前提下清除补丁,可能会引起crash。这个时候更好重启一下所有的进程。
监控
1.日常监控:处于正常的LOG日志上报程序中。
难点与疑点
多渠道
由于目前使用的是酷传的分渠道打包,经过验证,及使用方式是在Manifest内修改对应的字段,所以不影响PATCH包的修复。MultiDex
由于Android本身方法数65535的限制,需要进行MultiDex的方式进行对App打包。Tinker需要将复制完整补丁任务的类和直接引用放在MainDex.而如果决定这个MainDex,需要后续继续研究。加固
usePreGeneratedPatchDex模式
。由于加固会改变apk的dex结构,所以生成补丁包时我们务必要使用加固前的apk。
对于360加固,MainActivity由于被提前加载,也无法修复。大家对于加固的情况,请仔细测试,能否支持与加固的方式有关联。灰度发布
请理解,热更新的技术本身的难点和android机型适配的复杂程度。最佳的实践方案是集合对应的灰度发布,针对对应的机型进行发布。这样能够提高相应的稳定性。
对应目前的TINKER版本,目前已知的存在问题的机型;
三星 21 对应版本5.0 : 三星S4 SHV-E330K
- 原理
总的来说,集成任何一种第三方技术,最好还是能将其原理了解清楚。引用原文的话:
Tinker为了实现“高可用”的目标,在接入成本上做了妥协。热补丁并不简单.
后续的问题,还需要不断加深了解和踩坑来度过。