热更新笔记
https://bugly.qq.com/docs/user-guide/instruction-manual-android-hotfix-demo/?v=20200622202242
1. 集成
1.添加插件依赖
工程根目录下“build.gradle”文件中添加:
buildscript {repositories {jcenter()}dependencies {// tinkersupport插件, 其中lastest.release指拉取最新版本,也可以指定明确版本号,例如1.0.4classpath "com.tencent.bugly:tinker-support:1.2.0"}
}
2.集成SDK
1.在app module的“build.gradle”文件中添加
// 远程仓库集成方式(推荐)
implementation 'com.tencent.bugly:crashreport_upgrade:latest.release'
//1. 指定tinker依赖版本(注:应用升级1.3.5版本起,不再内置tinker)
//2.为了便于解答问题,这里的tinker版本建议跟随此处demo设置,如果微信更新了tinker版本,bugly会定期同步更新
implementation 'com.tencent.tinker:tinker-android-lib:1.9.14.3'
implementation 'com.tencent.bugly:nativecrashreport:latest.release'
2.在app module的“build.gradle”文件中添加:
// 依赖插件脚本
apply from: 'tinker-support.gradle'
2. 创建tinker-support.gradle文件
apply plugin: 'com.tencent.bugly.tinker-support'def bakPath = file("${buildDir}/bakApk/")/*** 此处填写每次构建生成的基准包目录*/
def baseApkDir = "app-0413-11-58-08"/*** 对于插件各参数的详细解析请参考,如果没有特殊需求下面的参数都可以不用更改;如果apk需要加固等可以参考具体描述设置参数*/
tinkerSupport {// 开启tinker-support插件,默认值trueenable = true// 指定归档目录,默认值当前module的子目录tinkerautoBackupApkDir = "${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%AEautoGenerateTinkerId = true//tinkerId必须保证唯一性,如果两个base包的tinkerid是一样的,并且都联网激活了,那么后续补丁上传到后台的时候会出现匹配错误tinkerId = "if autoGenerateTinkerId=true ,no need set here"// 是否启用覆盖tinkerPatch配置功能,默认值false// 开启后tinkerPatch配置不生效,即无需添加tinkerPatchoverrideTinkerPatchConfiguration = true// 编译补丁包时,必需指定基线版本的apk,默认值为空// 如果为空,则表示不是进行补丁包的编译// @{link tinkerPatch.oldApk }baseApk = "${bakPath}/${baseApkDir}/fwTeacher-v${build_version.version_name}.apk"// 对应tinker插件applyMappingbaseApkProguardMapping = "${bakPath}/${baseApkDir}/app-release-mapping.txt"// 对应tinker插件applyResourceMappingbaseApkResourceMapping = "${bakPath}/${baseApkDir}/app-release-R.txt"// buildAllFlavorsDir = "${bakPath}/${baseApkDir}"// 是否开启加固模式,默认为falseisProtectedApp = falseenableProxyApplication = falsesupportHotplugComponent = 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 = falseuseSign = truedex {dexMode = "jar"pattern = ["classes*.dex"]loader = ["com.tencent.tinker.loader.*","com.tencent.tinker.*","com.xkt.fwteacher.MyApplication","com.xkt.commonlib.bean.Env"]}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的分配}}android.applicationVariants.all { variant ->def taskName = variant.nametasks.all {if ("assemble${taskName.capitalize()}".equalsIgnoreCase(it.name)) {it.doLast {copy {def fileNamePrefix = "${project.name}-${variant.baseName}"def newFileNamePrefix = "fwTeacher-v${versionName}"def destPath = bakPathif (variant.metaClass.hasProperty(variant, 'packageApplicationProvider')) {def packageAndroidArtifact = variant.packageApplicationProvider.get()if (packageAndroidArtifact != null) {try {from new File(packageAndroidArtifact.outputDirectory.getAsFile().get(), variant.outputs.first().apkData.outputFileName)} catch (Exception e) {from new File(packageAndroidArtifact.outputDirectory, variant.outputs.first().apkData.outputFileName)}} else {from variant.outputs.first().mainOutputFile.outputFile}} else {from variant.outputs.first().outputFile}into destPathrename { String fileName ->fileName.replace("${fileNamePrefix}.apk", "${newFileNamePrefix}.apk")}def dirName = variant.dirNamefrom "${buildDir}/outputs/mapping/${dirName}/mapping.txt"into destPathrename { String fileName ->fileName.replace("mapping.txt", "${newFileNamePrefix}-mapping.txt")}from "${buildDir}/intermediates/symbols/${dirName}/R.txt"from "${buildDir}/intermediates/symbol_list/${dirName}/R.txt"from "${buildDir}/intermediates/runtime_symbol_list/${dirName}/R.txt"into destPathrename { String fileName ->fileName.replace("R.txt", "${newFileNamePrefix}-R.txt")}}}}}
}
3.初始化SDK
enableProxyApplication = false 的情况
这是Tinker推荐的接入方式,一定程度上会增加接入成本,但具有更好的兼容性。
1.自定义Application
public class MyApplication extends TinkerApplication {public MyApplication() {super(ShareConstants.TINKER_ENABLE_ALL, "com.xkt.fwteacher.MyApplicationLike","com.tencent.tinker.loader.TinkerLoader", false);}
}
注意:这个类集成TinkerApplication类,这里面不做任何操作,所有Application的代码都会放到ApplicationLike继承类当中。
参数解析
- 参数1:tinkerFlags 表示Tinker支持的类型 dex only、library only or all suuport,default: TINKERENABLEALL
- 参数2:delegateClassName Application代理类 这里填写你自定义的ApplicationLike
- 参数3:loaderClassName Tinker的加载器,使用默认即可
- 参数4:tinkerLoadVerifyFlag 加载dex或者lib是否验证md5,默认为false
Applicaton配置为继承TinkerApplication的类
2.自定义ApplicationLike
处理所有的初始化application
public class MyApplicationLike extends DefaultApplicationLike {public MyApplicationLike(Application application, int tinkerFlags, boolean tinkerLoadVerifyFlag, long applicationStartElapsedTime, long applicationStartMillisTime, Intent tinkerResultIntent) {super(application, tinkerFlags, tinkerLoadVerifyFlag, applicationStartElapsedTime, applicationStartMillisTime, tinkerResultIntent);}@Overridepublic void onCreate() {super.onCreate();initBugly();initBase();}private void initBugly() {// 补丁回调接口Beta.betaPatchListener = new BetaPatchListener() {@Overridepublic void onPatchReceived(String patchFile) {Toast.makeText(getApplication(), "补丁下载地址" + patchFile, Toast.LENGTH_SHORT).show();}@Overridepublic void onDownloadReceived(long savedLength, long totalLength) {Toast.makeText(getApplication(),String.format(Locale.getDefault(), "%s %d%%",Beta.strNotificationDownloading,(int) (totalLength == 0 ? 0 : savedLength * 100 / totalLength)),Toast.LENGTH_SHORT).show();}@Overridepublic void onDownloadSuccess(String msg) {Toast.makeText(getApplication(), "补丁下载成功", Toast.LENGTH_SHORT).show();}@Overridepublic void onDownloadFailure(String msg) {Toast.makeText(getApplication(), "补丁下载失败", Toast.LENGTH_SHORT).show();}@Overridepublic void onApplySuccess(String msg) {Toast.makeText(getApplication(), "补丁应用成功", Toast.LENGTH_SHORT).show();}@Overridepublic void onApplyFailure(String msg) {Toast.makeText(getApplication(), "补丁应用失败", Toast.LENGTH_SHORT).show();}@Overridepublic void onPatchRollback() {}};// 设置开发设备,默认为false,上传补丁如果下发范围指定为“开发设备”,需要调用此接口来标识开发设备Bugly.setIsDevelopmentDevice(getApplication(), true);// 这里实现SDK初始化,appId替换成你的在Bugly平台申请的appIdBugly.init(getApplication(), "9254371c08", true);}....
}
4.AndroidManifest.xml配置
1.权限配置
2.Activity配置(官方需要,我没有配置)
3.配置FileProvider
4.filepath.xml的配置
5.混淆配置
-dontwarn com.tencent.bugly.**
-keep public class com.tencent.bugly.**{*;}
# tinker混淆规则
-dontwarn com.tencent.tinker.**
-keep class com.tencent.tinker.** { *; }
使用步骤
1.集成完成后,配置基准包的tinkerId
//建议设置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%AEautoGenerateTinkerId = true//tinkerId必须保证唯一性,如果两个base包的tinkerid是一样的,并且都联网激活了,那么后续补丁上传到后台的时候会出现匹配错误tinkerId = "if autoGenerateTinkerId=true ,no need set here"
使用构建自动生成的thinkid,不需要每次手动去设置
2.执行assembleRelease编译生成基准包:

这个会在build/outputs/bakApk路径下生成每次编译的基准包、混淆配置文件、资源Id文件,如下图所示:

- 实际应用中,请注意保存线上发布版本的基准apk包、mapping文件、R.txt文件,如果线上版本有bug,就可以借助我们tinker-support插件进行补丁包的生成。
- 注意文件夹的名称,在打补丁包的时候需要修改打包的文件目录为基准包的文件目录,也就是上图中的app-0209-16-07
3.根据基线版本生成补丁包
1. 修改tinker-support.gradle文件中的baseApkDir的值为基准包的目录,要不然会报找不到的错误
2. 执行构建补丁包的task

如果你要生成不同编译环境的补丁包,只需要执行TinkerSupport插件生成的task,比如buildTinkerPatchRelease就能生成release编译环境的补丁包。
3.生成的补丁包在build/outputs/patch目录下

4.上传补丁包到平台


5.补丁应用
我们方案是基于Tinker方案的实现,需要下次启动才能让补丁生效,下发成功后,重新启动app会应用补丁,然后修改,修改完成,重新打开就可显示修改的问题。
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
