在《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

projectbuild.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 构建

接下来在 modulebuild.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 属性来解决,首先,在 modulebuild.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 了。

引入 Tinker 之后如何在 Debug 模式下开启 Instant Run的更多相关文章

  1. eclipse的问题:如何在debug模式下,能始终看到某变量的值

    Window—>Show View—>other—>Debug—>Expressions中左边是变量名,右边显示变量value.

  2. 如何在debug模式下,使用正式的签名文件

    有两种方式(在集成第三方库的使用 使用的非常多)  签名配置信息 一是直接按F4,在项目结构面板中进行设置,只要操作两个两个选项卡就好了,signing(生成配置信息)和build types(打包类 ...

  3. 在debug模式下引入一些性能检测工具

    我们经常在debug模式下使用一些性能检测工具,例如blockCannary,leakCannary.Stetho等,但是我们release的时候又不需要这些检测工具,通常情况下我们的做法是在buil ...

  4. Debug模式下编译溢出问题

    问题: 代码在Debug模式下编译报出内存溢出的错误,而Release模式下则没有. 由于Debug模式下包含调试信息,并且不作任何优化.而Release模式进行了各种优化,内存检测等操作均省去,使得 ...

  5. 重写NSLog,Debug模式下打印日志和当前行数

    在pch文件中加入以下命令,NSLog在真机测试中就不会打印了 //重写NSLog,Debug模式下打印日志和当前行数 #if DEBUG #define NSLog(FORMAT, ...) fpr ...

  6. C++程序在debug模式下遇到Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call问题。

    今天遇到一个Access Violation的crash,只看crash call stack没有找到更多的线索,于是在debug模式下又跑了一遍,遇到了如下的一个debug的错误提示框: 这个是什么 ...

  7. DEBUG模式下, 内存中的变量地址分析

    测试函数的模板实现 /// @file my_template.h /// @brief 测试数据类型用的模板实现 #ifndef MY_TEMPLATE_H_2016_0123_1226 #defi ...

  8. Intellij IDEA debug模式下项目启动慢/无法启动的事件解决过程记录

    项目无法启动了 简单的介绍一下事件过程:周一的早上,收到前端同事抛过来的一个任务,说是一个接口无法正常返回数据,于是就让他把参数发过来,我想试着在本地重现一下并且将问题修复掉,这种情况肯定是要通过de ...

  9. Myeclipse在debug模式下没加断点程序卡住,start模式下可以正常启动

    参考<eclipse在debug模式下卡住,start模式下可以启动>,地址:https://blog.csdn.net/jack_chen1994/article/details/761 ...

随机推荐

  1. SBC应用

    在VoIP呼叫中主要使用会话发起协议(SIP),H.323和MGCP呼叫信令协议,Sbc 在主叫和被叫的信令/媒体路径之间引入. 通常,SBC隐藏网络拓扑,接管呼入并生成到新的请求分支到被叫.技术上叫 ...

  2. [转] gitlab 的 CI/CD 配置管理

    [From] http://blog.51cto.com/flyfish225/2156602 gitlab 的 CI/CD 配置管理 (二) 标签(空格分隔):运维系列 一:gitlab CI/CD ...

  3. chm 已取消到该网页的导航,打不开!

    方法 11. 双击此 .chm 文件. 2. 在“打开文件安全警告”对话框,单击以清除“打开此文件前始终询问”复选框. 3. 单击“打开”. 方法 21. 右键单击该 CHM 文件,然后单击“属性”. ...

  4. Window对象的判定方法

    /* window对象的判定,由于ECMA是不规范Host对象,window对象属于Host,所以也没有约定,所以就算是Object.prototype也对它无可奈何, 而且如果根据window.wi ...

  5. django blank

    null: If True, Django will store empty values as NULL in the database. Defaultis False. 如果为True,空值将会 ...

  6. ACCESS 手工注入

    ACCESS的注入,基本是死的.思路很简单,基本都可以工具解决.上代码: 1.判断有无注入点' and 1=1 and 1=22.猜表一般的表的名称无非是admin adminuser user pa ...

  7. css3基础下

    box-shadow:0 5px 5px rgba(0,0,0,0.5) 文本 text-shadow:5px 5px 4px green; word-wrap: 背景: background:#ff ...

  8. R语言格式化数字和字符串format函数

    数字和字符串可以使用 format()函数的格式化为特定样式. 语法 format()函数的基本语法是: format(x, digits, nsmall,scientific,width,justi ...

  9. 如何用webgl(three.js)搭建不规则建筑模型,客流量热力图模拟

    本节课主要讲解如何用webgl(three.js)搭建一个建筑模型,客流量热力图模拟 使用技术说明: 这里主要用到了three.js,echart.js以及一些其它的js 与css技术,利用webso ...

  10. IOS折线图二

    上周把项目的折线图给做了下,今天想着把它完善完善,自己设置了不同的数据源来测试,哈哈,还真遇到问题了, 就是给图表设置折点数为0时,视图显示的还是原来的,由于数据为空,应该将其设置为空,所以想着怎么把 ...