Android Tinker 基本使用教程
为什么使用Tinker
当前市面的热补丁方案有很多,其中比较出名的有阿里的AndFix、美团的Robust以及QZone的超级补丁方案。但它们都存在无法解决的问题,这也是正是我们推出Tinker的原因。
这个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体积 | 较大 | 较小 | 较小 | 较小 |
成功率 | 较高 | 较高 | 一般 | 最高 |
1.怎么使用:
Tinker 的使用还是比较简单的,这是Tinker官方的github链接 : https://github.com/Tencent/tinker.
官方上面的文档很久没更新了,可以直接下载他最新的demo,按照demo上的来集成。
2. 导入依赖:
注意,这里有个坑,gradle版本不能用超过4.0.0版本
的,不然构建会出错,tinker还不支持超过4.0.0版本,我这里用的3.5.3版本的
gradle依赖
allprojects {
dependencies {
classpath "com.android.tools.build:gradle:3.5.3"
classpath "com.tencent.tinker:tinker-patch-gradle-plugin:1.9.1"
}
}
dependencies {
//可选,如果不用注解构建application可不用
// annotationProcessor("com.tencent.tinker:tinker-android-anno:1.9.14.5") { changing = true }
// compileOnly("com.tencent.tinker:tinker-android-anno:1.9.14.5") { changing = true }
//tinker's main Android lib
implementation('com.tencent.tinker:tinker-android-lib:1.9.14.5')
//dex分包
implementation "androidx.multidex:multidex:2.0.1"
}
3. build.gradle配置:
在你的build.gradle
加上以下配置 。tinker.gradle
是我新建的一个gradle,目的是将tinker配置独立出来
${TINKER_ID}
是我在 gradle.properties
里面配置的一个常量TINKER_ID=100
每次发布新基准包都需要修改此版本号 注意:(发布补丁包不需要修改)
apply from: 'tinker.gradle'
android {
........
defaultConfig {
.......
javaCompileOptions {
annotationProcessorOptions {
includeCompileClasspath = true } }
multiDexEnabled true
buildConfigField "String", "MESSAGE", "\"I am the base apk\""
buildConfigField "String", "TINKER_ID", "\"${TINKER_ID}\""
buildConfigField "String", "PLATFORM", "\"all\""
}
dexOptions {
jumboMode = true
}
}
tinker.gradle配置信息:可直接复制, 后面只需要修改ext {}
里面的内容,其他的无需要可不用修改
def bakPath = file("${buildDir}/bakApk/")
ext {
//for some reason, you may want to ignore tinkerBuild, such as instant run debug build?
tinkerEnabled = true
//基准apk路径
tinkerOldApkPath = "${bakPath}/app-debug-0828-10-39-58.apk"
//未开启混淆,则不需要填写
tinkerApplyMappingPath = "${bakPath}/"
//基准apk中的R文件路径
tinkerApplyResourcePath = "${bakPath}/app-debug-0828-10-39-58-R.txt"
//如果你修复了res文件,需要指定你bug版本的R.txt文件
tinkerBuildFlavorDirectory = "${bakPath}/"
}
def getOldApkPath() {
return hasProperty("OLD_APK") ? OLD_APK : ext.tinkerOldApkPath
}
def getApplyMappingPath() {
return hasProperty("APPLY_MAPPING") ? APPLY_MAPPING : ext.tinkerApplyMappingPath
}
def getApplyResourceMappingPath() {
return hasProperty("APPLY_RESOURCE") ? APPLY_RESOURCE : ext.tinkerApplyResourcePath
}
def buildWithTinker() {
return hasProperty("TINKER_ENABLE") ? TINKER_ENABLE : ext.tinkerEnabled
}
def getTinkerBuildFlavorDirectory() {
return ext.tinkerBuildFlavorDirectory
}
if (buildWithTinker()) {
apply plugin: 'com.tencent.tinker.patch'
tinkerPatch {
/**
* 默认为null
* 将旧的apk和新的apk建立关联
* 从build / bakApk添加apk
*/
oldApk = getOldApkPath()
/**
* 可选,默认'false'
*有些情况下我们可能会收到一些警告
*如果ignoreWarning为true,我们只是断言补丁过程
* case 1:minSdkVersion低于14,但是你使用dexMode与raw。
* case 2:在AndroidManifest.xml中新添加Android组件,
* case 3:装载器类在dex.loader {}不保留在主要的dex,
* 它必须让tinker不工作。
* case 4:在dex.loader {}中的loader类改变,
* 加载器类是加载补丁dex。改变它们是没有用的。
* 它不会崩溃,但这些更改不会影响。你可以忽略它
* case 5:resources.arsc已经改变,但是我们不使用applyResourceMapping来构建
*/
ignoreWarning = true
/**
* 可选,默认为“true”
* 是否签名补丁文件
* 如果没有,你必须自己做。否则在补丁加载过程中无法检查成功
* 我们将使用sign配置与您的构建类型
*/
useSign = true
/**
* 可选,默认为“true”
* 是否使用tinker构建
*/
tinkerEnable = buildWithTinker()
/**
* 警告,applyMapping会影响正常的android build!
*/
buildConfig {
/**
* 可选,默认为'null'
* 如果我们使用tinkerPatch构建补丁apk,你最好应用旧的
* apk映射文件如果minifyEnabled是启用!
* 警告:你必须小心,它会影响正常的组装构建!
*/
applyMapping = getApplyMappingPath()
/**
* 可选,默认为'null'
* 最好保留R.txt文件中的资源id,以减少java更改
*/
applyResourceMapping = getApplyResourceMappingPath()
/**
* 必需,默认'null'
* 因为我们不想检查基地apk与md5在运行时(它是慢)
* tinkerId用于在试图应用补丁时标识唯一的基本apk。
* 我们可以使用git rev,svn rev或者简单的versionCode。
* 我们将在您的清单中自动生成tinkerId
*/
tinkerId = TINKER_ID.toInteger()
/**
* 如果keepDexApply为true,则表示dex指向旧apk的类。
* 打开这可以减少dex diff文件大小。
*/
keepDexApply = false
/**
* optional, default 'false'
* Whether tinker should treat the base apk as the one being protected by app
* protection tools.
* If this attribute is true, the generated patch package will contain a
* dex including all changed classes instead of any dexdiff patch-info files.
*/
isProtectedApp = false
/**
* optional, default 'false'
* Whether tinker should support component hotplug (add new component dynamically).
* If this attribute is true, the component added in new apk will be available after
* patch is successfully loaded. Otherwise an error would be announced when generating patch
* on compile-time.
*
* <b>Notice that currently this feature is incubating and only support NON-EXPORTED Activity</b>
*/
supportHotplugComponent = false
}
dex {
/**
* 可选,默认'jar'
* 只能是'raw'或'jar'。对于原始,我们将保持其原始格式
* 对于jar,我们将使用zip格式重新包装dexes。
* 如果你想支持下面14,你必须使用jar
* 或者你想保存rom或检查更快,你也可以使用原始模式
*/
dexMode = "jar"
/**
* 必需,默认'[]'
* apk中的dexes应该处理tinkerPatch
* 它支持*或?模式。
*/
pattern = ["classes*.dex",
"assets/secondary-dex-?.jar"]
/**
* 必需,默认'[]'
* 警告,这是非常非常重要的,加载类不能随补丁改变。
* 因此,它们将从补丁程序中删除。
* 你必须把下面的类放到主要的dex。
* 简单地说,你应该添加自己的应用程序{@code tinker.sample.android.SampleApplication}
* 自己的tinkerLoader,和你使用的类
*/
loader = [
//use sample, let BaseBuildInfo unchangeable with tinker
<