引入 Tinker 之后如何在 Debug 模式下开启 Instant Run
在《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 了。
引入 Tinker 之后如何在 Debug 模式下开启 Instant Run的更多相关文章
- eclipse的问题:如何在debug模式下,能始终看到某变量的值
Window—>Show View—>other—>Debug—>Expressions中左边是变量名,右边显示变量value.
- 如何在debug模式下,使用正式的签名文件
有两种方式(在集成第三方库的使用 使用的非常多) 签名配置信息 一是直接按F4,在项目结构面板中进行设置,只要操作两个两个选项卡就好了,signing(生成配置信息)和build types(打包类 ...
- 在debug模式下引入一些性能检测工具
我们经常在debug模式下使用一些性能检测工具,例如blockCannary,leakCannary.Stetho等,但是我们release的时候又不需要这些检测工具,通常情况下我们的做法是在buil ...
- Debug模式下编译溢出问题
问题: 代码在Debug模式下编译报出内存溢出的错误,而Release模式下则没有. 由于Debug模式下包含调试信息,并且不作任何优化.而Release模式进行了各种优化,内存检测等操作均省去,使得 ...
- 重写NSLog,Debug模式下打印日志和当前行数
在pch文件中加入以下命令,NSLog在真机测试中就不会打印了 //重写NSLog,Debug模式下打印日志和当前行数 #if DEBUG #define NSLog(FORMAT, ...) fpr ...
- 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的错误提示框: 这个是什么 ...
- DEBUG模式下, 内存中的变量地址分析
测试函数的模板实现 /// @file my_template.h /// @brief 测试数据类型用的模板实现 #ifndef MY_TEMPLATE_H_2016_0123_1226 #defi ...
- Intellij IDEA debug模式下项目启动慢/无法启动的事件解决过程记录
项目无法启动了 简单的介绍一下事件过程:周一的早上,收到前端同事抛过来的一个任务,说是一个接口无法正常返回数据,于是就让他把参数发过来,我想试着在本地重现一下并且将问题修复掉,这种情况肯定是要通过de ...
- Myeclipse在debug模式下没加断点程序卡住,start模式下可以正常启动
参考<eclipse在debug模式下卡住,start模式下可以启动>,地址:https://blog.csdn.net/jack_chen1994/article/details/761 ...
随机推荐
- [JZOJ6088] [BZOJ5376] [loj #2463]【2018集训队互测Day 1】完美的旅行【线性递推】【多项式】【FWT】
Description Solution 我们考虑将问题一步步拆解 第一步求出\(F_{S,i}\)表示一次旅行按位与的值为S,走了i步的方案数. 第二步答案是\(F_{S,i}\)的二维重复卷积,记 ...
- js img转换base64
方法一:canvas <script type="text/javascript"> function getBase64Image(img) { var canvas ...
- OpenERP 中的on_change方法总结
1.xml中应为on_change=""的形式 2.py文件中 self,cr,uid,ids为必备参数,后面的参数根据xml文件中的参数的数量而定 3.return的是一个字典, ...
- 【Vim】Vim学习
1. 三种模式 (1)命令模式:刚启动vim便进入命令模式,此时敲击键盘会被当做命令来处理 以下是常用的几个命令: i 切换到插入模式,以输入字符.x 删除当前光标所在处的字符.: 切换到底线命令模式 ...
- https证书pfx 生成 pem,crt,key
(1)将.pfx格式的证书转换为.pem文件格式: openssl pkcs12 -in xxx.pfx -nodes -out server.pem (2)从.pem文件中导出私钥server ...
- maven备忘
maven常见命令 mvn clean mvn compile mvn package mvn clean compile package mvn -Djetty.port= jetty:run mv ...
- js 页面间的通信
看了一下公司原来的代码,原页面ajax post返回一个页面完整的HTML,然后再打开一个新页面并输出ajax返回的所有代码到新页面上,在新页面上以表单提交的形式实现重定向. 任凭我想了半天也没想出来 ...
- [作业] Python入门基础--猜年龄
age = 20 while True: try: guess_age = int(input('guess age:')) if guess_age > age: print('Is bigg ...
- [Mysql 查询语句]——对查询结果进一步的操作
distinct 不显示重复的查询结果 (1) 对于表中一些没有唯一性约束的字段,可能存在重复的值,这时可以使用distinct来消除那些查询结果中的重复值 select cust_id from ...
- iOS开源项目周报0316
由OpenDigg 出品的iOS开源项目周报第十二期来啦.我们的iOS开源周报集合了OpenDigg一周来新收录的优质的iOS开源项目,方便iOS开发人员便捷的找到自己需要的项目工具等.GodEye ...