Tinker热修复接入

在app上集成tinker,根据 tinker上的wiki 的指示操作即可。

具体步骤如下:

gradle接入

gradle是推荐的接入方式,在gradle插件tinker-patch-gradle-plugin中我们帮你完成proguard、multiDex以及Manifest处理等工作。

添加gradle依赖

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

buildscript {
    dependencies {
        classpath ('com.tencent.tinker:tinker-patch-gradle-plugin:1.9.1')
    }
}

然后在app的gradle文件app/build.gradle,我们需要添加tinker的库依赖以及apply tinker的gradle插件.

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'

tinkerPatch task详解

直接使用task:tinkerPatchVariantName(例如tinkerPatchDebug、tinkerPatchRelease)即可自动根据Variant选择相应的编译类型,同时它还贴心的为我们完成以下几个操作:

  1. 将TINKER_ID自动插入AndroidManifest的meta项,输出路径为build/intermediates/tinker_intermediates/AndroidManifest.xml;

  2. 如果minifyEnabled为true,将自动将Tinker的proguard规则添加到proguardFiles中,输出路径为build/intermediates/tinker_intermediates/tinker_proguard.pro,这里你不需要将它们拷贝到自己的proguard配置文件中;

  3. 如果multiDexEnabled为true,将自动生成Tinker需要放在主dex的keep规则。在tinker 1.7.6版本之前,你需要手动将生成规则拷贝到自己的multiDexKeepProguard文件中。例如Sample中的multiDexKeepProguard file("keep_in_main_dex.txt")。在1.7.6版本之后,这里会通过脚本自动处理,无须手动填写。

  4. 把dexOptions的jumboMode打开。

dexOptions {
     jumboMode = true
 }

输出路径为:build/intermediates/tinker_intermediates/tinker_multidexkeep.pro。 后你可以在build/outputs/tinkerPatch中找到输出的文件。

多Flavor打包

有的时候我们希望通过flavor方式打包,在sample中提供了简单的用法事例:

  1. 通过flavor编译,这个时候我们可以看到bakApk路径是一个按照flavor名称区分的目录;

  2. 将编译目录路径填写到sample中tinkerBuildFlavorDirectory,其他的几个字段不需要填写,这里会自动根据路径拼接;

ext {
    tinkerBuildFlavorDirectory = "${bakPath}/app-1014-13-35-12"
}
  1. 运行tinkerPatchAllFlavorDebug或者tinkerPatchAllFlavorRelease即可得到所有flavor的补丁包。

注:
对于渠道包,如果不是需要使用热修复,那么怎么生成渠道包都可以的。
对于flavor编译渠道包,会导致不同的渠道包由于BuildConfig变化导致classes.dex差异,这种方案是不可取的。
将渠道信息写在apk文件的zip comment中,是非常推荐的,例如可以使用项目 packer-ng-plugin 或者可使用V2 Scheme的 walle , 也包括最新出来的多渠道打包神器 ApkChannelPackage ,说一下区别,如果要使用热修复的话,对于不需要加固的app,那么生成渠道包,这三种方案都可以采用;对于要加固的app,只能采用ApkChannelPackage这种方案中的根据已有APK生成渠道包。 这篇文章 对多渠道打包工具对比做了详细的区分。目前采用的也是ApkChannelPackage方案。

Sample的使用方法

Demo请参考tinker-sample-android, 它的使用方法如下:

  1. 调用assembleDebug编译,我们会将编译过的包保存在build/bakApk中。然后我们将它安装到手机,点击SHOW INFO按钮,可以看到补丁并没有加载.

    Tinker热修复接入_第1张图片

  2. 修改代码,例如将MainActivity中I am on patch onCreate的Log打开。然后我们需要修改build.gradle中的参数,将步骤一编译保存的安装包路径拷贝到tinkerPatch中的oldApk参数中。

    Tinker热修复接入_第2张图片

  3. 调用tinkerPatchDebug, 补丁包与相关日志会保存在/build/outputs/tinkerPatch/。然后我们将patch_signed_7zip.apk推送到手机的sdcard中。

    adb push ./app/build/outputs/tinkerPatch/debug/patch_signed_7zip.apk /storage/sdcard0/
    
  4. 点击LOAD PATCH按钮, 如果看到patch success, please restart process的toast,即可锁屏或者点击KILL SELF按钮

    Tinker热修复接入_第3张图片

  5. 我们可以看到的确出现了I am on patch onCreate日志,同时点击SHOW INFO按钮,显示补丁包的确已经加载成功了。

    Tinker热修复接入_第4张图片

Release的使用方法

Tinker的使用方式如下,以gradle接入的release包为例:

  1. 每次编译或发包将安装包与mapping文件备份;
  2. 若有补丁包的需要,按自身需要修改你的代码、库文件等;
  3. 将备份的基准安装包与mapping文件输入到tinkerPatch的配置中;
  4. 运行tinkerPatchRelease,即可自动编译最新的安装包,并与输入基准包作差异,得到最终的补丁包。

调试源码

tinker调试源码非常简单,大家需要在tinker的主工程运行tinker group中buildAndPublishTinkerToLocalMaven任务即可。

此外由于localmaven无法传递依赖,需要在使用的地方再显式引用以下库:

compile("com.tencent.tinker:tinker-android-loader:${TINKER_VERSION}") { changing = true }
compile("com.tencent.tinker:aosp-dexutils:${TINKER_VERSION}") { changing = true }
compile("com.tencent.tinker:bsdiff-util:${TINKER_VERSION}") { changing = true }
compile("com.tencent.tinker:tinker-commons:${TINKER_VERSION}") { changing = true }

github/Tinker的默认分支为master分支,几个含义的含义分别是:

  1. master分支;最近一次release的稳定代码,我们在master分支打tag;
  2. dev分支;开发分支,这里会包含下一个版本的代码,我们只能给dev分支提pr以及验证部分已经修复的issue;
  3. hotfix分支;为了修复tinker紧急bug的分支。

关于tinker分支管理、issue以及pr规范,请阅读Tinker Contributing Guide。

为了将tinker单独分块更清晰,可以将tinker相关的代码整理到 tinkerpatch.gradle 中

加固支持

从1.7.8开始,tinker又支持加固了,只需要修改tinkerpatch.gradle中的这部分

buildConfig {
            applyMapping = getApplyMappingPath()
            applyResourceMapping = getApplyResourceMappingPath()
            tinkerId = getTinkerIdValue()
            keepDexApply = false

            isProtectedApp = true //开启加固
            ...
        }

补丁管理后台:

https://github.com/baidao/tinker-manager

一、集成Tinker app/build.gradle 配置,参考官方 sample,也可以参考SDK里的 sample

二、集成SDK

  1. app/build.gradle
repositories {
    jcenter()
}

dependencies {
    ...
    compile 'com.dx168.patchsdk:patchsdk:1.2.6'
}
  1. ApplicationLike
@SuppressWarnings("unused")
@DefaultLifeCycle(application = "com.dx168.patchsdk.sample.MyApplication",
        flags = ShareConstants.TINKER_ENABLE_ALL,
        loadVerifyFlag = false)
public class MyApplicationLike extends TinkerApplicationLike {

    private OriginalApplication originalApplication;

    public MyApplicationLike(Application application, int tinkerFlags, boolean tinkerLoadVerifyFlag, long applicationStartElapsedTime, long applicationStartMillisTime, Intent tinkerResultIntent) {
        super(application, tinkerFlags, tinkerLoadVerifyFlag, applicationStartElapsedTime, applicationStartMillisTime, tinkerResultIntent);
        originalApplication = new OriginalApplication();
    }

    @Override
    public void onCreate() {
        super.onCreate();
        String appId = "20170112162040035-6936";
        String appSecret = "d978d00c0c1344959afa9d0a39d7dab3";
        PatchManager.getInstance().init(getApplication(), "http://xxx.xxx.xxx/hotfix-apis/", appId, appSecret, new ActualPatchManager() {
            @Override
            public void cleanPatch(Context context) {
                TinkerInstaller.cleanPatch(context);
            }

            @Override
            public void patch(Context context, String patchPath) {
                TinkerInstaller.onReceiveUpgradePatch(context, patchPath);
            }
        });
        PatchManager.getInstance().register(new Listener() {
            ...
        });
        PatchManager.getInstance().setTag("your tag");
        PatchManager.getInstance().setChannel("");
        PatchManager.getInstance().queryAndPatch();
        originalApplication.onCreate();
    }
}
  1. 通知结果

LoadReporter

@Override
public void onLoadResult(File patchDirectory, int loadCode, long cost) {
    super.onLoadResult(patchDirectory, loadCode, cost);
    switch (loadCode) {
        case ShareConstants.ERROR_LOAD_OK:
            PatchManager.getInstance().onLoadSuccess();
            ...
            break;
        default:
            PatchManager.getInstance().onLoadFailure();
            break;
    }
    ...
}

TinkerResultService

@Override
public void onPatchResult(final PatchResult result) {
    ...
    if (result.isSuccess) {
        PatchManager.getInstance().onPatchSuccess(result.rawPatchFilePath);
    } else {
        PatchManager.getInstance().onPatchFailure(result.rawPatchFilePath);
    }
    ...
}
  1. 记得注册TinkerResultService

三、补丁调试工具(patchtool) 测试未发布的补丁,可以扫描补丁二维码,下载补丁、立即修复、重启应用

注:

参考 Readme 搭建补丁后台,不过这个后台没有push下发补丁的功能,只有后台下发后,客户端pull拉取补丁,进行补丁修复操作

如果你的app用的是bugly来作为异常上报和运营统计,那么可以直接使用bugly提供的后台,具体操作请参考 这里 , 小巫同学录制了一系列相关的视频,参考视频教程即可学会,地址在 这里 ,bugly支持push下发,比自己搭建后台更加有优势,同样,也可以使用 TinkerPatch补丁管理后台 ,不过是收费的。

参考文档:

  1. Tinker热修复集成总结
  2. Tinker 接入指南
  3. tinker官方文档
  4. tinker补丁管理后台

你可能感兴趣的:(Tinker热修复接入)