2025年热修复学习六:Tinker详解一

热修复学习六:Tinker详解一一 Tinker 官网介绍 官网 https github com Tencent tinker wiki 二 Tinker 核心原理 基于 android 原生的 ClassLoader 开发了自己的 ClassLoader 基于 android 原生的 aapt 开发了自己的 aapt 微信团队自己基于 Dex 文件的格式

大家好,我是讯享网,很高兴认识大家。

一、Tinker官网介绍

官网:https://github.com/Tencent/tinker/wiki

二、Tinker核心原理

  • 基于android原生的ClassLoader,开发了自己的ClassLoader
  • 基于android原生的aapt,开发了自己的aapt
  • 微信团队自己基于Dex文件的格式,研发了DexDiff算法

三、使用Tinker完成bug修复

1、集成阶段

gradle中添加Tinker依赖

app的build.gradle文件中:

//生成application时使用 compileOnly('com.tencent.tinker:tinker-android-anno:1.7.7') //tinker的核心SDK库 implementation('com.tencent.tinker:tinker-android-lib:1.7.7') 

讯享网

implementation不仅在编译时使用,也会打包到apk中

compileOnly仅在编译时使用,不参与打包,从而减少apk包的体积

在代码中完成对Tinker的初始化

 

2、准备阶段

  • build一个old apk并安装到手机
  • 修改一些功能后,build一个new apk

3、patch生成方式

使用命令行的方式完成patch包的生成

讯享网java -jar tinker-patch-cli-1.7.7.jar -old old.apk -new new.apk -config tinker_config.xml -out output/

使用以上方式可能会爆出“tinkerId is not set”的错误

解决办法:Manifest文件按照如下方式设置

<application android:name=".tinker.MyTinkerApplication" android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" 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> <meta-data android:name="TINKER_ID" android:value="1.0" /> </application>

 把生成的文件push到手机上:

讯享网adb push patch_signed.apk /storage/emulated/0/Android/data/com.gs.tinker/cache/tpatch/imooc.apk

使用gradle插件的方式完成patch包的生成

在gradle中正确配置tinker参数(非常重要)

在android studio中直接生成patch文件

步骤详解:

1、manifest文件中设置的tinkerid删除,因为我们需要在gradle文件中设置tinkerid

2、在gradle.properties中进行配置:用来表明tinker的版本号

# Project-wide Gradle settings.

# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.

# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html

# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx1536m

# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
TINKER_VERSION=1.9.1

3、在工程的gradle文件中加入一个classpath


讯享网

参考文章:腾讯Tinker 热修复 Andriod studio 3.0 配置和集成(一)

讯享网classpath "com.tencent.tinker:tinker-patch-gradle-plugin:${TINKER_VERSION}"
buildscript { repositories { google() jcenter() } dependencies { classpath 'com.android.tools.build:gradle:3.0.1' classpath "com.tencent.tinker:tinker-patch-gradle-plugin:${TINKER_VERSION}" // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } }

4、在APP的gradle文件中加入:

讯享网//可选,用于生成application类 implementation("com.tencent.tinker:tinker-android-lib:${TINKER_VERSION}") { changing = true } //tinker的核心库 annotationProcessor("com.tencent.tinker:tinker-android-anno:${TINKER_VERSION}") { changing = true } compileOnly("com.tencent.tinker:tinker-android-anno:${TINKER_VERSION}") { changing = true }

谨记:里面是双引号,单引号会报错:

Failed to resolve: com.tencent Show in File

5、Tinker gradle参数配置 APP的build.gradle:

讯享网apply plugin: 'com.android.application' configurations.all { resolutionStrategy.force 'com.android.support:support-annotations:26.1.0' } //配置java版本 def javaVersion = JavaVersion.VERSION_1_8 //buildDir 就是build文件目录 这行代码就是在build目录下创建一个backApk的文件夹 def bakPath = file("${buildDir}/bakApk/") android { compileSdkVersion 26 defaultConfig { applicationId "com.gs.tinker" minSdkVersion 19 targetSdkVersion 26 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" multiDexEnabled true javaCompileOptions { // 显式声明支持注解 annotationProcessorOptions { includeCompileClasspath true } } } signingConfigs { //签名打包 release { storeFile file("tinkerdemo.jks") storePassword "" keyAlias "tinker" keyPassword "" } } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' signingConfig signingConfigs.release } } } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation 'com.android.support:appcompat-v7:26.1.0' implementation 'com.android.support.constraint:constraint-layout:1.1.3' testImplementation 'junit:junit:4.12' androidTestImplementation 'com.android.support.test:runner:1.0.2' androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' //networklib implementation project(':networklib') //Tinker // implementation('com.tencent.tinker:tinker-android-lib:${TINKER_VERSION}'){ changing = true } // annotationProcessor("com.tencent.tinker:tinker-android-anno:${TINKER_VERSION}") { changing = true } // compileOnly('com.tencent.tinker:tinker-android-anno:${TINKER_VERSION}'){ changing = true } //可选,用于生成application类 implementation("com.tencent.tinker:tinker-android-lib:${TINKER_VERSION}") { changing = true } //tinker的核心库 annotationProcessor("com.tencent.tinker:tinker-android-anno:${TINKER_VERSION}") { changing = true } compileOnly("com.tencent.tinker:tinker-android-anno:${TINKER_VERSION}") { changing = true } implementation "com.android.support:multidex:1.0.1" } //变量块 ext { tinkerEnable = true tinkerOldApkPath = "${bakPath}/" tinkerApplyMappingPath = "${bakPath}/" tinkerApplyMappingPath = "${bakPath}/" tinkerID = "1.0" } def buildWithTinker() { return ext.tinkerEnable } def getOldApkPath() { return ext.tinkerOldApkPath } def getApplyMappingPath() { return ext.tinkerApplyMappingPath } def getApplyResourceMappingPath() { return ext.tinkerApplyMappingPath } def getTinkerIdValue() { return ext.tinkerID } if (buildWithTinker()) { // start to use tinker apply plugin: 'com.tencent.tinker.patch' //configure all parameters of tinker tinkerPatch { oldApk = getOldApkPath() //指定 old apk文件路径 ignoreWarning = false //不忽略tinker的警告,有则终止patch文件的生成 useSign = true //强制patch文件也是用签名 tinkerEnable = buildWithTinker() //指定是否启动tinker buildConfig { applyMapping = getApplyMappingPath() //指定old apk打包时所使用的混淆文件 applyResourceMapping = getApplyResourceMappingPath() //指定old apk的资源文件 tinkerId = getTinkerIdValue() //指定tinker ID keepDexApply = false } dex { dexMode = "jar" // jar、raw pattern = ["classes*.dex", "assets/secondary-dex-7.jar"] //指定dex文件目录 loader = ["com.com.gs.tinker.tinker.MyTinkerApplication"] //指定加载patch文件时用到的类 } lib { pattern = ["libs/*/*.so"] } res { //指定tinker可以修改的资源路径 pattern = ["res/*", "assets/*", "resources.arcw", "AndroidManifest.xml"] ignoreChange = ["assets/sample_meta.txt"] //指定不受影响的资源路径 largeModSize = 100 //资源修改大小默认值为100k,若超过此数值,tinker会调用算法缩小patch文件的体积 } packageConfig { configField("patchMessage", "fix the 1.0 version's bugs") configField("patchVersion", "1.0") } } //是否配置了多渠道 List<String> flavors = new ArrayList<>(); project.android.productFlavors.each { flavor -> flavors.add(flavor.name) } boolean hasFlavors = flavors.size() > 0 / * bak apk and mapping */ android.applicationVariants.all { variant -> / * task type, you want to bak */ def taskName = variant.name def date = new Date().format("MMdd-HH-mm-ss") tasks.all { if ("assemble${taskName.capitalize()}".equalsIgnoreCase(it.name)) { it.doLast { copy { def fileNamePrefix = "${project.name}-${variant.baseName}" def newFileNamePrefix = hasFlavors ? "${fileNamePrefix}" : "${fileNamePrefix}-${date}" def destPath = hasFlavors ? file("${bakPath}/${project.name}-${date}/${variant.flavorName}") : bakPath // from variant.outputs.outputFile from variant.outputs.first().outputFile //variant.outputs.all into destPath rename { String fileName -> fileName.replace("${fileNamePrefix}.apk", "${newFileNamePrefix}.apk") } from "${buildDir}/outputs/mapping/${variant.dirName}/mapping.txt" into destPath rename { String fileName -> fileName.replace("mapping.txt", "${newFileNamePrefix}-mapping.txt") } from "${buildDir}/intermediates/symbols/${variant.dirName}/R.txt" into destPath rename { String fileName -> fileName.replace("R.txt", "${newFileNamePrefix}-R.txt") } } } } } } }

6、删除build文件夹,在控制台输入 gralew assembleRelease

7、生成了以下文件:

将文件名称写入build.gradle文件中

8、点击如图所示的tinkerPatchRelease命令:

9、以上命令执行完成以后,就会生成patch文件

然后把这个文件push到手机上就可以了。

小讯
上一篇 2025-04-06 09:38
下一篇 2025-03-14 09:58

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/62018.html