参考
腾讯Tinker官方文档
建议大家先使用demo实验,成功后再集成到真正项目中。。。因为。。。你懂的!!!
写在前面
好久没有写博客了,都用笔记的形式记录了所学的东西。最近面试跟面试官聊起,发现写博客真的是一个好习惯,希望坚持下去吧。本文的目的就一个,让应用接入Tinker热更新,我们不去探究这东西怎么实现,本文仅仅作为工具使用指南。
类似的原理性文章可以参考下拙作:
Android黑科技动态加载(一)之Java中的ClassLoader
Android黑科技动态加载(二)之Android中的ClassLoader
Android黑科技动态加载(三)之动态加载资源
Android黑科技动态加载(四)之插件化开发
基准包
例如有一个版本A,但是这时A是有Bug的,然后修复Bug后的生成的版本我们称为B。A和B之间的区别产生一个差分包(这里也称为补丁包),那么我们就可以说这个差分包是以A作为基准包相对B生成的。参考增量更新文章:Android NDK开发两部曲(二)之应用篇(增量更新也就那样)
基本步骤
1、注册Tinker账号并新建项目,传送门
2、配置gradle和代码
3、生成基准包
4、修复Bug
5、生成补丁包
6、发布补丁包
Tinker做了什么
1、1-2步是APP开发的基本步骤,完成1-3步,那么你的APP就集成了Tinker。
集成Tinker后,Tinker会根据各个版本的配置信息去自动加载补丁。可配置强制更新,也可配置轮询更新。
2、第3步则是保留一个之前版本副本,用于后面生成补丁。为什么要这样做?因为1.0.2的相对于1.0.1的补丁包只能作用在1.0.1版本上。如果想要处理1.0.0那么有两种方法,使用1.0.0->1.0.1和1.0.1->1.0.2两个补丁包。但是也可以生成1.0.0->1.0.2的补丁包。所以副本保留还是有必要的。
3、4-6部就是真正应用到生产环境上了,真正达到热修复的作用。
一、注册Tinker账号
这个就不说了,Tinker注册和新建项目都好简单,也没有什么需要注意的。拿到appKey
二、配置Gradle和代码
这个推荐我们的拷贝粘贴代码
1、配置Tinker版本信息
我们使用配置文件去配置版本信息,易于统一版本和后面更换版本
编辑根目录的gradle.properties
,加入
TINKER_VERSION=1.9.2
TINKERPATCH_VERSION=1.2.2
2、配置根目录下的build.gradle文件
使用Tinker插件
classpath "com.tinkerpatch.sdk:tinkerpatch-gradle-plugin:${TINKERPATCH_VERSION}"
3、配置Tinker的gradle脚本
在项目根目录新建tinkerpatch.gradle
文件
apply plugin: 'tinkerpatch-support'
/**
* TODO: 请按自己的需求修改为适应自己工程的参数
*/
def bakPath = file("${buildDir}/bakApk/")
def baseInfo = "app-1.0.0-1213-19-52-36"
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 = "c6a00cf4aafa2ab2"
/** 注意: 若发布新的全量包, 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"
/**
* 若有编译多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
}
}
注意几个字段内容,主要是后面生成补丁需要用到的,除了AppKey外其他暂时不用改
baseInfo
: 这个是基准包的名称,使用Tinker脚本编译在模块的build/bakApk生成编译副本
variantName
: 这个一般对应buildTypes
里面你基准包生成的类型,release、debug或其他
appKey
: 这个就是Tinker新建项目时拿到的appKey
appVersion
: 配置和Tinker后台新建补丁包的一致
4、配置模块下的buidle.gradle
A、配置应用签名
这个百度搜都有,大概就这样
signingConfigs {
release {//发布版本的签名配置
storeFile file('key.jks')
keyAlias 'test'
storePassword '123456789'
keyPassword '123456789'
}
debug {//调试版本的签名配置
storeFile file('key.jks')
keyAlias 'test'
storePassword '123456789'
keyPassword '123456789'
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.release
}
debug {
signingConfig signingConfigs.debug
}
}
B、配置依赖
//若使用annotation需要单独引用,对于tinker的其他库都无需再引用
annotationProcessor("com.tinkerpatch.tinker:tinker-android-anno:${TINKER_VERSION}") {
changing = true
}
compileOnly("com.tinkerpatch.tinker:tinker-android-anno:${TINKER_VERSION}") {
changing = true
}
implementation("com.tinkerpatch.sdk:tinkerpatch-android-sdk:${TINKERPATCH_VERSION}") {
changing = true
}
C、使用插件
在模块的build.gradle加入
apply from: 'tinkerpatch.gradle'
3、代码配置
最后一步配置,把代码集成到App里,别忘了在AndroidManifest里面配置APP。。。
public class App extends Application {
private ApplicationLike tinkerApplicationLike;
@Override
public void onCreate() {
super.onCreate();
tinkerApplicationLike = TinkerPatchApplicationLike.getTinkerPatchApplicationLike();
// 初始化TinkerPatch SDK, 更多配置可参照API章节中的,初始化SDK
TinkerPatch.init(tinkerApplicationLike)
.reflectPatchLibrary()
.fetchPatchUpdate(true)
// 强制更新
.setPatchRollbackOnScreenOff(true)
.setPatchRestartOnSrceenOff(true)
.setFetchPatchIntervalByHours(3);
// 每隔3个小时(通过setFetchPatchIntervalByHours设置)去访问后台时候有更新,通过handler实现轮训的效果
TinkerPatch.with().fetchPatchUpdateAndPollWithInterval();
}
}
三、生成基准包
其实到了这里就配置完成了,我们生产一个基准包
双击assembleRelease生成成功后安装模块/build/outputs/apk/release/app-release.apk
就OK了,这时候进去模块/build/bakApk
里面记录一下类似app-1.0.0-1213-19-52-36
的文件名称,只生成一次基准包,那么就会生成一个。但是如果手贱点太多生成太多的话确定不了刚刚生成的是哪个,那么就选最新那个或者删掉重新生成基准包,真实环境并不允许这样搞。。。
四、修复bug
随便修改点代码
五、生成补丁包
这时候我们就需要去修改一些tinkerpatch.gradle
文件的信息了。
baseInfo
:还记得app-1.0.0-1213-19-52-36
这个东西吗?换成自己上面记录的就OK了
variantName
: 因为刚刚我们使用assembleRelease
生成的补丁,所以我们只需要使用release
就OK了
双击TinkerPatchRelease
生成差分包,patch_signed_7zip.apk
就是补丁包了
六、发布补丁包
回到Tinker后台,选中我们开始新建的项目,补丁下发->添加APP版本。然后上传刚刚的patch_signed_7zip.apk
。
APP开启强制更新的话那么重启应用就会更新,否则会通过轮询去更新。应用重启才生效。Tinker太强大了,本文目的就是把项目跑通,相信后面的很多功能大家有兴趣的话一起发现,一起讨论。