Android热修复之Tinker集成最新详解

前言

该文章属于初级集成详解,侧重Tinker的使用,如若想深入了解其原理请自行查阅相关文档Tinker相关文档

当前市面的热补丁方案有很多,其中比较出名的有阿里的 AndFix、美团的 Robust 以及 QZone 的超级补丁方案,先来做一个对比

 

热修复对比表.png

 

通过对比我们发现Tinker还是有一定的优势。
下面我们就来摆一摆Tinker的用法

1.先去Tinker平台注册一个AppKey,后面会使用到

注册流程

2.添加 gradle 插件依赖

gradle 远程仓库依赖 jcenter

buildscript {
    repositories {
        //mavenLocal()
        google()
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.0.1'
        //无需再单独引用tinker的其他库
        classpath "com.tinkerpatch.sdk:tinkerpatch-gradle-plugin:${TINKERPATCH_VERSION}"
    }
}

3.集成 TinkerPatch SDK

添加 TinkerPatch SDK 库的 denpendencies 依赖

//若使用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 }

4.新建tinkerpatch.gradle tinkerpatch.gradle

为了操作简单,可以直接复制上面链接中的tinkerpatch.gradle放在app目录下
为了简单方便,我们将 TinkerPatch 相关的配置都放于 tinkerpatch.gradle 中
在app的build.gradle中引入

apply from: 'tinkerpatch.gradle'

tinkerpatch.gradle中的baseInfo和variantName可以先不用管,后面使用

def bakPath = file("${buildDir}/bakApk/")
def baseInfo = "app-1.0.0-0115-14-59-51"
def variantName = "debug"

5.配置tinkerpatchSupport参数

1)baseInfo和variantName参数先按照这个放着暂时不管

2)appKey请自行登录tinker官网登录并创建应用获取即可 To: http://www.tinkerpatch.com/

3)appVersion版本号一般对应你的versionName就行了(versionName改的话 这里就改,这里的appVersion对应tinker官网上传patch时的版本,切记!)

/** 可以在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}"

    appKey = "你第一步申请的appkey"

    /** 注意: 若发布新的全量包, 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"

具体的参数详解如下

参数默认值描述
tinkerEnabletrue是否开启 tinkerpatchSupport 插件功能。
appKey""在 TinkerPatch 平台 申请的 appkey, 例如 sample 中的 'f828475486f91936'
appVersion""在 TinkerPatch 平台 输入的版本号, 例如 sample 中的 '1.0.0'。 注意,我们使用 appVersion 作为 TinkerId, 我们需要保证每个发布出去的基础安装包的 appVersion 都不一样。
reflectApplicationfalse是否反射 Application 实现一键接入;一般来说,接入 Tinker 我们需要改造我们的 Application, 若这里为 true, 即我们无需对应用做任何改造即可接入。
autoBackupApkPath""将每次编译产生的 apk/mapping.txt/R.txt 归档存储的位置
baseApkFile""基准包的文件路径, 对应 tinker 插件中的 oldApk 参数;编译补丁包时,必需指定基准版本的 apk,默认值为空,则表示不是进行补丁包的编译。
baseProguardMappingFile""基准包的 Proguard mapping.txt 文件路径, 对应 tinker 插件 applyMapping 参数;在编译新的 apk 时候,我们希望通过保持基准 apk 的 proguard 混淆方式,从而减少补丁包的大小。这是强烈推荐的,编译补丁包时,我们推荐输入基准 apk 生成的 mapping.txt 文件。
baseResourceRFile""基准包的资源 R.txt 文件路径, 对应 tinker 插件 applyResourceMapping 参数;在编译新的apk时候,我们希望通基准 apk 的 R.txt 文件来保持 Resource Id 的分配,这样不仅可以减少补丁包的大小,同时也避免由于 Resource Id 改变导致 remote view 异常。
protectedAppfalse是否开启支持加固,注意:只有在使用加固时才能开启此开关
supportComponentfalse是否开启支持在补丁包中动态增加Activity 注意:新增Activity的Exported属性必须为false�
backupFileNameFormat'${appName}-${variantName}'格式化命名备份文件 这里请使用单引号

上述步骤 配置完之后 sync编译即可

6.初始化 TinkerPatch SDK

以上属性中有一个reflectApplication 属性,所以初始化 TinkerPatch SDK有两种方法

1. reflectApplication = true 的情况

若我们使用 reflectApplication 模式,我们无需为接入 Tinker 而改造我们的 Application 类。相当于自己写一个Application,本人就是使用的这种方式。

public class MyApplication extends Application {
    private ApplicationLike tinkerApplicationLike;

    @Override
    public void onCreate() {
        super.onCreate();
        initTinkerPatch();
    }

    /**
     * 我们需要确保至少对主进程跟patch进程初始化 TinkerPatch
     */
    private void initTinkerPatch() {
        if (BuildConfig.TINKER_ENABLE) {
            // 我们可以从这里获得Tinker加载过程的信息
            // 我们可以从这里获得Tinker加载过程的信息
            tinkerApplicationLike = TinkerPatchApplicationLike.getTinkerPatchApplicationLike();

            // 初始化TinkerPatch SDK, 更多配置可参照API章节中的,初始化SDK
            TinkerPatch.init(tinkerApplicationLike)
                    .reflectPatchLibrary()
                    .setPatchRollbackOnScreenOff(true)
                    .setPatchRestartOnSrceenOff(true)
                    .setFetchPatchIntervalByHours(3);

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

2. reflectApplication = false 的情况

不需要自己写Application类,新建一个集成DefaultApplicationLike的类即可

public class SampleApplicationLike extends DefaultApplicationLike {
   ...
    @Override
    public void onCreate() {
        super.onCreate();
        // 初始化TinkerPatch SDK, 更多配置可参照API章节中的,初始化 SDK
        TinkerPatch.init(this)
            .reflectPatchLibrary()
            .setPatchRollbackOnScreenOff(true)
            .setPatchRestartOnSrceenOff(true)
            .setFetchPatchIntervalByHours(3);

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

setFetchPatchIntervalByHour(3)// 每隔3个小时(通过setFetchPatchIntervalByHours设置)去访问后台时候有更新,通过handler实现轮训的效果
如果你想快点看见效果,可以将这个数字改小点

7.AndroidManifest.xml中完成配置

将AndroidManifest.xml中的添加上相应的网络和SD的权限,还要在application中加上 android:name=".MyApplication"

 <!--tinker修复所需-->
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

    <application
        android:name=".MyApplication"

到现在tinker基本上已经集成完了

8.开始体验

我们在xml里随便写个view以便区分新旧包。

 <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:text="我是旧版"
            android:textSize="30dp" />

 

 

写完之后找到编辑器右侧的Gradle下点击build下的assembleDebug进行编译

                                                

完成后在左侧build查看,最下面就是最新生成的apk

 

                                                

 

生成之后,我们将此debug包安装到手机上,运行效果为我们刚才在xml里写的旧布局

接下来,我们打补丁包(模拟修复bug)

首先到tinkerpatch.gradle里更改咱们先前介绍的两个参数:
baseInfo:修改为上面生成的对应文件夹名(请修改为自己的)
variantName:因为打的debug包,所以传入debug即可

/**
 * TODO: 请按自己的需求修改为适应自己工程的参数
 */
//基包路径
def bakPath = file("${buildDir}/bakApk/")
//基包文件夹名(打补丁包的时候,需要修改)
def baseInfo = "app-1.0.0-0116-11-22-29"(上图中的最后一个app-.....)
//版本名称
def variantName = "debug"

然后我们在xml中做写修改

 <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:text="我是新版"
            android:textSize="30dp" />

然后打出差异包补丁,继续找到Gradle下的tinker目录,点击tinkerPatchDebug进行编译

 

                                           

 

编译完成之后,请到工程目录下app->outputs->查看生成的文件夹 tinkerPatch:

 

                                           


接下来,我们将图中箭头所指的patch_signed_7zip.apk上传至tinker官网(发布补丁):

 

点击图中的补丁下发,然后将上面生成的patch_signed_7zip.apk上传至补丁文件处,点击提交

接下来就是见证奇迹的时刻

退出应用,再次打开应用,显示的就是新的布局文件的内容。

然后到tinker官网,我们可以查看补丁下发进度及当前成功率。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值