Tinker再探之TinkerPatch 平台 第一篇

距离上一次学习Tinker热更新:使用Bugly集成的Tinker已经两年了,现在复习一下Tinker。
Tinker对比阿里的 AndFix、美团的 Robust 以及 QZone 的超级补丁方案

功能/名称 Tinker QZone AndFix Robust
类替换 yes yes no no
So替换 yes no no no
资源替换 yes yes no no
全平台支持 yes yes no yes
即时生效 no no yes yes
性能损耗 较小 较大 较小 较小
补丁包大小 较小 较大 一般 一般
开发透明 yes yes no no
复杂度 较低 较低 复杂 复杂
gradle支持 yes no no no
Rom体积 Dalvik较大 较小 较小 较小
成功率 较高 较高 一般 最高
  • 看官方提供对比其他第三方热修复方案,Tinker综合性能最好。只有及时生效,Rom体积有劣势。成功率不是最高的。及时生效就是用户不用重启应用就会生效,个人觉得一般用户对于应用都会开关很多次,所以这项可以忽略。而Rom体积比较大,用户也感知不出来,所以也可以忽略。要是成功率比Robust,就更完美了。

  • 同时,由于原理与系统限制,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以及桌面图标。

那么什么是TinkerPatch呢?

Tinker 需要使用者有一个后台可以下发和管理补丁包,并且需要处理传输安全等部署工作,TinkerPatch 平台帮你做了这些工作,提供了补丁后台托管,版本管理,保证传输安全等功能,让你无需搭建一个后台,无需关心部署操作,只需引入一个 SDK 即可立即使用 Tinker。

此外,通过深入研究 Tinker 源码,TinkerTinkerPatch 平台在 Tinker的基础上加入了以下特性:

  1. 一键傻瓜式接入;无需理解复杂的热修复原理,一行代码即可接入热修复。实现了自动反射 Appliction 与 Library,使用者无需对自己的项目做任何的改动;
  2. 补丁管理;实现了热补丁的版本管理,补丁的自动重试与异常时自动回退等功能。同时我们可以简单实现条件下发补丁,在出现异常情况时,我们也可以快速回滚补丁;
  3. 编译优化;简化了 Tinker 的编译复杂度,实现了备份路径选择,功能开关等功能。

TinkerPatch 平台在 Github 为大家提供了各种各样的 Sample,大家可点击前往 [TinkerPatch Github].

为什么使用 TinkerPatch 平台?

市面上可能还有其他的一些热补丁服务,为什么我们需要选择 TinkerPatch 平台呢?

  1. 研发实力雄厚;Tinker 在微信的数亿用户上得到验证,它的稳定性与性能值得信赖。TinkerPatch 平台作为 Tinker 项目贡献者与管理者之一,在 Tinker 基础上开发了许多方便使用者的特性;
  2. 服务全面快速;TinkerPatch 平台客户关于热修复使用过程的所有问题在工作日内一个小时内响应,提供您满意的服务;
  3. 稳定可靠;TinkerPatch 平台上传的补丁文件都会保存在七牛云存储上,客户端 APP 只跟七牛服务器通讯,支持高并发,CDN分布全国,速度和稳定性有保证。

TinkerPatch 平台将与 Tinker 一起继续优化,四大组件代理/ABTest/安全模式等功能都将陆续推出,欢迎大家咨询。

第一步 添加 gradle 插件依赖 - 在Project的build.gradle

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

第二步 集成 TinkerPatch SDK

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:appcompat-v7:28.0.0'
    implementation 'com.android.support.constraint:constraint-layout:1.1.3'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'

    //若使用annotation需要单独引用,对于tinker的其他库都无需再引用
    annotationProcessor("com.tinkerpatch.tinker:tinker-android-anno:${TINKER_VERSION}") { changing = true }
    compileOnly("com.tinkerpatch.tinker:tinker-android-anno:${TINKER_VERSION}") { changing = true }
    implementation("com.tinkerpatch.sdk:tinkerpatch-android-sdk:${TINKERPATCH_VERSION}") { changing = true }
}
apply from: 'tinkerpatch.gradle'
  • gradle.properties
TINKER_VERSION=1.9.2
TINKERPATCH_VERSION=1.2.2

第三步 配置 tinkerpatchSupport 参数

在Module的build.gradle同级目录下创建tinkerpatch.gradle:

apply plugin: 'tinkerpatch-support'

/**
 * TODO: 请按自己的需求修改为适应自己工程的参数
 */
def bakPath = file("${buildDir}/bakApk/")
def baseInfo = "app-1.0.0-1112-12-49-34"
def variantName = "debug"

/**
 * 对于插件各参数的详细解析请参考
 * http://tinkerpatch.com/Docs/SDK
 */
tinkerpatchSupport {
    /** 可以在debug的时候关闭 tinkerPatch **/
    /** 当disable tinker的时候需要添加multiDexKeepProguard和proguardFiles,
        这些配置文件本身由tinkerPatch的插件自动添加,当你disable后需要手动添加
        你可以copy本示例中的proguardRules.pro和tinkerMultidexKeep.pro,
        需要你手动修改'tinker.sample.android.app'本示例的包名为你自己的包名, com.xxx前缀的包名不用修改
     **/
    tinkerEnable = true
    reflectApplication = false
    /**
     * 是否开启加固模式,只能在APK将要进行加固时使用,否则会patch失败。
     * 如果只在某个渠道使用了加固,可使用多flavors配置
     **/
    protectedApp = false
    /**
     * 实验功能
     * 补丁是否支持新增 Activity (新增Activity的exported属性必须为false)
     **/
    supportComponent = true

    autoBackupApkPath = "${bakPath}"

    appKey = "f938475486f91936"

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

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

    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}"
    }
}

/**
 * 一般来说,我们无需对下面的参数做任何的修改
 * 对于各参数的详细介绍请参考:
 * https://github.com/Tencent/tinker/wiki/Tinker-接入指南
 */
tinkerPatch {
    ignoreWarning = false
    useSign = true
    dex {
        dexMode = "jar"
        pattern = ["classes*.dex"]
        loader = []
    }
    lib {
        pattern = ["lib/*/*.so"]
    }

    res {
        pattern = ["res/*", "r/*", "assets/*", "resources.arsc", "AndroidManifest.xml"]
        ignoreChange = []
        largeModSize = 100
    }

    packageConfig {
    }
    sevenZip {
        zipArtifact = "com.tencent.mm:SevenZip:1.1.10"
//        path = "/usr/local/bin/7za"
    }
    buildConfig {
        keepDexApply = false
    }
}

同步后,出现错误一:


方法过时,使用新方法

说明Tinker库有的方法过时了,我们可以不理会,或者回退gradle到3.2.1,等Tinker更新这些过时的方法。

tinkerpatch.gradle中我们只需要更改appKey和对应的打包名称baseInfo。其他的一般不需要更改,但有的确实需要更改的,可以参考gradle参数配置详解

第四步 初始化 TinkerPatch SDK

    1. tinkerpatch.gradle中配置参数为reflectApplication = true的情况
public class MyApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        // 我们可以从这里获得Tinker加载过程的信息
       ApplicationLike tinkerApplicationLike = TinkerPatchApplicationLike.getTinkerPatchApplicationLike();
        // 初始化TinkerPatch SDK, 更多配置可参照API章节中的,初始化SDK
        TinkerPatch.init(tinkerApplicationLike)
                .reflectPatchLibrary()
                .setPatchRollbackOnScreenOff(true)
                .setPatchRestartOnSrceenOff(true)
                .setFetchPatchIntervalByHours(3);

        // 每隔3个小时(通过setFetchPatchIntervalByHours设置)去访问后台时候有更新,通过handler实现轮训的效果
        TinkerPatch.with().fetchPatchUpdateAndPollWithInterval();
    }
}

第五步 使用步骤

  • 1.运行 assembleRelease 构建基准包(请在发布前确保更新tinkerpatch.gradle中的appVersion),tinkerPatch会基于你填入的autoBackupApkPath自动备份基础包信息到相应的文件夹,包含:apk文件、R.txt文件和mapping.txt文件 (注:mapping.txt是proguard的产物,如果你没有开启proguard则不会有这个文件)
    双击assembleRelease命令打包

    文件夹名称相当于版本名称appVersion
  • 2.若想发布补丁包, 只需将自动保存下来的文件分别填到tinkerpatch.gradle中的baseApkFile、baseProguardMappingFile和baseResourceRFile 参数中;
  • 3.运行 tinkerPatchRelease task 构建补丁包,补丁包将位于 build/outputs/tinkerPatch下。


    image.png

    image.png

配置差不多完成了,那么配置中的appkey和如何发布可以参考:平台使用说明

运行项目:

  • 错误一:applicationLike must not be null.

原因:是因为配置的tinkerpatch.gradle中的reflectApplication = flase,改为reflectApplication = true

  • 错误二:> old apk F:\project\MLVBSDK-master\Android\TinkerPatchDemo\app\build\bakApk/app-1.0.0-0715-15-35-51/release//app-release.apk is not exist, you must set the correct old apk value!

原因:是因为配置的tinkerpatch.gradle中的baseInfo不正确,改为def baseInfo = app-1.0.0-0715-16-20-04,也就是打的基准包的文件名称

image.png

  • 错误三 we build app apk with apply resource mapping file F:\project\MLVBSDK-master\Android\TinkerPatchDemo\app\build\bakApk/app-1.0.0-0715-16-20-04/release//app-release-R.txt
    原因:原来是我们mapping.txt是proguard的产物,如果你没有开启proguard则不会有这个文件,所以我们注释调映射一行

  • 错误四 can't the get signConfig for this build
    原因:没有配置签名文件,那么配置签名文件吧

    配置签名

  • 错误五:Execution failed for task ':app:tinkerProcessReleaseResourceId'. java.io.FileNotFoundException: F:\project\MLVBSDK-master\Android\TinkerPatchDemo\app\build\intermediates\tinker_intermediates\values_backup
    原因:说是values_backup没找到,解决方案一

经过5连跪,终于出现了官方说的第三步,运行 tinkerPatchRelease task 构建补丁包。所谓的补丁包对应的文件夹。补丁包将位于 build/outputs/tinkerPatch下:

tinkerPatch

我估计patch_signed.apk应该就是补丁包,去TinkerPatch后台把这个包以开发预览的方式发布上去
开发预览

  • 实验一:重启一下应用,没有反应。界面还是只有一个Hello World!,哦,忘记说了,我修改的内容其实就是在布局文件中加了一段话-- 我是补丁包1.0.
  • 实验二:哦,记得要官方下载的DebugTool工具的开关,才能用开发预览模式,打开了,还是无效。


    打开开发模式
  • 实验三:哦,突然想起Application中默认设置的3小时更新补丁,改为立即拉取补丁
 TinkerPatch.with().fetchPatchUpdate(true);
  • 实验四:重启N次,依然无反应,后台去看说是下载补丁包失败,日志中看说是签名不对,这个时候才想起自己是debug包,而打的基础包和补丁包是针对relase包的,所以把这个基础包app-relase.apk传到手机上进行安装,安装后打开第一次还是Hello World~!重启后生效。

经过4连跪,重启应用,总算多了几个字:我是补丁包1.0

我是补丁包1.0

后台看看,确实成功下发了:


实时监控

没错,这就是Tinker的精髓,不重新下载apk,即可实现修改文字的效果。

下一篇Tinker再探之TinkerPatch 平台 第二篇我们将学习1.在线参数获取,2.实时监控,3.图片补丁,4.新增Activity的相关功能

文档参考:TinkerPatch 平台介绍
Demo参考:TinkerPatch相关Demo

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