android进阶

微信Android热补丁方案Tinker初步使用

2017-03-14  本文已影响1327人  handsomeslow

Tinker 官方使用文档


本文根据官网文档进行了一次初步使用,从APP的构建到补丁发布完整地介绍了Tinker,用来了解Tinker的使用,参考了官方Demo:

官方 Demo:tinkerpatch-easy-sample

为什么使用Tinker

由于其他热补丁方案还未使用过,不好做出评论,以下引述Tinker官网上的说明:来说明Tinker的优势。


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

Tinker QZone AndFix Robust
类替换 yes yes no no
So替换 yes no no no
资源替换 yes yes no no
全平台支持 yes yes yes yes
即时生效 no no yes yes
性能损耗 较小 较大 较小 较小
补丁包大小 较小 较大 一般 一般
开发透明 yes yes no no
复杂度 较低 较低 复杂 复杂
gradle支持 yes no no no
Rom体积 较大 较小 较小 较小
成功率 较高 较高 一般 最高

总的来说:

AndFix作为native解决方案,首先面临的是稳定性与兼容性问题,更重要的是它无法实现类替换,它是需要大量额外的开发成本的;
Robust兼容性与成功率较高,但是它与AndFix一样,无法新增变量与类只能用做的bugFix方案;
Qzone方案可以做到发布产品功能,但是它主要问题是插桩带来Dalvik的性能问题,以及为了解决Art下内存地址问题而导致补丁包急速增大的。
特别是在Android N之后,由于混合编译的inline策略修改,对于市面上的各种方案都不太容易解决。而Tinker热补丁方案不仅支持类、So以及资源的替换,它还是2.X-7.X的全平台支持。利用Tinker我们不仅可以用做bugfix,甚至可以替代功能的发布。Tinker已运行在微信的数亿Android设备上,那么为什么你不使用Tinker呢?

下面我们来开始介绍 Tinker 的具体使用,包括以下几个部分:


一、集成 Tinker 及初始化

添加 gradle 插件依赖

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

集成 TinkerPatch SDK

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

添加 TinkerPatch 配置

为了简单方便,Demo将 TinkerPatch 相关的配置都放于 tinkerpatch.gradle 中,

apply plugin: 'tinkerpatch-support'

/**
 * TODO: 请按自己的需求修改为适应自己工程的参数
 */
def bakPath = file("${buildDir}/bakApk/")
def baseInfo = "app-1.0.0-0314-11-30-49"
def variantName = "debug"
import java.util.regex.Matcher
import java.util.regex.Pattern

/**
 * 对于插件各参数的详细解析请参考
 * http://tinkerpatch.com/Docs/SDK
 */
tinkerpatchSupport {
    /** 可以在debug的时候关闭 tinkerPatch, isRelease() 可以判断BuildType是否为Release **/
    tinkerEnable = true
    reflectApplication = true

    autoBackupApkPath = "${bakPath}"

    /** 需要改为对应的appKey,下文新增APP里说明 **/
    appKey = "5a25479b9aeb2e5e"

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

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

    /** 基准APK文件 **/
    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}"
    }
}

app/build.gradle 中引入 tinkerpatch.gradle

apply from: 'tinkerpatch.gradle'

初始化 TinkerPatch SDK

public class MyApplication extends Application {
    ApplicationLike tinkerAppLike;

    @Override
    protected void attachBaseContext(Context base) {
        super.attachBaseContext(base);
        MultiDex.install(base);
    }

    @Override
    public void onCreate() {
        super.onCreate();
        if (BuildConfig.TINKER_ENABLE){
            tinkerAppLike = TinkerPatchApplicationLike.getTinkerPatchApplicationLike();
            TinkerPatch.init(tinkerAppLike)
                    //是否自动反射Library路径,无须手动加载补丁中的So文件
                    //注意,调用在反射接口之后才能生效,你也可以使用Tinker的方式加载Library
                    .reflectPatchLibrary()
                    //设置收到后台回退要求时,锁屏清除补丁
                    //默认是等主进程重启时自动清除
                    .setPatchRollbackOnScreenOff(true)
                    //设置补丁合成成功后,锁屏重启程序
                    //默认是等应用自然重启
                    .setPatchRestartOnSrceenOff(true);
                 
        }
        // 每隔一小时检查一次,按自己需求设定
        new FetchPatchHandler().fetchPatchWithInterval(1);
    }
}
    ...

最后在AndroidManifest.xml中设置MyApplication:

<application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:name=".MyApplication"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

至此Demo已经构建完成,下面就开始进行补丁包的构建与发布。


二、构建基准包及生成补丁文件

首先直接运行task assembleRelease,此时即可在build文件夹内出现bakApk文件夹,里面存放的是每次编译的APK文件,也就是完整的APP安装包。

基准包文件

并且我们可以看到在build/bakApk文件夹内已经生成了三个文件:


build/bakApk文件夹

执行assembleDebug 没有mapping文件。

生成补丁文件

现在需要生成上面的基准包APK的补丁文件。作为测试Demo我们这里随便改动TextView文字

    <!--Hello World 改为 Hello World!!!!!!!!!!!-->
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!!!!!!!!!!!" />

改好代码后,我们开始生成补丁包:


这里需要我们在tinkerpatch.gradle文件中配置三个文件路径:

而在官方的tinkerpatch.gradle文件中已经帮我们配置好基本路径:

  baseApkFile = "${pathPrefix}/${name}.apk"
// 这里tinkerPatchDubug和tinkerPatchRelease不同的是tinkerPatchRelease需要配置mapping文件,否则task会失败
  baseProguardMappingFile = "${pathPrefix}/${name}-mapping.txt"
  baseResourceRFile = "${pathPrefix}/${name}-R.txt"

我们只需要将tinkerpatch.gradle文件中baseInfo = "app-1.0.0-0314-11-30-49"值改成要生成补丁的基准包所在文件夹名称即可(即上文bakApk文件夹下基准包文件夹名称,选择哪个文件夹生成的补丁就是基于对应的基准包)。

接下来就执行tinkerPatchRelease task开始生成补丁文件了:

tinkerPatchRelease task

需要耐心等待一会,执行结束会在outputs文件夹内生成tinkerPatch文件夹:

生成的补丁文件夹
该文件夹内文件还是挺多的, patch_signed_7zip.apk 既是我们要的补丁包。

三、Tinker 平台使用及发布补丁

首先登录Tinker 平台注册账号,然后需要经过3个步骤即可完成补丁包的发布:

新增APP

新增APP

若首次使用点击新增APP后,输入APP的名称,名称可以再次修改。此时会生成对应的appKey(如下图左侧),需要将key填入到 tinkerpatch.gradle 中: appKey = "5a25479b9aeb2e5e"

添加版本

添加版本

输入需要打补丁的基准APP的版本号,不同的版本因为迭代的原因补丁也不相同,需要前期做好规划。

发布补丁

发布补丁
需要对应APP版本对应的补丁文件,既是我们上文中提到的 patch_signed_7zip.apk文件。

测试结果

经过了大约20分钟看到了测试机补丁merge成功,没有立即看到效果的可以等等:

Hello World 已被改为 Hello World!!!!!!!!!!!

补丁详情里可以查看该补丁的信息:


补丁详情

平台也提供了实时的数据监控,方便及时了解补丁的安装情况:


实时监控

Tinker的已知问题

由于原理与系统限制,Tinker有以下已知问题:


以上就是一个Tinker完整的使用过程,并没有涉及到原理及深入使用,希望对大家有所帮助!
本文的Demo

上一篇下一篇

猜你喜欢

热点阅读