摘要:在爬坑之路一文中讲了在接入之后,中的一些坑,由此,热修复算告一段落,但是,在直接模式运行时,程序会报出如下错误好吧,使用时不能开启上也有一个同样的,引入之后如何在模式下开启,这里我将我的方法讲述一下,给大家一个参考。
在《Tinker + Bugly + Jenkins 爬坑之路》一文中讲了在接入 Tinker 之后,Jenkins 中的一些坑,由此,热修复算告一段落,但是,在直接 Run 模式运行时,程序会报出如下错误:
Tinker does not support instant run mode, please trigger build by assembleDebug or disable instant run in "File->Settings...".
好吧,使用 TInker 时不能开启 Instant Run  ̄□ ̄||
GitHub 上也有一个同样的 issue,引入Tinker之后如何在Debug模式下开启Instant Run ,这里我将我的方法讲述一下,给大家一个参考。
1. 使用变量标记是否使用 Tinker在 project 的 build.gradle 文件的 ext 中定义变量 tinkerEnabled 用来标记是否使用 TInker,代码如下所示:
ext { /** * 是否启用tinker参与编译 * 开发时,根据需要修改值来开启 * Jenkins 构建时,会替换该值 */ tinkerEnabled = rootProject.properties["tinkerEnable"] if (null == tinkerEnabled) { tinkerEnabled = "false" } }
看过《Tinker + Bugly + Jenkins 爬坑之路》的同学应该知道,我司的项目是使用 Jenkins 打包的,所以我这里先通过 rootProject.properties["tinkerEnable"] 从 Gradle 命令中取 tinkerEnabled 参数的值,然后在构建脚本的打包命令行中加入该参数:
sh gradlew assembleRelease -PtinkerEnable=true --stacktrace
这样,就确保了 Jenkins 构建时 tinkerEnable 的值为 true。在开发过程中,本地运行或者构建 apk 就可以通过修改 tinkerEnabled = "false" 来决定是否使用 Tinker 构建。
2. 通过标记值决定是否使用 TInker 构建接下来在 module 的 build.gradle 文件中,通过 tinkerEnabled 值来判断是否引入 tinker-support.gradle 构建项目,代码如下:
// 依赖插件脚本-tinker if (Boolean.parseBoolean(rootProject.ext.tinkerEnabled)) { apply from: rootProject.file("gradle/tinker-support.gradle") }3. Java/Kotlin 代码中通过标记值决定是否初始化 Tinker
在 Java/Kotlin 代码中,是无法直接使用 gradle 文件中的变量值的,那么在 Java/Kotlin 代码中,怎么通过上面定义的标记量来决定是否初始化 Tinker 呢?总不能在 Java/Kotlin 代码中也定义一个全局变量来控制吧,那样本地开发时一改就得改两个地方,不但麻烦而且可能出错,另外,Jenkins 打包时也无法确定 Java/Kotlin 会初始化 Tinker。
那,怎么办呢?我们来个“曲线救国”的方法。通过自定义 BuildConfig 属性来解决,首先,在 module 的 build.gradle 文件中,将 tinkerEnabled 的值传递到 BuildConfig 的自定义属性中,代码如下:
android { compileSdkVersion rootProject.ext.compileSdkVersion buildToolsVersion rootProject.ext.buildToolsVersion defaultConfig { /** =============自定义 BuildConfig 属性========================*/ buildConfigField "boolean", "BuildConfig", rootProject.ext.tinkerEnabled /** =============自定义 BuildConfig 属性========================*/ } }
然后,在自定义的 application 类中添加根据 BuildConfig.BuildConfig 判断是否初始化 Tinker 的代码:
package com.cy.sample import android.app.Application import android.content.Context import android.widget.Toast import com.tencent.bugly.Bugly import com.tencent.bugly.beta.Beta import com.tencent.bugly.beta.interfaces.BetaPatchListener import com.tencent.bugly.beta.tinker.TinkerManager.getApplication import java.util.* /** * 类描述。 * * @author cspecialy * @version v1.0.0 */ class MyApplication : Application() { override fun onCreate() { super.onCreate() if (BuildConfig.TINKER_ENABLE) { initTinker() } } /** * 初始化 Tinker */ private fun initTinker() { // 设置是否开启热更新能力,默认为true Beta.enableHotfix = true // 设置是否自动下载补丁,默认为true Beta.canAutoDownloadPatch = true // 设置是否自动合成补丁,默认为true Beta.canAutoPatch = true // 设置是否提示用户重启,默认为false Beta.canNotifyUserRestart = true // 补丁回调接口 Beta.betaPatchListener = object : BetaPatchListener { override fun onPatchReceived(patchFile: String) { Toast.makeText(getApplication(), "补丁下载地址$patchFile", Toast.LENGTH_SHORT).show() } override fun onDownloadReceived(savedLength: Long, totalLength: Long) { Toast.makeText(getApplication(), String.format(Locale.getDefault(), "%s %d%%", Beta.strNotificationDownloading, (if (totalLength == 0L) 0 else savedLength * 100 / totalLength).toInt()), Toast.LENGTH_SHORT).show() } override fun onDownloadSuccess(msg: String) { Toast.makeText(getApplication(), "补丁下载成功", Toast.LENGTH_SHORT).show() } override fun onDownloadFailure(msg: String) { Toast.makeText(getApplication(), "补丁下载失败", Toast.LENGTH_SHORT).show() } override fun onApplySuccess(msg: String) { Toast.makeText(getApplication(), "补丁应用成功", Toast.LENGTH_SHORT).show() } override fun onApplyFailure(msg: String) { Toast.makeText(getApplication(), "补丁应用失败", Toast.LENGTH_SHORT).show() } override fun onPatchRollback() { } } // 设置开发设备,默认为false,上传补丁如果下发范围指定为“开发设备”,需要调用此接口来标识开发设备 Bugly.setIsDevelopmentDevice(getApplication(), true) // 多渠道需求塞入 // String channel = WalleChannelReader.getChannel(getApplication()); // Bugly.setAppChannel(getApplication(), channel); // 这里实现SDK初始化,appId替换成你的在Bugly平台申请的appId Bugly.init(getApplication(), "2a1dc56c3a", true) } override fun attachBaseContext(base: Context) { super.attachBaseContext(base) // you must install multiDex whatever tinker is installed! MultiDex.install(base) if (BuildConfig.TINKER_ENABLE) { // 安装tinker Beta.installTinker() } } }
以上代码相信大家也注意到了,是的,我这里 TInker 是使用 enableProxyApplication = true 开启反射代理的方式,大家如果使用 enableProxyApplication = false 方式的话,方向也一样,我这里就不赘述了,大家因地制宜哈~~~ O(∩_∩)O哈哈~
接下来,开发时只需要将 tinkerEnabled 变量的值设置为 false,就可以愉快的使用 Instant Run 了。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/69706.html
摘要:不过它确实各方面都做了大量的优化,本文中的很多知识点也来源于阿里的热修复技术原理一书,本书值得一读,里面就是基于框架来编排的。 前言;本文框架什么是热修复?热修复框架分类技术原理及特点Tinker框架解析各框架对比图总结通过阅读本文,你会对热修复技术有更深的认知,本文会列出各类框架的优缺点以及技术原理,文章末尾简单描述一下Tinker的框架结构。 一、什么是热修复?1.正常开发流程showI...
阅读 2952·2021-11-23 09:51
阅读 1006·2021-09-26 09:55
阅读 3934·2021-09-22 14:58
阅读 1467·2021-09-08 09:35
阅读 1078·2021-08-26 14:16
阅读 881·2019-08-23 18:17
阅读 2053·2019-08-23 16:45
阅读 700·2019-08-23 15:55