Tinker-让android热更新更靠谱

作者: monkey01 | 来源:发表于2017-11-10 09:45 被阅读203次

Tinker是微信前段时间开源的Android热补丁方案,它支持动态下发代码、So库以及资源,让应用能够在不需要重新安装的情况下实现更新。今天我们就来介绍下Tinker,希望大家能用到自己的项目中,我自己的项目已经使用了,而且在线上已经稳定运行了大半年了,是个人目前用下来最好的android hot fix方案,在这里感谢微信团队🙏🙏🙏,Tinker的github地址为https://github.com/Tencent/tinker

1 常见android热更新方案

目前常用的方案有Native Hook方案,通过在native代码进行方法hook,这种方式最大的问题在于部分手机需要root后才能hook进程,而且功能太弱,是比较早期的热更新方案,现在应该基本没什么人用了;Classloader方案是用的比较多的一种,其实思路和Multidex是一个思路,就是在加载dex的时候优先加载patch.dex用新类覆盖有bug的类;今天我们要介绍的是通过instance Run替换dex的方案,这种方案最大的好处就是兼容性比较好,而且可以实现类的替换也可以实现资源文件的替换。

原理 方案
native Hook方案 AndFix
ClassLoader替换类方案 Nuwa、HotFix
Instance Run冷插拔dex替换 Tinker
测试模块 nativehook Classloader方案 InstanceRun方案
类替换 no yes yes
资源替换 no no yes
是否需要重启 no yes yes
兼容稳定性 不稳定 最好 稳定

这里再贴下tinker官网对各个主流hot fix方案的对比,对比下来还是很不错的:

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体积 较大 较小 较小 较小
成功率 较高 较高 一般 最高

2 Tinker方案设计思想

Tinker的方案对比其他方案为什么会有那么多好处?主要是因为Tinker采用的是全量Dex替换策略,这样不但可以避免ART地址错乱问题,也可以解决在Dalvik上需要插桩的麻烦,tinkerPatch直接使用基准apk包与新编译出来的apk包做差异,得到最终的补丁包。在运行的时候,将差异的patch.dex重新跟原始安装包里的Dex组合为新Dex。在启动的时候ClassLoader会加载最新的Dex,这样就做到了热修复,除了可以用来修复bug,甚至一些new feature也可以使用tinker来发布。为了保证patch.dex比较小,微信团队自研了DexDiff算法可以做到非常小的差量包。为了保证dex合并的性能,Tinker会在后台启动一个patch Process来进行dex合并,让用户感知不到,在下次启动的时候,新的dex就会生效。

这里盗用一张Tinker的原理图,让大家秒懂大概的原理。

https://raw.githubusercontent.com/WeMobileDev/article/master/assets/tinker/wechat.png

3 实施

3.1 引入Tinker

在项目的build.gradle中添加tinker-patch-gradle-plugin依赖

buildscript {
    dependencies {
        classpath ('com.tencent.tinker:tinker-patch-gradle-plugin:1.9.1')
    }
}
dependencies {
    //可选,用于生成application类 
    provided('com.tencent.tinker:tinker-android-anno:1.9.1')
    //tinker的核心库
    compile('com.tencent.tinker:tinker-android-lib:1.9.1') 
}
//apply tinker插件
apply plugin: 'com.tencent.tinker.patch'

3.2 初始化

首先需要定义一个继承自DefaultApplicationLike的类,这个类是com.tencent.tinker.loader.app包下的一个类,可以把这个类当作Application去用,目前我的项目里就是把这个类当作Application去用了。在类的头部需要加上@DefaultLifeCycle注解,用来在编译的时候动态生成SimpleTinkerInApplication这个类,然后需要在app的androidMainfest.xml里设置Application name为注解里设置的动态生成的这个Application类。

@DefaultLifeCycle(application = ".SimpleTinkerInApplication",
        flags = ShareConstants.TINKER_ENABLE_ALL,
        loadVerifyFlag = false)
public class SimpleTinkerInApplicationLike extends ApplicationLike {
    public SimpleTinkerInApplicationLike(Application application, int tinkerFlags, boolean tinkerLoadVerifyFlag, long applicationStartElapsedTime, long applicationStartMillisTime, Intent tinkerResultIntent) {
        super(application, tinkerFlags, tinkerLoadVerifyFlag, applicationStartElapsedTime, applicationStartMillisTime, tinkerResultIntent);
    }

    @Override
    public void onBaseContextAttached(Context base) {
        super.onBaseContextAttached(base);
    }

    @Override
    public void onCreate() {
        super.onCreate();
        TinkerInstaller.install(this);
    }
}

3.3 调用API

在patch下发后,我们可以在一些隐蔽的地方调用Tinker加载patch的方法,我的项目里是放在用户进入app后进行版本检测的时候如果发现服务端有新patch需要更新,则异步下载,在完成下载后调用该方法loadpatch,load完成后Tinker是需要下次启动才会生效的,用户下次再进入app的时候看到的就是打过patch的版本了。

TinkerInstaller.onReceiveUpgradePatch(getApplicationContext(),
                Environment.getExternalStorageDirectory().getAbsolutePath() + "/patch_signed.apk");

3.4 生成patch包

tinker提供了patch生成的工具,源码见:tinker-patch-cli,打成一个jar就可以使用,并且提供了命令行相关的参数以及文件。

执行下面的jar包就可以在output目录生成patch差量包。

java -jar tinker-patch-cli.jar -old old.apk -new new.apk -config tinker_config.xml -out output

在build/output目录下会生成下面这些文件,其中patch_signed_7zip.apk是我们最后发布补丁要用的apk差量文件:

文件名 描述
patch_unsigned.apk 没有签名的补丁包
patch_signed.apk 签名后的补丁包
patch_signed_7zip.apk 签名后并使用7zip压缩的补丁包,也是我们通常使用的补丁包。但正式发布的时候,最好不要以.apk结尾,防止被运营商挟持。
log.txt 在编译补丁包过程的控制台日志
dex_log.txt 在编译补丁包过程关于dex的日志
so_log.txt 在编译补丁包过程关于lib的日志
tinker_result 最终在补丁包的内容,包括diff的dex、lib以及assets下面的meta文件
resources_out.zip 最终在手机上合成的全量资源apk,你可以在这里查看是否有文件遗漏
tempPatchedDexes 在Dalvik与Art平台,最终在手机上合成的完整Dex,我们可以在这里查看dex合成的产物。

3.5 patch分发管理

patch分发涉及到主版本和补丁版本的依赖关系,所以需要在服务端进行管理哪些手机需要推送补丁包,出问题后如何回滚等等问题,补丁包管理可以和自己产品的版本管理结合起来自研,也可以使用Tinker团队开发的patch发布管理平台。

Tinker团队还同步开发了一个patch发布管理的三方平台,对于规模较小的团队或者个人开发者完全可以使用TinkerPatch这个免费的平台进行补丁包的发放和管理,日请求量<1w,赠送的每月cdn流量包是10g,所以一般规模的小app足够使用了。下面是TinkerPatch的地址 http://www.tinkerpatch.com

4 实施注意点

  1. tinker需要在AndroidManifest.xml中指定TINKER_ID;
<application>
  <meta-data
            android:name="TINKER_ID"
            android:value="tinker_id_1234567" />
    //...
</application>
  1. 添加SDCard权限,因为patch会下载到sdcard所以需要sdcard权限,如果你是6.0以上的系统,需要添加上授权代码,或者手动在设置页面打开SDCard读写权限;
  2. 对于项目中自定义了Application的APP需要注意下,建议将原先Application里app初始化的内容都搬迁到新建的ApplicationLike类中,替换掉原先的Application;
  3. 建议直接将tinker github上sample目录中的tinker相关的java代码和gradle和自己的工程内容合并,这样可以很快集成Tinker,避免出现一些问题出现,起码我的项目一开始还不熟的时候是这样实施的。。。后期熟悉Tinker后可以随意灵活使用;
  4. 使用Proguard做混淆的同学还需要注意设置下;
  5. Tinker的常见问题可以参考官网的QA,在使用的过程中遇到的问题基本都涵盖了 官网QA

5 总结

Tinker在我的项目实施的过程中暂时没有遇到不能解决的问题,目前Tinker在项目中主要还是用来修复bug使用,还没有作为new feature发布使用,不过这样的热更效率和稳定性,作为new feature使用也是可以的,自从使用了Tinker后目前还没有遇到以前使用Andfix遇到的一些crash的问题,上了Tinker以后最大的好处就是每次发版后再也不用担心出问题后需要赶急忙慌的修bug去市场上架,再期待着用户点击更新了。。

相关文章

  • Tinker-让android热更新更靠谱

    Tinker是微信前段时间开源的Android热补丁方案,它支持动态下发代码、So库以及资源,让应用能够在不需要重...

  • 微信Tinker-热更新

    使用指南: 在项目根目录下的build.gradle文件中: 在app目录下的build.gradle文件中: 在...

  • 让自己成为一个靠谱的人,很重要!

    让自己成为一个靠谱的人,很重要,哪怕只是看起来靠谱。 上周刚入职了新公司,还是做Android开发,老板让我负责A...

  • 开源集锦

    Android2017 这些技术 —— 你都了解过吗 插件化 热更新 对Android平台,我们通常所说的在线热更...

  • 兄弟连

    兄弟连以“让学员技术靠谱、做人更靠谱”为使命,传承极致的工匠精神,深耕PHP、Java、大数据、Python全栈+...

  • 2020-01-06

    因为靠谱,所以更持久。

  • 什么是靠谱的男人

    什么叫靠谱男人 什么叫靠谱?靠谱即可靠,让人相信,值得托付。 从字意上来讲,靠谱与南阳话的靠弦沾弦类...

  • ReactNative热更新&拆包

    目录 1)全量热更新-Android 2)拆包增量更新-Android 3)图片增量更新-Android 4)全量...

  • android更新

    ## android更新 ## 导航 - ### 热更新 >- [x] 热修复简介 >- [x] 技术原理及特点 ...

  • 怎样让你更靠谱

网友评论

    本文标题:Tinker-让android热更新更靠谱

    本文链接:https://www.haomeiwen.com/subject/ahnvmxtx.html