最近突然想集成Tinker的SDK,写个Demo,然后这么一写就是一天。感触很深,踩过很多坑,目前也有很多不理解的地方。下面我就说说大致流程及注意事项;
1.在项目的gradle中添加tinker插件
2.在app的gradle中添加sdk相关依赖
3.创建tinkerpatch.gradle文件(在app目录中右键新建)
4.根据tinkerpatch.gradle文件创建相应的application
5.manifest文件中添加相应权限(6.0以上手动申请)
好了,到现在基本的sdk集成配置算完成了,下面我就直接截图:
第一步 添加 gradle 插件依赖
gradle 远程仓库依赖 jcenter, 例如 TinkerPatch Sample 中的 build.gradle.
buildscript {
repositories {
jcenter()
}
dependencies {
// TinkerPatch 插件
classpath "com.tinkerpatch.sdk:tinkerpatch-gradle-plugin:1.2.13"
}
}
注意,在这里 SDK 使用了 fat 打包的模式,我们不能再引入任何 Tinker 的相关依赖,否则会造成版本冲突。
第二步 集成 TinkerPatch SDK
添加 TinkerPatch SDK 库的 denpendencies 依赖, 可参考 Sample 中的 app/build.gradle:
dependencies {
// 若使用annotation需要单独引用,对于tinker的其他库都无需再引用
provided("com.tinkerpatch.tinker:tinker-android-anno:1.9.13")
compile("com.tinkerpatch.sdk:tinkerpatch-android-sdk:1.2.13")
}
注意,若使用 annotation 自动生成 Application, 需要单独引入 Tinker 的 tinker-android-anno 库。除此之外,我们无需再单独引入 tinker 的其他库。
为了简单方便,我们将 TinkerPatch 相关的配置都放于 tinkerpatch.gradle 中, 我们需要将其引入:
apply from: 'tinkerpatch.gradle'
第三步 配置 tinkerpatchSupport 参数
打开引入的 tinkerpatch.gradle 文件,它的具体参数如下:
tinkerpatchSupport {
/** 可以在debug的时候关闭 tinkerPatch **/
tinkerEnable = true
/** 是否使用一键接入功能 **/
reflectApplication = true
/** 是否开启加固模式,只有在使用加固时才能开启此开关 **/
protectedApp = false
/** 补丁是否支持新增 Activity (exported必须为false)**/
supportComponent = false
autoBackupApkPath = "${bakPath}"
/** 在tinkerpatch.com得到的appKey **/
appKey = "yourAppKey"
/** 注意: 若发布新的全量包, 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"
}
它的具体含义如下:
参数 | 默认值 | 描述 |
---|---|---|
tinkerEnable | true | 是否开启 tinkerpatchSupport 插件功能。 |
appKey | "" | 在 TinkerPatch 平台 申请的 appkey, 例如 sample 中的 'f828475486f91936' |
appVersion | "" | 在 TinkerPatch 平台 输入的版本号, 例如 sample 中的 '1.0.0'。 注意,我们使用 appVersion 作为 TinkerId, 我们需要保证每个发布出去的基础安装包的 appVersion 都不一样。 |
reflectApplication | false | 是否反射 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 异常。 |
protectedApp | false | 是否开启支持加固,注意:只有在使用加固时才能开启此开关 |
supportComponent | false | 是否开启支持在补丁包中动态增加Activity 注意:新增Activity的Exported属性必须为false |
backupFileNameFormat | '${appName}-${variantName}' | 格式化命名备份文件 这里请使用单引号 |
一般来说,我们无需修改引用 android 的编译配置,也不用修改 tinker 插件原来的配置。针对特殊需求,具体的参数含义可参考 Tinker 文档:Tinker 接入指南.
第四步 初始化 TinkerPatch SDK
最后在我们的代码中,只需简单的初始化 TinkerPatch 的 SDK 即可,我们无需考虑 Tinker 是如何下载/合成/应用补丁包, 也无需引入各种各样 Tinker 的相关类。
1. reflectApplication = true 的情况
若我们使用 reflectApplication 模式,我们无需为接入 Tinker 而改造我们的 Application 类。初始化 SDK 可参考 tinkerpatch-easy-sample 中的 SampleApplication 类.
public class SampleApplication extends Application {
...
@Override
public void onCreate() {
super.onCreate();
// 我们可以从这里获得Tinker加载过程的信息
tinkerApplicationLike = TinkerPatchApplicationLike.getTinkerPatchApplicationLike();
// 初始化TinkerPatch SDK, 更多配置可参照API章节中的,初始化SDK
TinkerPatch.init(tinkerApplicationLike)
.reflectPatchLibrary()
.setPatchRollbackOnScreenOff(true)
.setPatchRestartOnSrceenOff(true)
.setFetchPatchIntervalByHours(3);
// 每隔3个小时(通过setFetchPatchIntervalByHours设置)去访问后台时候有更新,通过handler实现轮训的效果
TinkerPatch.with().fetchPatchUpdateAndPollWithInterval();
}
...
我们将 Tinker 加载补丁过程的结果存放在 TinkerPatchApplicationLike 中。
2. reflectApplication = false 的情况
若我们已经完成了应用的 Application 改造,即将 Application 的逻辑移动到 ApplicationLike类中。我们可以参考 tinkerpatch-sample 中的 SampleApplicationLike 类.
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();
}
...
}
按照正常情况配置已经完成了,但是这才刚刚开始,(本人as 3.4,gradle版本5.1.1,gradle插件版本3.4)
1.当你编译的时候会发现提示某个依赖过时,也提示你新的依赖,但是这个依赖是真的不好找,于是只有降低gradle插件版本-3.2.1
2.还没完,当你再次编译的时候又提示你androidx与v7冲突.这时候估计就懵逼了,明明没有androidx这个包怎么会冲突呐,这时候你可能想到第三方中tinker含有androidx包,没错就是这个原因,于是你不得不把包统一改成androidx或者v7
3.你以为这就可以了嘛?不,还没完,继续编译继续报错,这次是提示你tinker某个依赖没添加。但是配置集成都是按照官网来的,怎么可能又错,这时候你可以百度一下,代码被我删了,就在app里面gradle加个配置
4.最后就是打基包的时候记得把最新基包名字更新到tinkerpatch.gradle中,然后运行,再改bug,最后打补丁包