微信Android热修复框架平台-TinkerPatch接入指南

今天总结下近期调研的一款热修复框架——Tinker。为了方便快速集成和使用,我们选择了微信提供的快速集成平台TinkerPatch(官方网站)。

什么是Tinker?

Tinker 是一个开源项目(Github链接),它是微信官方的 Android 热补丁解决方案,它支持动态下发代码、So 库以及资源,让应用能够在不需要重新安装的情况下实现更新。

什么是TinkerPatch?

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

快速安装SDK

一、添加Gradle插件依赖

buildscript {
    repositories {
        google()
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.0.0'
        // TinkerPatch 插件
        classpath "com.tinkerpatch.sdk:tinkerpatch-gradle-plugin:1.2.6"
    }
}

二、集成SDK,在app的build.gralde中加入第三方依赖

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

三、配置 tinkerpatchSupport 参数

为了简单方便,我们将 TinkerPatch 相关的配置都放于 tinkerpatch.gradle 中, 我们需要将其引入:

apply from: 'tinkerpatch.gradle'

tinkerpatchSupport配置如下:

apply plugin: 'tinkerpatch-support'

/**
 * TODO: 请按自己的需求修改为适应自己工程的参数
 */
def bakPath = file("${buildDir}/bakApk/")
def baseInfo = "app-1.0.0-0515-10-21-34" //基准包目录
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}"

    appKey = "95f17f5aaeb6334a"

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

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

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

使用步骤

一、初始化

public class SampleApplication extends Application {

    private ApplicationLike tinkerApplicationLike;

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

    private void initTinkerPatch() {
        // 我们可以从这里获得Tinker加载过程的信息
        tinkerApplicationLike = TinkerPatchApplicationLike.getTinkerPatchApplicationLike();

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

        // 每隔3个小时(通过setFetchPatchIntervalByHours设置)去访问后台时候有更新,通过handler实现轮训的效果
        TinkerPatch.with().fetchPatchUpdateAndPollWithInterval();
        // 获取当前的补丁版本
        LogUtils.d("Current patch version is " + TinkerPatch.with().getPatchVersion());
    }

}

二、构建基准包

运行 assembleRelease task 构建基准包,tinkerPatch会基于你填入的autoBackupApkPath自动备份基础包信息到相应的文件夹,包含:apk文件、R.txt文件和mapping.txt文件 (注:mapping.txt是proguard的产物,如果你没有开启proguard则不会有这个文件)

将基准包生成出来的文件路径分别填到tinkerpatchSupport中的baseApkFile、baseProguardMappingFile和baseResourceRFile 参数中。

三、发布补丁包

进行一些的BUG修改后,运行 tinkerPatchRelease task 构建补丁包,补丁包将位于 build/outputs/apk/tinkerPatch下。

上传patch_signed.apk到tinkerpatch管理平台。

四、下载安装补丁

在初始化时默认设置了3小时轮询依次查询后台有无更新补丁,若需要手动立即更新补丁,则使用如下方法

TinkerPatch.with().fetchPatchUpdate(true);

补丁自动下载、自动合并,需要彻底关闭app后重启方可生效。这里提供一个杀掉进程的方法,可以在适当的时机调用

ShareTinkerInternals.killAllOtherProcess(getApplicationContext());
android.os.Process.killProcess(android.os.Process.myPid());

五、回滚补丁

sdk提供了一键回滚到基准包到方法

TinkerPatch.with().cleanAll();

其他说明

一、补丁中如果有新增activity

需在基准包中的tinkerpatchSupport配置开启

supportComponent = true

且新activity的export属性必须false

二、在线参数

TinkerPlatform提供方便配置在线参数的功能,我们在代码中可以通过如下方法获取参数

TinkerPatch.with().fetchDynamicConfig(new ConfigRequestCallback() {

                    @Override
                    public void onSuccess(HashMap<String, String> configs) {
                        TinkerLog.w(TAG, "request config success, config:" + configs);
                        Iterator<Map.Entry<String, String>> it = configs.entrySet().iterator();
                        while (it.hasNext()) {
                            Map.Entry<String, String> entry = it.next();
                            ToastUtils.showShort("key= " + entry.getKey() + " and value= " + entry.getValue());
                        }
                    }

                    @Override
                    public void onFail(Exception e) {
                        TinkerLog.w(TAG, "request config failed, exception:" + e);
                    }
                }, true);

报错及解决

1. 编译后报如下错误:

Execution failed for task ':app:javaPreCompileDebug'.
> Annotation processors must be explicitly declared now.  The following dependencies on the compile classpath are found to contain annotation processor.  Please add them to the annotationProcessor configuration.
    - tinker-android-anno-1.9.6.jar (com.tinkerpatch.tinker:tinker-android-anno:1.9.6)

解决方法:

在app的build中加入

android {
    ...
    defaultConfig {
        ...
        //添加如下配置就OK了
        javaCompileOptions { annotationProcessorOptions { includeCompileClasspath = true } }
    }
    ...
}

2. Bad notification for startForeground

如果出现如下报错,请检查是否在AndroidManifest.xml配置了icon信息。

android.app.RemoteServiceException: Bad notification for startForeground: java.lang.RuntimeException: invalid service notification: Notification(pri=0 contentView=null vibrate=null sound=null defaults=0x0 flags=0x40 color=0x00000000 vis=PRIVATE)

### END ###

阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页