目录
前言
记录一下Bugly 热修复集成步骤,以及使用注意事项。Bugly目前采用微信Tinker方案。
一、配置
1.添加插件依赖
工程目录下 build.gradle
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.5.2'
// tinkersupport插件(1.0.3以上无须再配置tinker插件)
classpath "com.tencent.bugly:tinker-support:1.2.0"
}
}
2.集成SDK
app module下 build.gradle
apply plugin: 'com.android.application'
android {
compileSdkVersion 30
buildToolsVersion "30.0.1"
// recommend
dexOptions {
jumboMode = true
}
// 签名配置
signingConfigs {
release {
try {
storeFile file("./keystore/xxxx.jks")
storePassword "xxxx"
keyAlias "xxxx"
keyPassword "xxxx"
} catch (ex) {
throw new InvalidUserDataException(ex.toString())
}
}
debug {
try {
storeFile file("./keystore/xxxx.jks")
storePassword "xxxx"
keyAlias "xxxx"
keyPassword "xxxx"
} catch (ex) {
throw new InvalidUserDataException(ex.toString())
}
}
}
defaultConfig {
applicationId "com.xxxx.tinker"
minSdkVersion 21
targetSdkVersion 30
versionCode 1
versionName "1.0.1"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
// 开启multidex
multiDexEnabled true
ndk {
// 设置支持的SO库架构
abiFilters 'x86', 'armeabi-v7a', 'x86_64', 'arm64-v8a'//,'armeabi'
}
}
buildTypes {
release {
minifyEnabled true
signingConfig signingConfigs.release
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.1'
implementation 'androidx.multidex:multidex:2.0.0'// 多dex配置
implementation 'com.tencent.bugly:crashreport_upgrade:latest.release'
//1. 指定tinker依赖版本(注:应用升级1.3.5版本起,不再内置tinker)
implementation 'com.tencent.tinker:tinker-android-lib:1.9.14.3'
implementation 'com.tencent.bugly:nativecrashreport:latest.release'
}
注意的地方:签名配置和多dex配置;com.tencent.tinker:tinker-android-lib:1.9.14.3 版本最好与 BuglyHotfixDemo 中保持一致。
在 app module下 build.gradle中添加
// 依赖插件脚本
apply from: 'tinker-support.gradle'
创建tinker-support.gradle文件
参考BuglyHotfixDemo 的配置
apply plugin: 'com.tencent.bugly.tinker-support'
def bakPath = file("${buildDir}/bakApk/")
/**
* 此处填写每次构建生成的基准包目录 就是用于生成Patch 时才用到的有问题的基准包
*/
def baseApkDir = "app-0919-17-36-46"
/**
* 对于插件各参数的详细解析请参考,如果没有特殊需求下面的参数都可以不用更改;如果apk需要加固等可以参考具体描述设置参数
*/
tinkerSupport {
// 开启tinker-support插件,默认值true
enable = true
// 指定归档目录,默认值当前module的子目录tinker
autoBackupApkDir = "${bakPath}"
//建议设置true,用户就不用再自己管理tinkerId的命名,插件会为每一次构建的base包自动生成唯一的tinkerId,默认命名规则是versionname.versioncode_时间戳
//具体参考https://github.com/BuglyDevTeam/Bugly-Android-Demo/wiki/Tinker-ID%E8%AF%A5%E6%80%8E%E4%B9%88%E8%AE%BE%E7%BD%AE
autoGenerateTinkerId = true
//tinkerId必须保证唯一性,如果两个base包的tinkerid是一样的,并且都联网激活了,那么后续补丁上传到后台的时候会出现匹配错误
tinkerId = ""
// 是否启用覆盖tinkerPatch配置功能,默认值false
// 开启后tinkerPatch配置不生效,即无需添加tinkerPatch
//当overrideTinkerPatchConfiguration=true时,tinkerPatch可以省略不写,Bugly会加载默认的Tinker配置,但请注意,
// 如果你的so文件不是存放在libs目录下(与src目录同级),又或者资源文件的存放在你自定义的目录中,
// 那么这时候你要小心了,这些文件在制作补丁时不会被检测,
// 也就是说这些so文件和资源文件将不会被热修复,这种情况下就需要将
//overrideTinkerPatchConfiguration=false,并设置tinkerPatch的lib和res属性。
overrideTinkerPatchConfiguration = true
// 编译补丁包时,必需指定基线版本的apk,默认值为空
// 如果为空,则表示不是进行补丁包的编译
// @{link tinkerPatch.oldApk }
baseApk = "${bakPath}/${baseApkDir}/app-release.apk"
// 对应tinker插件applyMapping
baseApkProguardMapping = "${bakPath}/${baseApkDir}/app-release-mapping.txt"
// 对应tinker插件applyResourceMapping
baseApkResourceMapping = "${bakPath}/${baseApkDir}/app-release-R.txt"
//构建多渠道补丁时使用
// buildAllFlavorsDir = "${bakPath}/${baseApkDir}"
// 是否开启加固模式,默认为false
isProtectedApp = true
enableProxyApplication = true
supportHotplugComponent = true
ignoreWarning = true
}
/**
* 一般来说,我们无需对下面的参数做任何的修改
* 对于各参数的详细介绍请参考:
* https://github.com/Tencent/tinker/wiki/Tinker-%E6%8E%A5%E5%85%A5%E6%8C%87%E5%8D%97
*/
tinkerPatch {
//oldApk ="${bakPath}/${appName}/app-debug.apk"
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
//tinkerId = "1.0.1-patch"
//applyMapping = "${bakPath}/${appName}/app-debug-mapping.txt" // 可选,设置mapping文件,建议保持旧apk的proguard混淆方式
//applyResourceMapping = "${bakPath}/${appName}/app-debug-R.txt" // 可选,设置R.txt文件,通过旧apk文件保持ResId的分配
}
}
3.初始化SDK
有两种初始化方式,结合项目实际场景选择,这里采用enableProxyApplication = true 的情况,在tinker-support.gradle中进行修改。需要接入SDK 1.2.2版本 和 插件版本 1.0.3以上。
MyApplication中appId替换成你的在Bugly平台申请的appId
public class MyApplication extends Application {
private static final String TAG ="MyApplication" ;
@Override
public void onCreate() {
super.onCreate();
// 设置是否开启热更新能力,默认为true
Beta.enableHotfix = true;
// 设置是否自动下载补丁,默认为true
Beta.canAutoDownloadPatch = true;
// 设置是否自动合成补丁,默认为true
Beta.canAutoPatch = true;
// 设置是否提示用户重启,默认为false
Beta.canNotifyUserRestart = true;
// 补丁回调接口
Beta.betaPatchListener = new BetaPatchListener() {
@Override
public void onPatchReceived(String patchFile) {
Log.d(TAG,"补丁下载地址" + patchFile);
// Toast.makeText(getApplication(), "补丁下载地址" + patchFile, Toast.LENGTH_SHORT).show();
}
@Override
public void onDownloadReceived(long savedLength, long totalLength) {
Log.d(TAG,String.format(Locale.getDefault(), "%s %d%%",
Beta.strNotificationDownloading,
(int) (totalLength == 0 ? 0 : savedLength * 100 / totalLength)));
// Toast.makeText(getApplication(),
// String.format(Locale.getDefault(), "%s %d%%",
// Beta.strNotificationDownloading,
// (int) (totalLength == 0 ? 0 : savedLength * 100 / totalLength)),
// Toast.LENGTH_SHORT).show();
}
@Override
public void onDownloadSuccess(String msg) {
Log.d(TAG,"补丁下载成功");
// Toast.makeText(getApplication(), "补丁下载成功", Toast.LENGTH_SHORT).show();
}
@Override
public void onDownloadFailure(String msg) {
Log.d(TAG,"补丁下载失败");
// Toast.makeText(getApplication(), "补丁下载失败", Toast.LENGTH_SHORT).show();
}
@Override
public void onApplySuccess(String msg) {
Log.d(TAG,"补丁应用成功");
// Toast.makeText(getApplication(), "补丁应用成功", Toast.LENGTH_SHORT).show();
}
@Override
public void onApplyFailure(String msg) {
Log.d(TAG,"补丁应用失败");
// Toast.makeText(getApplication(), "补丁应用失败", Toast.LENGTH_SHORT).show();
}
@Override
public void onPatchRollback() {
}
};
//设置开发设备,默认false。可用于调试,后台下发补丁时会有选择
// Bugly.setIsDevelopmentDevice(getApplicationContext(), true);//开发设备
// 这里实现SDK初始化,appId替换成你的在Bugly平台申请的appId
// 调试时,将第三个参数改为true
Bugly.init(this, "xxxxx", true);
}
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
// you must install multiDex whatever tinker is installed!
MultiDex.install(base);
// 安装tinker
Beta.installTinker();
}
}
4.AndroidManifest.xml配置
注:1.3.1及以上版本,可以不用配置
5.混淆配置
-dontwarn com.tencent.bugly.**
-keep public class com.tencent.bugly.**{*;}
# tinker混淆规则
-dontwarn com.tencent.tinker.**
-keep class com.tencent.tinker.** { *; }
# 避免影响升级功能,需要keep住support包的类
-keep class android.support.**{*;}
二.使用
可以先了解下bugly上的接入流程
- 打基准包安装并上报联网(注:填写唯一的tinkerId),基准包需要在有网下打开一次,后面上传补丁包才能匹配上
- 对基准包的bug修复(可以是Java代码变更,资源的变更)
- 修改基准包路径、修改补丁包tinkerId、mapping文件路径(如果开启了混淆需要配置)、resId文件路径
- 执行buildTinkerPatchRelease打Release版本补丁包
- 选择app/build/outputs/patch目录下的补丁包并上传(注:不要选择tinkerPatch目录下的补丁包,不然上传会有问题)
- 编辑下发补丁规则,点击立即下发
- 杀死进程并重启基准包,请求补丁策略(SDK会自动下载补丁并合成)
- 再次重启基准包,检验补丁应用结果
- 查看页面,查看激活数据的变化
1.编译基准包
需要对tinkerId进行修改,在 tinker-support.gradle 中tinkerId="1.0.1.1-base",可以根据versionNme,versionCode,时间戳等生成,需要保证唯一。
建议使用插件替我们自动生成,配置 autoGenerateTinkerId = true (手动修改的tinkerId 就没用了)。这样就不必太关注于怎样命名了,规则是versionname.versioncode_时间戳 ,将编译好的apk 拖入AS 中分析可以查看
正常编译release包,就会在app/build/bakApk 下生成基准包,注意:正式发版生成的基准包要保留!保留!!保留!!!用于以后生成补丁包。
2.根据基准包生成补丁包
进行bug 修复后,同样需要对 tinker-support.gradle 文件中一些配置做修改。
如果配置了 autoGenerateTinkerId = true 就不用去管 tinkerId 了。不然仍需要修改tinkerId,例如tinkerId="1.0.1.1-patch",注意与打基准包时的tinkerId不一样。
执行task buildTinkerPatchRelease 生成补丁包
补丁包生成路径build/outputs/patch
3.上传补丁包
在bugly --》 应用升级 --》热更新 发布新补丁,将patch_signed_7zip.apk 进行上传
开发设备选项,对应MyApplication 中设置了Bugly.setIsDevelopmentDevice(getApplicationContext(), true);的设备
四.多渠道打包
productFlavors 方式需要为所有渠道生成补丁包,因为这种打包方式会修改buildConfig类中的FLAVOR字段,导致生成的不同渠道包的dex是不一样的,无法实现一个补丁包覆盖所有渠道。
Walle(瓦力):Android Signature V2 Scheme签名下的新一代渠道包打包神器:
https://github.com/Meituan-Dianping/walle
Walle通过修改APK Signature Block来添加自定义的渠道信息来生成渠道包,不会改变dex结构。
实际项目中使用Walle正常打多渠道包就行,基于基准包生成的补丁包也只需要一个,就可以实现多渠道覆盖。
五.一点注意
在开发阶段可以把插件脚本 //apply from: 'tinker-support.gradle' 注释,避免每次编译都会在build/bakApk下生成很多基准包文件
遇到这个错误:
在gradle.properties 中加入
android.enableR8.libraries = false
android.enableR8 = false
本文地址:https://blog.csdn.net/Woolle/article/details/108704541
如您对本文有疑问或者有任何想说的,请点击进行留言回复,万千网友为您解惑!
网友评论