Android-第三方开源框架:Bugly让热修复变得如此简单

dependencies {

classpath ‘com.android.tools.build:gradle:3.0.0’

// tinkersupport插件(1.0.3以上无须再配置tinker插件)

classpath “com.tencent.bugly:tinker-support:1.1.1”

}

三、集成SDK

=======

app的build.gradle:

apply from: ‘tinker-support.gradle’

android {

defaultConfig {

// 开启multidex

multiDexEnabled true

}

// recommend

dexOptions {

jumboMode = true

}

// 签名配置

signingConfigs {

release {

try {

storeFile file(“./keystore/release.keystore”)

storePassword “testres”

keyAlias “testres”

keyPassword “testres”

} catch (ex) {

throw new InvalidUserDataException(ex.toString())

}

}

debug {

storeFile file(“./keystore/debug.keystore”)

}

}

// 构建类型

buildTypes {

release {

minifyEnabled true

signingConfig signingConfigs.release

proguardFiles getDefaultProguardFile(‘proguard-android.txt’), ‘proguard-rules.pro’

}

debug {

debuggable true

minifyEnabled false

signingConfig signingConfigs.debug

}

}

sourceSets {

main {

jniLibs.srcDirs = [‘libs’]

}

}

}

dependencies {

implementation “com.android.support:multidex:1.0.1” // 多dex配置

implementation ‘com.tencent.bugly:crashreport_upgrade:1.3.4’// 远程仓库集成方式(推荐)

}

签名配置部分请根据你项目的实际情况修改,如:

四、配置Tinker

==========

在app的build.gradle文件同级目录下创建一个tinker-support.gradle文件,内容如下:

apply plugin: ‘com.tencent.bugly.tinker-support’

def bakPath = file(“${buildDir}/bakApk/”)

/**

  • 此处填写每次构建生成的基准包目录

*/

def baseApkDir = “tinker-bugly-1211-16-01-34”

def myTinkerId = “base-” + rootProject.ext.android.versionName // 用于生成基准包(不用修改)

//def myTinkerId = “patch-” + rootProject.ext.android.versionName + “.0.0” // 用于生成补丁包(每次生成补丁包都要修改一次,最好是 patch-${versionName}.x.x)

/**

  • 对于插件各参数的详细解析请参考

*/

tinkerSupport {

// 开启tinker-support插件,默认值true

enable = true

// 是否启用加固模式,默认为false.(tinker-spport 1.0.7起支持)

// isProtectedApp = true

// 是否开启反射Application模式

enableProxyApplication = true

// 是否支持新增非export的Activity(注意:设置为true才能修改AndroidManifest文件)

supportHotplugComponent = true

// 指定归档目录,默认值当前module的子目录tinker

autoBackupApkDir = “${bakPath}”

// 是否启用覆盖tinkerPatch配置功能,默认值false

// 开启后tinkerPatch配置不生效,即无需添加tinkerPatch

overrideTinkerPatchConfiguration = true

// 编译补丁包时,必需指定基线版本的apk,默认值为空

// 如果为空,则表示不是进行补丁包的编译

// @{link tinkerPatch.oldApk }

baseApk = “ b a k P a t h / {bakPath}/ bakPath/{baseApkDir}/app-release.apk”

// 对应tinker插件applyMapping

baseApkProguardMapping = “ b a k P a t h / {bakPath}/ bakPath/{baseApkDir}/app-release-mapping.txt”

// 对应tinker插件applyResourceMapping

baseApkResourceMapping = “ b a k P a t h / {bakPath}/ bakPath/{baseApkDir}/app-release-R.txt”

// 构建基准包和补丁包都要指定不同的tinkerId,并且必须保证唯一性

tinkerId = “${myTinkerId}”

// 构建多渠道补丁时使用

// buildAllFlavorsDir = “ b a k P a t h / {bakPath}/ bakPath/{baseApkDir}”

}

/**

  • 一般来说,我们无需对下面的参数做任何的修改

  • 对于各参数的详细介绍请参考:

  • https://github.com/Tencent/tinker/wiki/Tinker-%E6%8E%A5%E5%85%A5%E6%8C%87%E5%8D%97

*/

tinkerPatch {

}

1、overrideTinkerPatchConfiguration


当overrideTinkerPatchConfiguration = true时,tinkerPatch可以省略不写,Bugly会加载默认的Tinker配置。但请注意,如果你的so文件不是存放在libs目录下(与src目录同级),又或者资源文件的存放在你自定义的目录中,那么这时你要小心了,这些文件在制作补丁包时不会被检测,也就是说这些so文件和资源文件将不会被热修复,这种情况下就需要将overrideTinkerPatchConfiguration = false,并设置tinkerPatch的lib和res属性。

其它具体的配置与说明可以查看「Tinker-接入指南」

2、baseApkDir


baseApkDir是基准包(也称基线包)的目录,在生产补丁时需要根据基准包在bakApk下具体文件夹名字修改,如:bakApk/xxxx,到时生成补丁包时要将baseApkDir的值改为xxxx。(xxxx是Tinker自动生成的,根据时间戳来命名)。

3、tinkerId


tinkerId是Bugly热修复方案最最重要的一个因素,一般取值为git版本号、versionName等等(我习惯用versionName),它会将补丁包与基准包产生对应关系,假设基准包的tinkerId为 base-1.0,则生成的补丁包中的YAPATCH.MF文件关系如下:

Bugly要求baseApk(基准包)的tinkerId与补丁包的tinkerId要不一样。所以,在生成基准包时,请用如下tinkerId:

def myTinkerId = “base-” + rootProject.ext.android.versionName // 用于生成基准包(不用修改)

当生成补丁包时,请使用如下tinkerId:

def myTinkerId = “patch-” + rootProject.ext.android.versionName + “.0.0” // 用于生成补丁包(每次生成补丁包都要修改一次,最好是 patch-${versionName}.x.x)

对于同一个基准包,我们可能会多次生成补丁包上传到Bugly的热修复管理后台,这时,这些补丁包的tinkerId也要不一样,不然的话,当客户手机上的App在获取补丁时,会错乱(亲测,当同个基准包的补丁包的tinkerId一样时,App每次重启都会获取不同的补丁包,导致tinkerId相同的补丁包轮流下发)。所以,“patch-” + rootProject.ext.android.versionName + “.0.0"中的”.0.0"(称为计数)就是为了区分每次生成的补丁包,如.0.1,.0.2等等,建议versionName更新时计数重置。

因为Tinker的配置放在了tinker-support.gradle文件中,与app的build.gradle不在同一个文件中,所以没办法通过android.defaultConfig.versionName直接获取App的versionName,这里我使用了config.gradle来提取共同的属性,rootProject.ext.android.versionName获取的是config.gradle中的versionName属性,详情请百度。

4、补丁新旧判定


def myTinkerId = “patch-” + rootProject.ext.android.versionName + “.0.0” // 用于生成补丁包(每次生成补丁包都要修改一次,最好是 patch-${versionName}.x.x)

对于一个基准包,可以在Bugly上发布多个补丁包(切记tinkerid不同),这里或许会让你误以为计数越大,表明补丁越新,这是错误的,这个计数仅仅只是区分不同的补丁包而已,它没有标记补丁新旧的作用,补丁新旧由Bugly来判定,最后上传的补丁便是最新的补丁,举个例子,我在昨天上传了tinkerid为"patch-1.0.0.9"的补丁1,在今天上传了tinkerid为"patch-1.0.0.1"的补丁2,虽然补丁2的计数比补丁1小,但补丁2比补丁1晚上传,所以补丁2是最新的补丁,即补丁新旧与计数无关。Bugly会下发并应用最新的补丁(即补丁2),但还是建议计数从小到大计算,这里仅仅只是说明Bugly如何判定补丁新旧罢了。

五、初始化SDK

========

Bugly的初始化工作需要在Application中完成,但对原生Tinker来说,默认的Application是无法实现热修复的。看过Tinker官方Wiki的人应该知道,Tinker针对Application无法热修复的问题,给予开发者两个选择,分别是:

  • 使用「继承TinkerApplication + DefaultApplicationLike」。

  • 使用「DefaultLifeCycle注解 + DefaultApplicationLike」。

这2种选择都需要对自定义的Application进行改造,对于自定义Application代码不多的情况来说还可以接受,但有些情况还是比较"讨厌"这2种选择的,对此,Bugly给出了它的2种解决方法,分别如下:

  • 使用原来的自定义Application,Bugly通过反射为App动态生成新的Application。

  • 使用「继承TinkerApplication + DefaultApplicationLike」。

DefaultLifeCycle注解在Bugly中被阉割了。

分别对应tinker-support.gradle文件中enableProxyApplication的值:true或false。

1、enableProxyApplication = true


Bugly将通过反射的方式针对项目中自定义的Application动态生成新的Application,下图是源码中的AndroidManifest.xml和编译好的apk中的AndroidManifest.xml:

既然将enableProxyApplication的值设置为true,那接下来的重点就是完成Bugly的初始化工作了。需要在自定义的Application的onCreate()中进行Bugly的配置,在attachBaseContext()中进行Bugly的安装:

public class MyApplication extends Application {

private Context mContext;

@Override

public void onCreate() {

super.onCreate();

mContext = getApplicationContext();

// 这里实现SDK初始化,appId替换成你的在Bugly平台申请的appId

// 调试时,将第三个参数改为true

configTinker();

}

@Override

protected void attachBaseContext(Context base) {

super.attachBaseContext(base);

// you must install multiDex whatever tinker is installed!

MultiDex.install(mContext);

// 安装tinker

// 此接口仅用于反射Application方式接入。

Beta.installTinker();

}

}

注意:

  1. Bugly的安装必须在attachBaseContext()方法中,否则将无法从Bugly服务器获取最新补丁。
  1. tinker需要你开启MultiDex,你需要在dependencies中进行配置compile "com.android.support:multidex:1.0.1"才可以使用MultiDex.install方法。

最后在清单文件中,声明使用我们自定义的Application即可:

<application

android:name=“com.lqr.MyApplication”

…>

2、enableProxyApplication = false


这是Bugly推荐的方式,稳定性有保障(因为第1种方式使用的是反射,可能会存在不稳定的因素),它需要对Application进行改造,首先就是继承TinkerApplication,然后在默认的构造函数中,将第2个参数修改为你项目中的ApplicationLike继承类的全限定名称:

public class SampleApplication extends TinkerApplication {

public SampleApplication() {

super(ShareConstants.TINKER_ENABLE_ALL, “com.lqr.SampleApplicationLike”,

“com.tencent.tinker.loader.TinkerLoader”, false);

}

}

注意:这个类集成TinkerApplication类,这里面不做任何操作,所有Application的代码都会放到ApplicationLike继承类当中

参数解析

参数1:tinkerFlags 表示Tinker支持的类型 dex only、library only or all suuport,default: TINKER_ENABLE_ALL

参数2:delegateClassName Application代理类 这里填写你自定义的ApplicationLike

参数3:loaderClassName Tinker的加载器,使用默认即可

参数4:tinkerLoadVerifyFlag 加载dex或者lib是否验证md5,默认为false

接着就是创建ApplicationLike继承类:

public class SampleApplicationLike extends DefaultApplicationLike {

public static final String TAG = “Tinker.SampleApplicationLike”;

private Application mContext;

public SampleApplicationLike(Application application, int tinkerFlags,

boolean tinkerLoadVerifyFlag, long applicationStartElapsedTime,

long applicationStartMillisTime, Intent tinkerResultIntent) {

super(application, tinkerFlags, tinkerLoadVerifyFlag, applicationStartElapsedTime, applicationStartMillisTime, tinkerResultIntent);

}

@Override

public void onCreate() {

super.onCreate();

mContext = getApplication();

configTinker();

}

@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)

@Override

public void onBaseContextAttached(Context base) {

super.onBaseContextAttached(base);

// you must install multiDex whatever tinker is installed!

MultiDex.install(base);

// 安装tinker

Beta.installTinker(this);

}

@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)

public void registerActivityLifecycleCallback(Application.ActivityLifecycleCallbacks callbacks) {

getApplication().registerActivityLifecycleCallbacks(callbacks);

}

@Override

public void onTerminate() {

super.onTerminate();

Beta.unInit();

}

}

注意:

SampleApplicationLike这个类是Application的代理类,以前所有在Application的实现必须要全部拷贝到这里,在onCreate方法调用SDK的初始化方法,在onBaseContextAttached中调用Beta.installTinker(this)。

最后在清单文件中,声明改造好的Application(注意不是ApplicationLike):

<application

android:name=“com.lqr.SampleApplication”

…>

3、配置Bugly


这是Bugly官方给出的配置,应有尽有,注释也很nice,请仔细看看,对项目的功能拓展与用户体验有帮助:

private void configTinker() {

// 设置是否开启热更新能力,默认为true

Beta.enableHotfix = true;

// 设置是否自动下载补丁,默认为true

Beta.canAutoDownloadPatch = true;

// 设置是否自动合成补丁,默认为true

Beta.canAutoPatch = true;

// 设置是否提示用户重启,默认为false

Beta.canNotifyUserRestart = true;

// 补丁回调接口

Beta.betaPatchListener = new BetaPatchListener() {

@Override

public void onPatchReceived(String patchFile) {

Toast.makeText(mContext, “补丁下载地址” + patchFile, Toast.LENGTH_SHORT).show();

}

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
img

Android高级架构师

由于篇幅问题,我呢也将自己当前所在技术领域的各项知识点、工具、框架等汇总成一份技术路线图,还有一些架构进阶视频、全套学习PDF文件、面试文档、源码笔记。

  • 330页PDF Android学习核心笔记(内含上面8大板块)

  • Android学习的系统对应视频

  • Android进阶的系统对应学习资料

  • Android BAT部分大厂面试题(有解析)

好了,以上便是今天的分享,希望为各位朋友后续的学习提供方便。觉得内容不错,也欢迎多多分享给身边的朋友哈。

g.csdnimg.cn/13f2cb2e05a14868a3f0fd6ac81d625c.png)

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
[外链图片转存中…(img-XZAOwzrF-1711857893437)]

Android高级架构师

由于篇幅问题,我呢也将自己当前所在技术领域的各项知识点、工具、框架等汇总成一份技术路线图,还有一些架构进阶视频、全套学习PDF文件、面试文档、源码笔记。

  • 330页PDF Android学习核心笔记(内含上面8大板块)

[外链图片转存中…(img-cxGA1g43-1711857893438)]

[外链图片转存中…(img-QxTodbrl-1711857893438)]

  • Android学习的系统对应视频

  • Android进阶的系统对应学习资料

[外链图片转存中…(img-fsJ4QE4A-1711857893438)]

  • Android BAT部分大厂面试题(有解析)

[外链图片转存中…(img-Nbk17UMV-1711857893438)]

好了,以上便是今天的分享,希望为各位朋友后续的学习提供方便。觉得内容不错,也欢迎多多分享给身边的朋友哈。

本文已被CODING开源项目:《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》收录

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值