热修复框架Tinker的从0到集成之路.docx
- 文档编号:29590813
- 上传时间:2023-07-24
- 格式:DOCX
- 页数:22
- 大小:199.37KB
热修复框架Tinker的从0到集成之路.docx
《热修复框架Tinker的从0到集成之路.docx》由会员分享,可在线阅读,更多相关《热修复框架Tinker的从0到集成之路.docx(22页珍藏版)》请在冰豆网上搜索。
热修复框架Tinker的从0到集成之路
热修复框架Tinker的从0到集成之路
Gradle配置
工程的根目录的gradle.properties文件中添加Tinker的版本号
org.gradle.jvmargs=-Xmx2048m-XX:
MaxPermSize=512m-XX:
+HeapDumpOnOutOfMemoryError-Dfile.encoding=UTF-8
TINKER_VERSION=1.7.6
工程根目录下的build.gradle中添加Tinker的编译插件
dependencies{
//Tinker编译的插件
classpath'com.tencent.tinker:
tinker-patch-gradle-plugin:
1.7.6'
classpath'com.android.tools.build:
gradle:
2.1.0'
}
app目录下的build.gradle中添加程序运行时的jar包
applyplugin:
'com.android.application'
android{
compileSdkVersion23
buildToolsVersion"23.0.2"
defaultConfig{
applicationId"com.alex.tinkerdemo"
minSdkVersion15
targetSdkVersion21
versionCode1
versionName"1.0"
//tinker基本配置
multiDexEnabledtrue
buildConfigField"String","MESSAGE","\"Iamthebaseapk\""
buildConfigField"String","TINKER_ID","\"${getTinkerIdValue()}\""
buildConfigField"String","PLATFORM","\"all\""
}
//Tinker推荐设置
dexOptions{
jumboMode=true
}
//签名信息的配置
signingConfigs{
release{
try{
storeFilefile("./keystore/key.jks")
storePassword"123456"
keyAlias"1111"
keyPassword"1234567"
}catch(ex){
thrownewInvalidUserDataException(ex.toString())
}
}
}
//编译类型的配置
buildTypes{
release{
minifyEnabledtrue
signingConfigsigningConfigs.release
proguardFilesgetDefaultProguardFile('proguard-android.txt'),'proguard-rules.pro'
}
debug{
debuggabletrue
minifyEnabledfalse
signingConfigsigningConfigs.debug
}
}
}
dependencies{
compilefileTree(dir:
'libs',include:
['*.jar'])
testCompile'junit:
junit:
4.12'
compile'com.android.support:
appcompat-v7:
24.2.1'
//多dex打包的类库
compile"com.android.support:
multidex:
1.0.1"
//Tinker基本类库
compile("com.tencent.tinker:
tinker-android-lib:
${TINKER_VERSION}"){changing=true}
//编译时生成Application
provided("com.tencent.tinker:
tinker-android-anno:
${TINKER_VERSION}"){changing=true}
}
在build.gradle中,关键是依赖的添加,分别三个依赖,第一个是MultiDex分包使用的依赖,第二个是基本功能的类库,第三个是重点。
Tinker不推荐我们自己实现Application,而是由Tinker自己生成,那么我们通常开发时都会自己定义一个Application类,进行一些App的初始化操作,怎么解决呢?
Tinker推荐了另一种实现的方式,后面再说,而第三个依赖便是方便实现自定义Application所推荐的类库。
如上,就是基本的环境配置,当然还有Tinker的配置,这里我们直接采用Tinker提供的基本配置,具体配置的细节可以看wiki。
在app的build.gradle最后,添加如下配置
//=======================Tinker配置=======================================
defgitSha(){
try{
//StringgitRev='gitrev-parse--shortHEAD'.execute(null,project.rootDir).text.trim()
StringgitRev="1008611"
if(gitRev==null){
thrownewGradleException("can'tgetgitrev,youshouldaddgittosystempathorjustinputtestvalue,suchas'testTinkerId'")
}
returngitRev
}catch(Exceptione){
thrownewGradleException("can'tgetgitrev,youshouldaddgittosystempathorjustinputtestvalue,suchas'testTinkerId'")
}
}
//保存打包oldapk的地址,便于生成补丁包时的对比
defbakPath=file("${buildDir}/bakApk/")
ext{
//是否打开tinker的功能。
tinkerEnabled=true
//oldapk地址
tinkerOldApkPath="${bakPath}/app-release-16-13.apk"
//oldapk混淆文件地址
tinkerApplyMappingPath="${bakPath}/app-release-16-13-mapping.txt"
//oldapkR文件地址
tinkerApplyResourcePath="${bakPath}/app-release-16-13-R.txt"
//多渠道打包相关
tinkerBuildFlavorDirectory="${bakPath}/app-1018-17-32-47"
}
defgetOldApkPath(){
returnhasProperty("OLD_APK")?
OLD_APK:
ext.tinkerOldApkPath
}
defgetApplyMappingPath(){
returnhasProperty("APPLY_MAPPING")?
APPLY_MAPPING:
ext.tinkerApplyMappingPath
}
defgetApplyResourceMappingPath(){
returnhasProperty("APPLY_RESOURCE")?
APPLY_RESOURCE:
ext.tinkerApplyResourcePath
}
defgetTinkerIdValue(){
returnhasProperty("TINKER_ID")?
TINKER_ID:
gitSha()
}
defbuildWithTinker(){
returnhasProperty("TINKER_ENABLE")?
TINKER_ENABLE:
ext.tinkerEnabled
}
defgetTinkerBuildFlavorDirectory(){
returnext.tinkerBuildFlavorDirectory
}
if(buildWithTinker()){
applyplugin:
'com.tencent.tinker.patch'
tinkerPatch{
/**
*necessary,default'null'
*theoldapkpath,usetodiffwiththenewapktobuild
*addapkfromthebuild/bakApk
*/
oldApk=getOldApkPath()
/**
*optional,default'false'
*therearesomecaseswemaygetsomewarnings
*ifignoreWarningistrue,wewouldjustassertthepatchprocess
*case1:
minSdkVersionisbelow14,butyouareusingdexModewithraw.
*itmustbecrashwhenload.
*case2:
newlyaddedAndroidComponentinAndroidManifest.xml,
*itmustbecrashwhenload.
*case3:
loaderclassesindex.loader{}arenotkeepinthemaindex,
*itmustbelettinkernotwork.
*case4:
loaderclassesindex.loader{}changes,
*loaderclassesisuestoloadpatchdex.itisuselesstochangethem.
*itwon'tcrash,butthesechangescan'teffect.youmayignoreit
*case5:
resources.arschaschanged,butwedon'tuseapplyResourceMappingtobuild
*/
ignoreWarning=false
/**
*保证签名的唯一性
*/
useSign=true
/**
*optional,default'true'
*whetherusetinkertobuild
*/
tinkerEnable=buildWithTinker()
/**
*编译相关配置
*/
buildConfig{
/**
*新的apk使用旧的Map文件,减少补丁包大小
*/
applyMapping=getApplyMappingPath()
/**
*同上所述,相同的R文件,减少补丁包大小
*/
applyResourceMapping=getApplyResourceMappingPath()
/**
*补丁的id标识,补丁包的tinkerId和apk的tinkerId相同才能加载补丁
*/
tinkerId=getTinkerIdValue()
/**
*打开keepDexApply模式,补丁包将根据基准包的类分布来编译。
*/
keepDexApply=false
}
dex{
/**
*'raw'模式,将会保持输入dex的格式。
*'jar'模式,我们将会把输入dex重新压缩封装到jar
*/
dexMode="jar"
/**
*需要处理dex路径
*/
pattern=["classes*.dex",
"assets/secondary-dex-?
.jar"]
/**
*放在main.dex中的类,这些类不会被加载
*/
loader=[
//usesample,letBaseBuildInfounchangeablewithtinker
"tinker.sample.android.app.BaseBuildInfo"
]
}
lib{
/**
*需要处理的lib路径
*/
pattern=["lib/armeabi/*.so"]
}
res{
/**
*需要处理的资源路径
*/
pattern=["res/*","assets/*","resources.arsc","AndroidManifest.xml"]
/**
*忽视改变的文件,即这些文件的改变不会被打到补丁包中
*/
ignoreChange=["assets/sample_meta.txt"]
/**
*对于修改的资源,如果大于largeModSize,我们将使用bsdiff算法。
这可以降低补丁包的大小,但是会增加合成时的复杂度。
默认大小为100kb
*/
largeModSize=100
}
packageConfig{
/**
*配置到清单文件的一些字段,没啥用
*/
configField("patchMessage","tinkerissampletouse")
/**
*配置到清单文件的一些字段,没啥用
*/
configField("platform","all")
/**
*配置到清单文件的一些字段,没啥用
*/
configField("patchVersion","1.0")
}
//oryoucanaddconfigfiledoutside,orgetmetavaluefromoldapk
//project.tinkerPatch.packageConfig.configField("test1",project.tinkerPatch.packageConfig.getMetaDataFromOldApk("Test"))
//project.tinkerPatch.packageConfig.configField("test2","sample")
/**
*ifyoudon'tusezipArtifactorpath,wejustuse7zatotry
*/
sevenZip{
/**
*zip路径配置项,执行前提是useSign为true,推荐配置
*/
zipArtifact="com.tencent.mm:
SevenZip:
1.1.10"
}
}
List
project.android.productFlavors.each{flavor->
flavors.add(flavor.name)
}
booleanhasFlavors=flavors.size()>0
/**
*bakapkandmapping
*/
android.applicationVariants.all{variant->
/**
*tasktype,youwanttobak
*/
deftaskName=variant.name
//defdate=newDate().format("MMdd-HH-mm-ss")
defdate=newDate().format("mm-ss")
tasks.all{
if("assemble${taskName.capitalize()}".equalsIgnoreCase(it.name)){
it.doLast{
copy{
deffileNamePrefix="${project.name}-${variant.baseName}"
defnewFileNamePrefix=hasFlavors?
"${fileNamePrefix}":
"${fileNamePrefix}-${date}"
defdestPath=hasFlavors?
file("${bakPath}/${project.name}-${date}/${variant.flavorName}"):
bakPath
fromvariant.outputs.outputFile
intodestPath
rename{StringfileName->
fileName.replace("${fileNamePrefix}.apk","${newFileNamePrefix}.apk")
}
from"${buildDir}/outputs/mapping/${variant.dirName}/mapping.txt"
intodestPath
rename{StringfileName->
fileName.replace("mapping.txt","${newFileNamePrefix}-mapping.txt")
}
from"${buildDir}/intermediates/symbols/${variant.dirName}/R.txt"
intodestPath
rename{StringfileName->
fileName.replace("R.txt","${newFileNamePrefix}-R.txt")
}
}
}
}
}
}
project.afterEvaluate{
//sampleuseforbuildallflavorforonetime
if(hasFlavors){
task(tinkerPatchAllFlavorRelease){
group='tinker'
deforiginOldPath=getTinkerBuildFlavorDirectory()
for(Stringflavor:
flavors){
deftinkerTask=tasks.getByName("tinkerPatch${flavor.capitalize()}Release")
dependsOntinkerTask
defpreAssembleTask=tasks.getByName("process${flavor.capitalize()}ReleaseManifest")
preAssembleTask.doFirst{
StringflavorName=preAssembleTask.name.substring(7,8).toLowerCase()+preAssembleTask.name.substring(8,preAssembleTask.name.length()-15)
project.tinkerPatch.oldApk="${originOldPath}/${flavorName}/${project.name}-${flavorName}-release.apk"
project.tinkerPatch.buildConfig.applyMapping="${originOldPath}/${flavorName}/${project.name}-${flavorName}-release-mapping.txt"
project.tinkerPatch.buildConfig.applyResourceMapping="${originOldPath}/${flavorName}/${project.name}-${flavorName}-release-R.txt"
}
}
}
task(tinkerPatchAllFlavorDebug){
group='tinker'
deforiginOldPath=getTinkerBuildFlavorDirectory()
for(Stringflavor:
flavors){
deftinkerTask=tasks.getByName("tinkerPatch${flavor.capitalize()}Debug")
dependsOntinkerTask
defpreAssembleTask=tasks.getByName("process${flavor.capitalize()}DebugManifest")
preAssembleTask.doFirst{
StringflavorName=preAssembleTask.name.substring(7,8).toLowerCase()+preAssembleTask.name.substring(8,preAssembleTask.name.length()-13)
project.tinkerPatch.oldApk="${originOldPath}/${flavorName}/${project.name}-${flavorName}-debug.apk"
project.tinkerPatch.buildConfig.applyMapping="${originOldPath}/${flavorName}/${project.name}-${flavorName}-debug-mapping.txt"
project.tinkerPatch.buildConfig.applyResourceMapping="${originOldPath}/${flavorName}/${project.name}-${flavorName}-debug-R.txt"
}
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 修复 框架 Tinker 集成