前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >Android架构之路--热更新Tinker(上)

Android架构之路--热更新Tinker(上)

原创
作者头像
conanma
修改于 2021-09-06 02:09:28
修改于 2021-09-06 02:09:28
1.8K00
代码可运行
举报
文章被收录于专栏:正则正则
运行总次数:0
代码可运行

一、简介

当前市面的热补丁方案有很多,其中比较出名的有阿里的 AndFix、美团的 Robust 以及 QZone 的超级补丁方案。但它们都存在无法解决的问题,这也是正是最后使用 Tinker 的原因。先看一张图对比:

1-1:热更新对比图

Tinker热补丁方案不仅支持类、So 以及资源的替换,它还是2.X-7.X的全平台支持。利用Tinker我们不仅可以用做 bugfix,甚至可以替代功能的发布。Tinker已运行在微信的数亿Android设备上。

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

Tinker原理图

1-2:原理图

Tinker流程图

1-3:Tinker 流程图

二、Tinker相关网站

微信Tinker Patch官网:Tinker Patch Github地址:tinker

三、接入Tinker步骤

基础步骤

  • 注册Tinker账户、添加APP、记录AppKey,添加 APP 版本、 发布补丁。详细步骤请移步Tinker平台使用文档

主要来说下配置Gradle和代码

1. 配置Tinker版本信息

我们使用配置文件去配置Tinker版本信息,易于统一版本和后面更换版本,如图:

2-1 gradle.properties文件

代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
TINKER_VERSION=1.9.6
TINKERPATCH_VERSION=1.2.6

2. 使用Tinker插件

在根目录下的build.gradle文件下配置,如图:

2-2 添加Tinker插件

代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
classpath "com.tinkerpatch.sdk:tinkerpatch-gradle-plugin:${TINKERPATCH_VERSION}"

3. 配置Tinker的gradle脚本

在项目app目录下新建tinkerparch.gradle文件,如图:

2-3 tinkerpatch.gradle

代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
apply plugin: 'tinkerpatch-support'
/**
 * TODO: 请按自己的需求修改为适应自己工程的参数
 */
def bakPath = file("${buildDir}/bakApk/")
def baseInfo = "app-1.0.0-0529-14-38-02"
def variantName = "release"
/**
 * 对于插件各参数的详细解析请参考
 * 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 = true
    /**
     * 是否开启加固模式,只能在APK将要进行加固时使用,否则会patch失败。
     * 如果只在某个渠道使用了加固,可使用多flavors配置
     **/
    protectedApp = false
    /**
     * 实验功能
     * 补丁是否支持新增 Activity (新增Activity的exported属性必须为false)
     **/
    supportComponent = true

    autoBackupApkPath = "${bakPath}"
    /** 注意:换成自己在Tinker平台上申请的appKey**/
    appKey = "521db2518e0ca16d"

    /** 注意: 若发布新的全量包, 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-
 * %E6%8E%A5%E5%85%A5%E6%8C%87%E5%8D%97
 */
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
    }
}

注意

  • AppKey:换成自己在Tinker平台上申请的。
  • baseInfo:基准包名称,使用Tinker脚本编译在模块的build/bakApk生成编译副本。
  • variantName: 这个一般对应buildTypes里面你基准包生成的类型,release、debug或其他
  • appVersion:配置和Tinker后台新建补丁包的一致。

其他地方可以暂时不用改

4. 配置模块下的build.gradle

配置签名

如果有不会的同学可以看这篇 Android Studio的两种模式及签名配置

2-4:配置签名

在配置混淆代码的时候,想要提醒下大家,当设置 minifyEnabled 为false时代表不混淆代码,shrinkResources也应设置为false ,它们通常是彼此关联。 要是你设置minifyEnabled 为false,shrinkResources为true,将会报异常,信息如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Error:A problem was found with the configuration of task':watch:packageOfficialDebug'.
File '...\build\intermediates\res\resources-official-debug-stripped.ap_' specified for property 'resourceFile' does not exist.

2-4-1:混淆配置

配置依赖

2-5:配置Tinker依赖

使用插件

2-6:使用Tinker插件

具体代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
apply plugin: 'com.android.application'
apply from: 'tinkerpatch.gradle'

android {
    compileSdkVersion 25
    buildToolsVersion "25.0.3"
    defaultConfig {
        applicationId "qqt.com.tinkerdemo"
        minSdkVersion 17
        targetSdkVersion 25
        versionCode 1
        versionName "1.0.0"
        multiDexEnabled true
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    signingConfigs {
        release {
                storeFile file("./jks/tinker.jks")
                storePassword "123456"
                keyAlias "tinker"
                keyPassword "123456"

        }
        debug {
            storeFile file("./jks/debug.keystore")
        }
    }
    buildTypes {
        release {
            minifyEnabled false
            signingConfig signingConfigs.release
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
        debug {
            signingConfig signingConfigs.debug
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    compile 'com.android.support:appcompat-v7:25.3.1'
    compile 'com.android.support.constraint:constraint-layout:1.0.2'
    testCompile 'junit:junit:4.12'

    annotationProcessor("com.tinkerpatch.tinker:tinker-android-anno:${TINKER_VERSION}") {
        changing = true
    }
    provided("com.tinkerpatch.tinker:tinker-android-anno:${TINKER_VERSION}") {
        changing = true
    }
    compile("com.tinkerpatch.sdk:tinkerpatch-android-sdk:${TINKERPATCH_VERSION}") {
        changing = true
    }

    compile 'com.android.support:multidex:1.0.1'
}

5. 代码集成

最后一步,在自己的代码新建一个Application,把代码集成在App中,别忘了在AndroidManifest里面配置APP。。。 如图:

2-7:集成代码

我是继承MultiDexApplication主要是防止64k异常。有关这块知识,请看 Android 方法数超过64k、编译OOM、编译过慢解决方案 具体代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package qqt.com.tinkerdemo;

import android.support.multidex.MultiDexApplication;

import com.tencent.tinker.loader.app.ApplicationLike;
import com.tinkerpatch.sdk.TinkerPatch;
import com.tinkerpatch.sdk.loader.TinkerPatchApplicationLike;

/**
 * 邮箱:ljh12520jy@163.com
 *
 * @author Ljh on 2018/5/28
 */

public class App extends MultiDexApplication {

    private ApplicationLike mApplicationLike;

    @Override
    public void onCreate() {
        super.onCreate();
        mApplicationLike = TinkerPatchApplicationLike.getTinkerPatchApplicationLike();
        // 初始化TinkerPatch SDK, 更多配置可参照API章节中的,初始化SDK
        TinkerPatch.init(mApplicationLike)
                .reflectPatchLibrary()
                .fetchPatchUpdate(true)
                // 强制更新
                .setPatchRollbackOnScreenOff(true)
                .setPatchRestartOnSrceenOff(true)
                .setFetchPatchIntervalByHours(3);

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

四、生成基准包

在生成基准包的时候,要注意一个问题,就是关闭 instant run(当tinkerEnable = true时,false的时候,就不需要),如图:

3-1:关闭InstantRun

Android Studio的右上角,点击Gradle,如图:

3-2:准备生成基准包

双击assembleRelease生成成功后安装模块/build/outputs/apk/release/app-release.apk就OK了,这时候进去模块/build/bakApk里面记录一下类似app-1.0.0-0530-18-01-59的文件名称,只生成一次基准包,那么就会生成一个。这里需要注意一下,如果点太多生成太多的话确定不了刚刚生成的是哪个,那么就选最新那个或者删掉重新生成基准包。 生成后的基准包如图:

3-3:生成基准包

五、修改bug

在自己的代码中随便修改点代码(Tinker1.9.6 里面支持新增Activity代码)

六、生成补丁包

在生成补丁包前,我们需要去tinkerpatch.gradle文件下修改一些信息。

  • baseInfo :把前面app-1.0.0-0529-14-38-02换成我们刚生成记录下的基准包(app-1.0.0-0530-18-01-59)就可以。
  • variantName : 因为刚刚我们使用assembleRelease生成的补丁,所以我们只需要使用release

双击TinkerPatchRelease生成差分包,patch_signed_7zip.apk就是补丁包

生成的补丁包如图:

3-4:生成补丁包

3-5:tinkerPatch下的一些文件说明

七、发布补丁包

回到Tinker后台,选中我们开始新建的项目,补丁下发->添加APP版本。然后上传刚刚的patch_signed_7zip.apk。

APP开启强制更新的话那么重启应用就会更新,否则会通过轮询去更新。应用重启才生效。

3-6:发布补丁包

注:在Tinker后台发布的差分包(补丁包)是根据app-1.0.0-0530-18-01-59为基准包下,修复bug生成的补丁包,只对于app-1.0.0-0530-18-01-59版本的apk生效。

3-7:差分包


看到这里已经我们已经集成Tinker热更新成功,下篇将讲解基于Tinker实现多渠道打包发布Android架构之路--热更新Tinker(下)

参考文章

Android热更新利器Tinker接入 一次集成使用Tinker热更新的体验 Tinker爬坑之路 Android实战——Tinker的集成和使用

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
作者已关闭评论
暂无评论
推荐阅读
编辑精选文章
换一批
spring的自定义标签都不会?你可能只学到了spring的皮毛
通常我们在applicationContext.xml文件中使用spring的标签时,会发现spring默认支持的只有5种,如图所示
苏三说技术
2020/10/15
1.3K0
spring的自定义标签都不会?你可能只学到了spring的皮毛
【死磕 Spring】----- IOC 之解析自定义标签
在博客 【死磕Spring】----- IOC 之 注册 BeanDefinition 中提到:获取 Document 对象后,会根据该对象和 Resource 资源对象调用 registerBeanDefinitions() 方法,开始注册 BeanDefinitions 之旅。在注册 BeanDefinitions 过程中会调用 parseBeanDefinitions() 开启 BeanDefinition 的解析过程。在该方法中,它会根据命名空间的不同调用不同的方法进行解析,如果是默认的命名空间,则调用 parseDefaultElement() 进行默认标签解析,否则调用 parseCustomElement() 方法进行自定义标签解析。前面 6 篇博客都是分析默认标签的解析工作,这篇博客分析自定义标签的解析过
用户1655470
2018/11/23
6390
Spring源码初探-IOC(2)-Bean的初始化-自定义标签解析
前面一文介绍的是Spring对于DefaultElement的解析,例如bean/import/alias等,但是在Spring体系中也存在很多扩展标签,例如事务、aop等非Default标签。按一般的套路通常是先介绍在Spring体系下如何在XML配置文件中自定义标签,本文先介绍Spring对于自定义标签的解析过程,在知道了Spring怎么“读”XML配置之后,写其能“读懂”的配置就显得非常自然了。
LNAmp
2018/09/05
4110
Spring源码初探-IOC(2)-Bean的初始化-自定义标签解析
Spring5 扩展篇之自定义xml标签
首先这个文件最好建立在静态资源resource文件夹下,我为了方便都将文件建立在了resource/META-INF下了,包括spring.handlers和spring.schemas这三个文件都在该目录下:
@派大星
2023/06/28
3090
Spring5 扩展篇之自定义xml标签
Spring解密 - 自定义标签与解析
在 上一节 Spring解密 - 默认标签的解析 中,重点分析了 Spring 对 默认标签是如何解析的,那么本章继续讲解标签解析,着重讲述如何对 自定义标签进行解析。
battcn
2018/08/03
6040
Spring解密 - 自定义标签与解析
Spring的BeanDefinition解析
在Spring生成bean的过程中,我们提到了Spring会先加载配置文件中的BeanDefinition,然后才会getBean。像普通的<bean>标签,我们也能写一个简单的解析工具将它转换为BeanDefinition,而像<context:component-scan>这样非基本的bean定义又是怎么解析的呢?
zhangheng
2020/04/29
7590
【DUBBO】 Schema解析Spring扩展机制集成Spring
dubbo是如何做到与spring集成的?这都依赖于Spring提供的XML Schema可扩展机制,用户可以自定义XML Schema文件,并自定义XML Bean解析器,并集成到SpringIOC容器中。 创建自定义扩展,主要有以下步骤: 1、创建XML Schema 文件,描述自定义的合法构建模块,也就是xsd文件,主要用于定义数据约束; 2、自定义个处理器类,并实现NamespaceHandler接口,在里面注册各个标签对应的BeanDefinitionParser; 3、自定义一个或多个解析器,实现BeanDefinitionParser接口,用于定义Bean的解析逻辑;
spilledyear
2018/12/19
1.1K0
聊聊自定义SPI如何使用自定义标签注入到spring容器中
之前我们聊过自定义的SPI如何与spring进行整合,今天我们就来聊下如何通过自定义标签将spi对象注入到spring容器中
lyb-geek
2021/11/25
6620
聊聊自定义SPI如何使用自定义标签注入到spring容器中
这一次搞懂Spring自定义标签以及注解解析原理
在上一篇文章中分析了Spring是如何解析默认标签的,并封装为BeanDefinition注册到缓存中,这一篇就来看看对于像context这种自定义标签是如何解析的。同时我们常用的注解如:@Service、@Component、@Controller标注的类也是需要在xml中配置<context:component-scan>才能自动注入到IOC容器中,所以本篇也会重点分析注解解析原理。
夜勿语
2020/09/07
5420
缘起 Dubbo ,讲讲 Spring XML Schema 扩展机制
在 Dubbo 中,可以使用 XML 配置相关信息,也可以用来引入服务或者导出服务。配置完成,启动工程,Spring 会读取配置文件,生成注入 相关 Bean。那 Dubbo 如何实现自定义 XML 被 Spring 加载读取?
andyxh
2019/09/10
5660
缘起 Dubbo ,讲讲 Spring XML Schema 扩展机制
Spring中的XML schema扩展机制
很久没有写关于 Spring 的文章了,最近在系统梳理 Dubbo 代码的过程中发现了 XML schema 这个被遗漏的知识点。由于工作中使用 SpringBoot 比较多的原因,几乎很少接触 XML,此文可以算做是亡羊补牢,另一方面,也为后续的 Dubbo 源码解析做个铺垫。
kirito-moe
2018/09/30
1.2K0
Spring中的XML schema扩展机制
Spring源码分析(二)Spring怎么扩展解析xml接口的
https://blog.csdn.net/bingduanlbd/article/details/38770685
石臻臻的杂货铺[同名公众号]
2021/07/14
2700
Elastic-Job2.1.5源码-自定义Spring标签与Spring 依赖注入无缝整合
大家好,本文给大家简单介绍一下Elastic-Job 是如何自定义标签与与Spring 依赖注入无缝整合
宋小生
2022/12/14
6800
(三)Spring源码解析:自定义标签解析
步骤3:创建BeanDefinitionParser接口的实现类,用来解析XSD文件中的定义和组件定义。
爪哇缪斯
2023/05/10
1630
(三)Spring源码解析:自定义标签解析
【死磕 Spring】----- IOC 之解析 bean 标签:解析自定义标签
前面四篇文章都是分析 Bean 默认标签的解析过程,包括基本属性、六个子元素(meta、lookup-method、replaced-method、constructor-arg、property、qualifier),涉及内容较多,拆分成了四篇文章,导致我们已经忘记从哪里出发的了,勿忘初心。
用户1655470
2018/10/22
5980
Spring 实现自定义 bean 的扩展
Spring mvc 提供了扩展 xml 的机制,用来编写自定义的 xml bean ,例如 dubbo 框架,就利用这个机制实现了好多的 dubbo bean,比如 <dubbo:applicati
古时的风筝
2018/01/08
9730
Spring 实现自定义 bean 的扩展
Sring源码解析(一)Spring是怎么读取配置Xml文件的
在XmlBeanDefinitionReader.doLoadBeanDefinitions(InputSource inputSource, Resource resource)方法中将Xml文件转换成Document对象; Document doc = doLoadDocument(inputSource, resource);
石臻臻的杂货铺[同名公众号]
2021/07/14
6400
【Spring源码】- 07 扩展点之自定义标签
Spring中正逐渐采用注解方式取代XML配置方式,所以,使用XML配置的机会正越来越少。然后,如果你开发的工具模块可能会被很多系统使用,考虑到兼容性问题,就需要提供XML方式集成,这时就需要自定义标签;还有,你在看一些开源源码时,一般也是提供自定义标签方式集成。所以,还是可以去了解一下自定义标签实现。
Reactor2020
2023/03/22
2810
【Spring源码】- 07 扩展点之自定义标签
Dubbo系列笔记之XML配置文件解析流程
Spring通过XML解析程序将其解析为DOM树,通过NamespaceHandler指定对应的Namespace的BeanDefinitionParser将其转换成BeanDefinition。再通过Spring自身的功能对BeanDefinition实例化对象。Dubbo做的只是实现了NamespaceHandler解析成BeanDefinition。
用户5546570
2020/11/12
1.1K0
Dubbo系列笔记之XML配置文件解析流程
基于Spring的可扩展Schema进行开发自定义配置标签支持
  最近和朋友一起想开发一个类似alibaba dubbo的功能的工具,其中就用到了基于Spring的可扩展Schema进行开发自定义配置标签支持,通过上网查资料自己写了一个demo.今天在这里进行和大家分享,也记录下方便以后复习备忘。
阿豪聊干货
2018/08/09
3750
基于Spring的可扩展Schema进行开发自定义配置标签支持
推荐阅读
相关推荐
spring的自定义标签都不会?你可能只学到了spring的皮毛
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验