微信Android热补丁方案Tinker初步使用

Tinker 官方使用文档


本文根据官网文档进行了一次初步使用,从APP的构建到补丁发布完整地介绍了Tinker,用来了解Tinker的使用,参考了官方Demo:

官方 Demo:tinkerpatch-easy-sample

为什么使用Tinker

由于其他热补丁方案还未使用过,不好做出评论,以下引述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下内存地址问题而导致补丁包急速增大的。
特别是在Android N之后,由于混合编译的inline策略修改,对于市面上的各种方案都不太容易解决。而Tinker热补丁方案不仅支持类、So以及资源的替换,它还是2.X-7.X的全平台支持。利用Tinker我们不仅可以用做bugfix,甚至可以替代功能的发布。Tinker已运行在微信的数亿Android设备上,那么为什么你不使用Tinker呢?

下面我们来开始介绍 Tinker 的具体使用,包括以下几个部分:

  • 集成 Tinker 及初始化
  • 构建基准包及生成补丁文件
  • Tinker 平台使用及发布补丁

一、集成 Tinker 及初始化

添加 gradle 插件依赖

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        // TinkerPatch 插件
        classpath "com.tinkerpatch.sdk:tinkerpatch-gradle-plugin:1.1.4"
    }
}

集成 TinkerPatch SDK

dependencies {
    // 若使用annotation需要单独引用,对于tinker的其他库都无需再引用
    provided("com.tencent.tinker:tinker-android-anno:1.7.7")
    compile("com.tinkerpatch.sdk:tinkerpatch-android-sdk:1.1.4")
}

添加 TinkerPatch 配置

为了简单方便,Demo将 TinkerPatch 相关的配置都放于 tinkerpatch.gradle 中,

apply plugin: 'tinkerpatch-support'

/**
 * TODO: 请按自己的需求修改为适应自己工程的参数
 */
def bakPath = file("${buildDir}/bakApk/")
def baseInfo = "app-1.0.0-0314-11-30-49"
def variantName = "debug"
import java.util.regex.Matcher
import java.util.regex.Pattern

/**
 * 对于插件各参数的详细解析请参考
 * http://tinkerpatch.com/Docs/SDK
 */
tinkerpatchSupport {
    /** 可以在debug的时候关闭 tinkerPatch, isRelease() 可以判断BuildType是否为Release **/
    tinkerEnable = true
    reflectApplication = true

    autoBackupApkPath = "${bakPath}"

    /** 需要改为对应的appKey,下文新增APP里说明 **/
    appKey = "5a25479b9aeb2e5e"

    /** 注意: 若发布新的全量包, appVersion一定要更新 **/
    appVersion = "1.0.0"

    def pathPrefix = "${bakPath}/${baseInfo}/${variantName}/"
    def name = "${project.name}-${variantName}"

    /** 基准APK文件 **/
    baseApkFile = "${pathPrefix}/${name}.apk"
    baseProguardMappingFile = "${pathPrefix}/${name}-mapping.txt"
    baseResourceRFile = "${pathPrefix}/${name}-R.txt"

    /**
     *  若有编译多flavors需求, 可以参照: https://github.com/TinkerPatch/tinkerpatch-flavors-sample
     *  注意: 除非你不同的flavor代码是不一样的,不然建议采用zip comment或者文件方式生成渠道信息(相关工具:walle 或者 packer-ng)
     **/
}

/**
 * 用于用户在代码中判断tinkerPatch是否被使能
 */
android {
    defaultConfig {
        buildConfigField "boolean", "TINKER_ENABLE", "${tinkerpatchSupport.tinkerEnable}"
    }
}

app/build.gradle 中引入 tinkerpatch.gradle

apply from: 'tinkerpatch.gradle'

初始化 TinkerPatch SDK

public class MyApplication extends Application {
    ApplicationLike tinkerAppLike;

    @Override
    protected void attachBaseContext(Context base) {
        super.attachBaseContext(base);
        MultiDex.install(base);
    }

    @Override
    public void onCreate() {
        super.onCreate();
        if (BuildConfig.TINKER_ENABLE){
            tinkerAppLike = TinkerPatchApplicationLike.getTinkerPatchApplicationLike();
            TinkerPatch.init(tinkerAppLike)
                    //是否自动反射Library路径,无须手动加载补丁中的So文件
                    //注意,调用在反射接口之后才能生效,你也可以使用Tinker的方式加载Library
                    .reflectPatchLibrary()
                    //设置收到后台回退要求时,锁屏清除补丁
                    //默认是等主进程重启时自动清除
                    .setPatchRollbackOnScreenOff(true)
                    //设置补丁合成成功后,锁屏重启程序
                    //默认是等应用自然重启
                    .setPatchRestartOnSrceenOff(true);
                 
        }
        // 每隔一小时检查一次,按自己需求设定
        new FetchPatchHandler().fetchPatchWithInterval(1);
    }
}
    ...

最后在AndroidManifest.xml中设置MyApplication:

<application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:name=".MyApplication"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

至此Demo已经构建完成,下面就开始进行补丁包的构建与发布。


二、构建基准包及生成补丁文件

首先直接运行task assembleRelease,此时即可在build文件夹内出现bakApk文件夹,里面存放的是每次编译的APK文件,也就是完整的APP安装包。

基准包文件

并且我们可以看到在build/bakApk文件夹内已经生成了三个文件:


build/bakApk文件夹

执行assembleDebug 没有mapping文件。

生成补丁文件

现在需要生成上面的基准包APK的补丁文件。作为测试Demo我们这里随便改动TextView文字

    <!--Hello World 改为 Hello World!!!!!!!!!!!-->
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!!!!!!!!!!!" />

改好代码后,我们开始生成补丁包:


这里需要我们在tinkerpatch.gradle文件中配置三个文件路径:

  • baseApkFile:基准APK文件
  • baseProguardMappingFile:基准包的 Proguard mapping.txt 文件路径
  • baseResourceRFile:基准包的资源 R.txt 文件路径

而在官方的tinkerpatch.gradle文件中已经帮我们配置好基本路径:

  baseApkFile = "${pathPrefix}/${name}.apk"
// 这里tinkerPatchDubug和tinkerPatchRelease不同的是tinkerPatchRelease需要配置mapping文件,否则task会失败
  baseProguardMappingFile = "${pathPrefix}/${name}-mapping.txt"
  baseResourceRFile = "${pathPrefix}/${name}-R.txt"

我们只需要将tinkerpatch.gradle文件中baseInfo = "app-1.0.0-0314-11-30-49"值改成要生成补丁的基准包所在文件夹名称即可(即上文bakApk文件夹下基准包文件夹名称,选择哪个文件夹生成的补丁就是基于对应的基准包)。

接下来就执行tinkerPatchRelease task开始生成补丁文件了:

tinkerPatchRelease task

需要耐心等待一会,执行结束会在outputs文件夹内生成tinkerPatch文件夹:

生成的补丁文件夹

该文件夹内文件还是挺多的, patch_signed_7zip.apk 既是我们要的补丁包。


三、Tinker 平台使用及发布补丁

首先登录Tinker 平台注册账号,然后需要经过3个步骤即可完成补丁包的发布:

  • 新增APP
  • 添加版本
  • 发布补丁

新增APP

新增APP

若首次使用点击新增APP后,输入APP的名称,名称可以再次修改。此时会生成对应的appKey(如下图左侧),需要将key填入到 tinkerpatch.gradle 中: appKey = "5a25479b9aeb2e5e"

添加版本

添加版本

输入需要打补丁的基准APP的版本号,不同的版本因为迭代的原因补丁也不相同,需要前期做好规划。

发布补丁

发布补丁

需要对应APP版本对应的补丁文件,既是我们上文中提到的 patch_signed_7zip.apk文件。

测试结果

经过了大约20分钟看到了测试机补丁merge成功,没有立即看到效果的可以等等:

Hello World 已被改为 Hello World!!!!!!!!!!!

补丁详情里可以查看该补丁的信息:


补丁详情

平台也提供了实时的数据监控,方便及时了解补丁的安装情况:


实时监控

Tinker的已知问题

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

  • Tinker不支持修改AndroidManifest.xml,Tinker不支持新增四大组件;
  • 由于Google Play的开发者条款限制,不建议在GP渠道动态更新代码;
  • 在Android N上,补丁对应用启动时间有轻微的影响;
  • 不支持部分三星android-21机型,加载补丁时会主动抛出"TinkerRuntimeException:checkDexInstall failed";
  • 由于各个厂商的加固实现并不一致,在1.7.6以及之后的版本,tinker不再支持加固的动态更新;
  • 对于资源替换,不支持修改remoteView。例如transition动画,notification icon以及桌面图标。

以上就是一个Tinker完整的使用过程,并没有涉及到原理及深入使用,希望对大家有所帮助!
本文的Demo

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 221,548评论 6 515
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,497评论 3 399
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 167,990评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,618评论 1 296
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,618评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,246评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,819评论 3 421
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,725评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,268评论 1 320
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,356评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,488评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,181评论 5 350
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,862评论 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,331评论 0 24
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,445评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,897评论 3 376
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,500评论 2 359

推荐阅读更多精彩内容