Tinker热更新(微信)详细教程

2023-11-21 07:59

本文主要是介绍Tinker热更新(微信)详细教程,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Tinker热更新(微信)详细教程

现在热更新有很多的选择,但是有很多都有限制,例如不能更新资源文件,不支持android7.0等,经过多种尝试,发现tinker是支持面最广的热更新插件了。
Tinker官方GitHub

Tinker和其他常见热更新特点对比

Tinker 执行原理分析

个人观点,不知道是否正确
在原项目中集成tinker的plugin,这时会生成old.apk oldresource-R.txt文件及old-mapping.txt(如果开启混淆才会有)
项目bug修复后,配置oldapk,resource,mapping文件,会对比生成一个patch文件,这个文件后缀名默认是apk,但不是一个可以安装的apk,可以根据自己的情况任意修改后缀名,把这个patch文件放到服务端,如果app需要修复bug则下载这个patch,然后执行后就会成修复后的app了

Tinker集成过程

  • 1.项目project gradle引入
dependencies {classpath 'com.android.tools.build:gradle:2.0.0'//引入tinker plugin 版本可以参考tinker官方githubclasspath ('com.tencent.tinker:tinker-patch-gradle-plugin:1.7.7')       }
  • 2.Moudle app gradle引入library
dependencies {compile 'com.android.support:appcompat-v7:23.2.1'compile 'com.android.support:support-v4:23+'debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5'releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5'//Tinker需要的library开始//可选,用于生成application类provided('com.tencent.tinker:tinker-android-anno:1.7.7')//tinker的核心库compile('com.tencent.tinker:tinker-android-lib:1.7.7')compile "com.android.support:multidex:1.0.1"//Tinker需要的library结束
}
  • 3.设置app的build.gradle

a,如果设置了dex分包则在android节点下的defaultConfig设置

  multiDexEnabled true

b,在app的build.gradle的末尾设置tinker的配置

以下内容很重要,请仔细看,或者直接复制进去后自己根据情况修改

/**Tinker 相关配置----------------开始-----------------------------------*/
//apply tinker插件
apply plugin: 'com.tencent.tinker.patch'
def bakPath = file("${buildDir}/bakApk/")
//这个函数返回的是tinkerid
//tinkerid是用来做代码更改对比的,
//例如 
//线上的是1.0版本
//则这里配置的oldapk 路径就是线上的apk在本地的路径
//如果要在这个版本上更新,则这里返回的string应该与线上版本设置的一模一样
def gitSha() {return "1.0"
}
ext {//for some reason, you may want to ignore tinkerBuild, such as instant run debug build?//变量,控制Tinker是否可用tinkerEnabled = true//for normal build//old apk file to build patch apk 旧包名//这里对应的路径就是app moudle下的oldApk路径(没有则自己新建),并且把需要修复版本的apk放进去tinkerOldApkPath = "${projectDir}/oldApk/old.apk"//proguard mapping file to build patch apk  旧包混淆文件目录//tinkerApplyMappingPath = "${bakPath}/app-debug-1018-17-32-47-mapping.txt"//混淆的mapping 有则配置路径,我这里没有,所以随便写tinkerApplyMappingPath = "${bakPath}/"//resource R.txt to build patch apk, must input if there is resource changed 旧包R文件//跟待修复版本apk一样,把老版本的resoures-r.txt放进来//这个是为了避免新旧版本R不一致,导致找不到资源闪退tinkerApplyResourcePath = "${projectDir}/oldApk/old-R.txt"//only use for build all flavor, if not, just ignore this field  多渠道//tinkerBuildFlavorDirectory = "${bakPath}/app-1018-17-32-47"
}
def getOldApkPath() {return  ext.tinkerOldApkPath
}
def getApplyMappingPath() {return  ext.tinkerApplyMappingPath
}
def getApplyResourceMappingPath() {return  ext.tinkerApplyResourcePath
}
def getTinkerIdValue() {return  gitSha()
}
def buildWithTinker() {return  ext.tinkerEnabled
}
def getTinkerBuildFlavorDirectory() {return ext.tinkerBuildFlavorDirectory
}
if (buildWithTinker()) {apply plugin: 'com.tencent.tinker.patch'tinkerPatch {/*** 基准apk包路径,也就是旧包路径* */oldApk = getOldApkPath()/*** 如果出现以下的情况,并且ignoreWarning为false,我们将中断编译。因为这些情况可能会导致编译出来的patch包* 带来风险:* 1. minSdkVersion小于14,但是dexMode的值为"raw";* 2. 新编译的安装包出现新增的四大组件(Activity, BroadcastReceiver...);* 3. 定义在dex.loader用于加载补丁的类不在main dex中;* 4. 定义在dex.loader用于加载补丁的类出现修改;* 5. resources.arsc改变,但没有使用applyResourceMapping编译。* */ignoreWarning = false/*** 在运行过程中,我们需要验证基准apk包与补丁包的签名是否一致,我们是否需要为你签名* */useSign = truebuildConfig {/*** 可选参数;在编译新的apk时候,我们希望通过保持旧apk的proguard混淆方式,从而减少补丁包的大小。这个只* 是推荐的,但设置applyMapping会影响任何的assemble编译。* */applyMapping = getApplyMappingPath()/*** 可选参数;在编译新的apk时候,我们希望通过旧apk的R.txt文件保持ResId的分配,这样不仅可以减少补丁包的* 大小,同时也避免由于ResId改变导致remote view异常。* */applyResourceMapping = getApplyResourceMappingPath()/*** 在运行过程中,我们需要验证基准apk包的tinkerId是否等于补丁包的tinkerId。这个是决定补丁包能运行在哪些* 基准包上面,一般来说我们可以使用git版本号、versionName等等。* */tinkerId = getTinkerIdValue()}dex {/*** optional,default 'jar'* only can be 'raw' or 'jar'. for raw, we would keep its original format* for jar, we would repack dexes with zip format.* if you want to support below 14, you must use jar* or you want to save rom or check quicker, you can use raw mode also*/dexMode = "jar"/*** necessary,default '[]'* what dexes in apk are expected to deal with tinkerPatch* it support * or ? pattern.*/pattern = ["classes*.dex","assets/secondary-dex-?.jar"]/*** necessary,default '[]'* Warning, it is very very important, loader classes can't change with patch.* thus, they will be removed from patch dexes.* you must put the following class into main dex.* Simply, you should add your own application {@code tinker.sample.android.SampleApplication}* own tinkerLoader, and the classes you use in them**///这个里面是设置你不希望更改的类,一般可以设置一些永远不会变的类,也可以不写loader = [//use sample, let BaseBuildInfo unchangeable with tinker"com.ubestkid.BlApplication","com.ubestkid.foundation.base.BaseApplication"]}lib {/*** 需要处理lib路径,支持*、?通配符,必须使用'/'分割。与dex.pattern一致, 路径是相对安装包的,例如/assets/...*/pattern = ["lib/armeabi/*.so"]}res {/*** 需要处理res路径,支持*、?通配符,必须使用'/'分割。与dex.pattern一致, 路径是相对安装包的,例如/assets/...,* 务必注意的是,只有满足pattern的资源才会放到合成后的资源包。*/pattern = ["res/*", "assets/*", "resources.arsc", "AndroidManifest.xml"]/*** 支持*、?通配符,必须使用'/'分割。若满足ignoreChange的pattern,在编译时会忽略该文件的新增、删除与修改。* 最极端的情况,ignoreChange与上面的pattern一致,即会完全忽略所有资源的修改。*/ignoreChange = ["assets/sample_meta.txt"]/*** 对于修改的资源,如果大于largeModSize,我们将使用bsdiff算法。这可以降低补丁包的大小,但是会增加合成* 时的复杂度。默认大小为100kb*/largeModSize = 100}packageConfig {/*** configField("key", "value"), 默认我们自动从基准安装包与新安装包的Manifest中读取tinkerId,并自动* 写入configField。在这里,你可以定义其他的信息,在运行时可以通过TinkerLoadResult.getPackageConfigByName得到相应的数值。但是建议直接通过修改代码来实现,例如BuildConfig。*/configField("patchMessage", "tinker is sample to use")}sevenZip {/*** 例如"com.tencent.mm:SevenZip:1.1.10",将自动根据机器属性获得对应的7za运行文件,推荐使用*/zipArtifact = "com.tencent.mm:SevenZip:1.1.10"}/***  文件名                              描述*  patch_unsigned.apk                  没有签名的补丁包*  patch_signed.apk                  签名后的补丁包*  patch_signed_7zip.apk              签名后并使用7zip压缩的补丁包,也是我们通常使用的补丁包。但正式发布的时候,最好不要以.apk结尾,防止被运营商挟持。*  log.txt                              在编译补丁包过程的控制台日志*  dex_log.txt                          在编译补丁包过程关于dex的日志*  so_log.txt                          在编译补丁包过程关于lib的日志*  tinker_result                      最终在补丁包的内容,包括diff的dex、lib以及assets下面的meta文件*  resources_out.zip                  最终在手机上合成的全量资源apk,你可以在这里查看是否有文件遗漏*  resources_out_7z.zip              根据7zip最终在手机上合成的全量资源apk*  tempPatchedDexes                  在Dalvik与Art平台,最终在手机上合成的完整Dex,我们可以在这里查看dex合成的产物。*** *//*** bak apk and mapping*  创建Task并执行文件操作*/android.applicationVariants.all { variant ->/*** task type, you want to bak*/def taskName = variant.namedef 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 = "${fileNamePrefix}-${date}"def destPath = bakPathfrom variant.outputs.outputFileinto destPathrename { String fileName ->fileName.replace("${fileNamePrefix}.apk", "${newFileNamePrefix}.apk")}from "${buildDir}/outputs/mapping/${variant.dirName}/mapping.txt"into destPathrename { String fileName ->fileName.replace("mapping.txt", "${newFileNamePrefix}-mapping.txt")}from "${buildDir}/intermediates/symbols/${variant.dirName}/R.txt"into destPathrename { String fileName ->fileName.replace("R.txt", "${newFileNamePrefix}-R.txt")}}}}}}}
}
/**Tinker 相关配置----------------结束-----------------------------------*/

-4.设置application

新建一个类继承DefaultApplicationLike
注意,这个并不是继承原生的application,也不是application的子类
里面有提供getApplication则是真正的application
初始化的一些代码可以写在onBaseContextAttached这个方法里面

@SuppressWarnings("unused")
@DefaultLifeCycle(application = "tinker.sample.android.app.SampleApplication",flags = ShareConstants.TINKER_ENABLE_ALL,loadVerifyFlag = false)
public class SampleApplicationLike extends DefaultApplicationLike {private static final String TAG = "Tinker.SampleApplicationLike";public SampleApplicationLike(Application application, int tinkerFlags, boolean tinkerLoadVerifyFlag,long applicationStartElapsedTime, long applicationStartMillisTime, Intent tinkerResultIntent) {super(application, tinkerFlags, tinkerLoadVerifyFlag, applicationStartElapsedTime, applicationStartMillisTime, tinkerResultIntent);}/*** install multiDex before install tinker* so we don't need to put the tinker lib classes in the main dex** @param base*/@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)@Overridepublic void onBaseContextAttached(Context base) {super.onBaseContextAttached(base);//you must install multiDex whatever tinker is installed!MultiDex.install(base);SampleApplicationContext.application = getApplication();SampleApplicationContext.context = getApplication();TinkerManager.setTinkerApplicationLike(this);TinkerManager.initFastCrashProtect();//should set before tinker is installedTinkerManager.setUpgradeRetryEnable(true);//optional set logIml, or you can use default debug logTinkerInstaller.setLogIml(new MyLogImp());//installTinker after load multiDex//or you can put com.tencent.tinker.** to main dexTinkerManager.installTinker(this);Tinker tinker = Tinker.with(getApplication());}@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)public void registerActivityLifecycleCallbacks(Application.ActivityLifecycleCallbacks callback) {getApplication().registerActivityLifecycleCallbacks(callback);}}

-5,修改AndroidManifest.xml
这里的name设置的名称应该与上一步一致

@DefaultLifeCycle(application = "tinker.sample.android.app.SampleApplication",flags = ShareConstants.TINKER_ENABLE_ALL,loadVerifyFlag = false)
 <application
 android:name="tinker.sample.android.app.SampleApplication"//other />

这里可能会报红,不用管,编译后会自动生成这个application

-6.设置加载patch的代码
在程序的入口或者你想加载补丁的地方设置代码

//path根据自己下载后保存的路径填写,这里不用判断文件是否存在,因为文件不存在tinker会自动判断的String path = ""; //注意这个方法名,是onReceiveUpgradePatch,TinkerInstaller有个方法名与这个非常想,别写错了
TinkerInstaller.onReceiveUpgradePatch(getApplicationContext(),path);

OK 调试,应该就好了,如果有其他问题可以评论留言,或者加我QQ 857879622 欢迎骚扰

另外,希望可以进去看看我的github,虽然很烂。。。后期会越来越好的
博主GitHub
我的个人主页

以下的文章也非常不错,可以去看看

Tinker微信热修复框架新手接入

这篇关于Tinker热更新(微信)详细教程的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/400954

相关文章

Python与MySQL实现数据库实时同步的详细步骤

《Python与MySQL实现数据库实时同步的详细步骤》在日常开发中,数据同步是一项常见的需求,本篇文章将使用Python和MySQL来实现数据库实时同步,我们将围绕数据变更捕获、数据处理和数据写入这... 目录前言摘要概述:数据同步方案1. 基本思路2. mysql Binlog 简介实现步骤与代码示例1

基于C#实现PDF转图片的详细教程

《基于C#实现PDF转图片的详细教程》在数字化办公场景中,PDF文件的可视化处理需求日益增长,本文将围绕Spire.PDFfor.NET这一工具,详解如何通过C#将PDF转换为JPG、PNG等主流图片... 目录引言一、组件部署二、快速入门:PDF 转图片的核心 C# 代码三、分辨率设置 - 清晰度的决定因

Java中HashMap的用法详细介绍

《Java中HashMap的用法详细介绍》JavaHashMap是一种高效的数据结构,用于存储键值对,它是基于哈希表实现的,提供快速的插入、删除和查找操作,:本文主要介绍Java中HashMap... 目录一.HashMap1.基本概念2.底层数据结构:3.HashCode和equals方法为什么重写Has

Java Scanner类解析与实战教程

《JavaScanner类解析与实战教程》JavaScanner类(java.util包)是文本输入解析工具,支持基本类型和字符串读取,基于Readable接口与正则分隔符实现,适用于控制台、文件输... 目录一、核心设计与工作原理1.底层依赖2.解析机制A.核心逻辑基于分隔符(delimiter)和模式匹

Java使用正则提取字符串中的内容的详细步骤

《Java使用正则提取字符串中的内容的详细步骤》:本文主要介绍Java中使用正则表达式提取字符串内容的方法,通过Pattern和Matcher类实现,涵盖编译正则、查找匹配、分组捕获、数字与邮箱提... 目录1. 基础流程2. 关键方法说明3. 常见场景示例场景1:提取所有数字场景2:提取邮箱地址4. 高级

Unity新手入门学习殿堂级知识详细讲解(图文)

《Unity新手入门学习殿堂级知识详细讲解(图文)》Unity是一款跨平台游戏引擎,支持2D/3D及VR/AR开发,核心功能模块包括图形、音频、物理等,通过可视化编辑器与脚本扩展实现开发,项目结构含A... 目录入门概述什么是 UnityUnity引擎基础认知编辑器核心操作Unity 编辑器项目模式分类工程

spring AMQP代码生成rabbitmq的exchange and queue教程

《springAMQP代码生成rabbitmq的exchangeandqueue教程》使用SpringAMQP代码直接创建RabbitMQexchange和queue,并确保绑定关系自动成立,简... 目录spring AMQP代码生成rabbitmq的exchange and 编程queue执行结果总结s

Springboot项目构建时各种依赖详细介绍与依赖关系说明详解

《Springboot项目构建时各种依赖详细介绍与依赖关系说明详解》SpringBoot通过spring-boot-dependencies统一依赖版本管理,spring-boot-starter-w... 目录一、spring-boot-dependencies1.简介2. 内容概览3.核心内容结构4.

MySQL 数据库表操作完全指南:创建、读取、更新与删除实战

《MySQL数据库表操作完全指南:创建、读取、更新与删除实战》本文系统讲解MySQL表的增删查改(CURD)操作,涵盖创建、更新、查询、删除及插入查询结果,也是贯穿各类项目开发全流程的基础数据交互原... 目录mysql系列前言一、Create(创建)并插入数据1.1 单行数据 + 全列插入1.2 多行数据

MySQL中优化CPU使用的详细指南

《MySQL中优化CPU使用的详细指南》优化MySQL的CPU使用可以显著提高数据库的性能和响应时间,本文为大家整理了一些优化CPU使用的方法,大家可以根据需要进行选择... 目录一、优化查询和索引1.1 优化查询语句1.2 创建和优化索引1.3 避免全表扫描二、调整mysql配置参数2.1 调整线程数2.