引入 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

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 了。

原文地址:https://www.cnblogs.com/cspecialy/p/9160850.html

时间: 2024-10-25 18:57:08

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

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

测试函数的模板实现 [cpp] view plain copy /// @file my_template.h /// @brief 测试数据类型用的模板实现 #ifndef MY_TEMPLATE_H_2016_0123_1226 #define MY_TEMPLATE_H_2016_0123_1226 template<int iArySize> void fnTestDataType() { char szBuf[iArySize] = {'\0'}; unsigned short wT

Django -&gt; debug模式下的静态文件服务(/media/)

正式发布django项目的时候,如果存在静态文件(一般会统一放在名称为media或static的目录下),则需要建立url到文件系统的映射,例如,使用nginx的时候我们需要进行这样的配置. # Django media location /media { alias /home/lyndon/github/Mathematician/dijkstra/media; } location /static { alias /home/lyndon/github/Mathematician/dijk

Debug模式下编译溢出问题

问题: 代码在Debug模式下编译报出内存溢出的错误,而Release模式下则没有. 由于Debug模式下包含调试信息,并且不作任何优化.而Release模式进行了各种优化,内存检测等操作均省去,使得程序在代码大小和运行速度上都是最优的. 方法1: 猜测Release对代码进行了优化或者根本就没有进行内存检测,才导致Release模式下编译通过的.于是我进行了代码缩减,删除没有用的变量,问题仍然没有解决. 方法2: 我发现在Debug模式下,main.c文件淡黄色, ,Release模式下仍然为

eclipse在debug模式下自动跳到ThreadPoolExecutor解决方案

困扰了很长时间的一个问题,以前没有自己研究,今天终于解决了. 使用eclipse时,如果tomcat设定的是热加载,当修改一些程序后,tomcat自动加载修改内容..... 但是很多次都会自动跳到debug模式,很是讨厌... 原因是eclipse的设置问题:默认[Suspend execution on uncaught exceptions]是选中的,则eclipse在遇到未捕获的异常时会停止..... 修改方法,就是去掉选中的checkbox即可 参考文章:http://hi.baidu.

在Debug模式下中断, 在Release模式下跳出当前函数的断言

在Debug模式下中断, 在Release模式下跳出当前函数的断言 #ifdef DEBUG #define __breakPoint_on_debug asm("int3") #else #define __breakPoint_on_debug #endif // 验证 #define UXY_ASSERT_RETURN_ON_RELEASE( __condition, __desc, ... ) \ metamacro_if_eq(0, metamacro_argcount(__

eclipse的debug模式下启动不了tomcat

使用eclipse启动tomcat,正常模式下可以启动tomcat,却在debug模式下无法启动tomcat. 这个问题可能是由于eclipse和tomcat的交互而产生的,在以debug模式启动tomcat时,发生了读取文件错误,eclipse自动设置了断点,导致tomcat不能正常启动. 解决方法把breakpoints veiw都删除就好了,步骤如下:window->show view->Breakpoints.在Breakpoints视图中右键,Remove all

Django -&amp;gt; debug模式下的静态文件服务(/media/)

正式公布django项目的时候,假设存在静态文件(通常会统一放在名称为media或static的文件夹下),则须要建立url到文件系统的映射,比如.使用nginx的时候我们须要进行这种配置. # Django media location /media { alias /home/lyndon/github/Mathematician/dijkstra/media; } location /static { alias /home/lyndon/github/Mathematician/dijk

Android studio build.gradle配置,debug模式下使用正式版签名,重命名apk

在build.gradle文件中,android节点下进行配置. android { compileSdkVersion 22 buildToolsVersion '22.0.1' signingConfigs { release { keyAlias 'xxx' keyPassword 'xxxxxxxxxxxx' storeFile file('./xxx.keystore') storePassword 'xxxxxxxxxxxxxxxx' } config { keyAlias 'xxx

IDEA Debug模式下启动慢的解决办法

工程没有做什么大的改动,近期Idea在debug模式下启动耗时800s +,run模式下200s.Idea debug模式启动的时候会有这样的提示: 方法断点会戏剧性的降低debug的速度.当时并没有在意,因为并不清晰这个方法断点是个什么概念.....看了网友的帖子,才知道这个method breakpoints就是方法签名上的断点.idea的这个提示能否更人性化点,就叫method signature breakpoints好了,搞个method breakpoints谁TMD知道.. ---