介绍
在介绍Bugly之前,需要先向大家简单介绍下一些热更新的相关内容。当前市面的热补丁方案有很多,其中比较出名的有阿里的AndFix、美团的Robust以及QZone的超级补丁方案。但它们都存在无法解决的问题,这也是Tinker面世的原因。Tinker目前已运行在微信的数亿Android设备上,相对于其它热更新方案,Tinker相对比较优秀。
什么是Tinker
Tinker是微信官方的Android热补丁解决方案,它支持动态下发代码、So库以及资源,让应用能够在不需要重新安装的情况下实现更新。当然,你也可以使用Tinker来更新你的插件。
Tinker | QZone | AndFix | Robust | |
---|---|---|---|---|
类替换 | yes | yes | no | no |
So替换 | yes | no | no | no |
资源替换 | yes | yes | no | no |
全平台支持 | yes | yes | yes | yes |
即时生效 | no | no | yes | yes |
性能损耗 | 较小 | 较大 | 较小 | 较小 |
补丁包大小 | 较小 | 较大 | 一般 | 一般 |
开发透明 | yes | yes | no | no |
复杂度 | 较低 | 较低 | 复杂 | 复杂 |
gradle支持 | yes | no | no | no |
Rom体积 | 较大 | 较小 | 较小 | 较小 |
成功率 | 较高 | 较高 | 一般 | 最高 |
总的来说:
-
AndFix作为native解决方案,首先面临的是稳定性与兼容性问题,更重要的是它无法实现类替换,它是需要大量额外的开发成本的;
-
Robust兼容性与成功率较高,但是它与AndFix一样,无法新增变量与类只能用做的bugFix方案;
-
Qzone方案可以做到发布产品功能,但是它主要问题是插桩带来Dalvik的性能问题,以及为了解决Art下内存地址问题而导致补丁包急速增大的。
Tinker的已知问题
-
Tinker不支持修改AndroidManifest.xml,Tinker不支持新增四大组件(1.9.0支持新增非export的Activity);
-
由于Google Play的开发者条款限制,不建议在GP渠道动态更新代码
-
在Android N上,补丁对应用启动时间有轻微的影响;
-
不支持部分三星android-21机型,加载补丁时会主动抛出"TinkerRuntimeException:checkDexInstall failed";
-
对于资源替换,不支持修改remoteView。例如transition动画,notification icon以及桌面图标。
Tinker更多介绍
对于tinker的详细介绍,感兴趣的可以前往查看,地址:
Bugly的介绍
腾讯 Bugly,是腾讯公司为移动开发者开放的服务之一,面向移动开发者提供专业的 Crash 监控、崩溃分析等质量跟踪服务。Bugly 能帮助移动互联网开发者更及时地发现掌控异常,更全面的了解定位异常,更高效的修复解决异常。
Bugly目前包括三大服务:
- 异常上报;
- 运营统计;
- 应用升级(包括全量升级和热更新)。
Bugly的热更新
热更新能力是Bugly为解决开发者紧急修复线上bug,而无需重新发版让用户无感知就能把问题修复的一项能力。Bugly目前采用微信Tinker的开源方案,开发者只需要集成我们提供的SDK就可以实现自动下载补丁包、合成、并应用补丁的功能,我们也提供了热更新管理后台让开发者对每个版本补丁进行管理。
为什么使用Bugly热更新?
-
无需关注Tinker是如何合成补丁的
-
无需自己搭建补丁管理后台
-
无需考虑后台下发补丁策略的任何事情
-
无需考虑补丁下载合成的时机,处理后台下发的策略
-
Bugly提供了更加方便集成Tinker的方式
-
Bugly通过HTTPS及签名校验等机制保障补丁下发的安全性
-
丰富的下发维度控制,有效控制补丁影响范围
-
Bugly提供了应用升级一站式解决方案
Bugly热更新SDK的集成
集成Bugly热更新的详细操作可以参考官网的文档:
在这里就不一步一步地结合如何集成SDK,总的来说有一下几个步骤:
-
工程根目录build.gradle添加tinker-support插件依赖;
-
app module的build.gradle添加SDK依赖;
-
在app目录下新建tinker-support.gradle文件,文件的内容文档有提供;
-
初始化SDK,改造application,虽然也可以不改造application,但是兼容性可能会出现问题,官方推荐改造application;
-
AndroidManifest.xml配置相关权限,如果仅仅只是使用热更新而不需要使用到全量升级功能,不需要配置BetaActivity和FileProvider。
-
混淆配置,在proguard-rules.pro文件中添加Bugly的混淆规则。
集成热更新所遇到的相关问题:
- 文档中提及使用插件的最新版本可以通过使用lastest.release拉取,如图:
但我添加依赖的时候,如下:
buildscript {
repositories {
jcenter()
}
dependencies {
// tinkersupport插件, 其中lastest.release指拉取最新版本,也可以指定明确版本号,例如1.0.4
classpath "com.tencent.bugly:tinker-support:lastest.release"
}
}
报了找不到该依赖的错误,原来是文档写错了,lastest应改成latest才对。
- tinker-support.gradle中缺少supportHotplugComponent这项配置导致打补丁包的时候出现错误
视频介绍和文档中都没有提及到tinker-support.gradle文件tinkerSupport { }中需要添加多supportHotplugComponent这项配置,按照文档来打补丁的时候,会出现如下错误:
看了错误提示,老是提示我说manifest was changed,可是我根本没有改动到manifest,一直很纳闷,直到看了demo后,才发现需要在tinkerSupport { }中,添加supportHotplugComponent这项配置,代码如下:
tinkerSupport {
...
supportHotplugComponent = true
}
- thinkerId 的指定
thinkerId需要是唯一的,在生成基准包和补丁包时都需要改动,官方推荐时间用git版本号或版本名生成,这里我自己使用的是versionName_MM-dd-HH-mm-ss这种格式,版本名+时间戳,比如1.0.5-1121-11-33-20,这和bakApk下生成基准包目录的时间戳类似,它是app-1121-11-33-20,这样查看起来一路了然,查看补丁包的YAPATCH文件也很清晰:
Created-Time: 2017-11-21 11:37:15.673
Created-By: YaFix(1.1)
YaPatchType: 2
VersionName: 1.0.5
VersionCode: 5
From: 1.0.5-1121-11-36-06
To: 1.0.5-1121-11-37-15
From 是基准包的tinkerId
To 是当前补丁包的tinkerId
生成上述格式tinkerId的代码如下:
tinkerSupport {
...
tinkerId = "${verName()}-${buildTime()}"
...
}
//获取版本名
def verName() {
def versionPropsFile = file("../version.properties")
if (versionPropsFile.canRead()) {
Properties versionProps = new Properties()
versionProps.load(new FileInputStream(versionPropsFile))
return versionProps['VERSION_NAME']
} else {
throw new GradleException("Could not read gradle.properties")
}
}
//获取构建时间
def buildTime() {
return new Date().format("MMdd-HH-mm-ss", TimeZone.getTimeZone("GMT+8"))
}
需要在工程根目录下,和gradle.properties文件同目录下,新建version.properties文件,用于保存当前app的versionCode和versionName,文件的内容:
VERSION_NAME=1.0.5
VERSION_CODE=4
既然将versionCode和versionName配置在properties文件中,那么app module的gradle文件中,defaultConfig{}中指定版本名和版本号直接使用该配置
android {
...
defaultConfig {
...
versionCode verCode()
versionName verName()
...
}
}
获取版本号的方法verCode(),代码如下:
//获取版本号
def verCode() {
def versionPropsFile = file("../version.properties")
if (versionPropsFile.canRead()) {
Properties versionProps = new Properties()
versionProps.load(new FileInputStream(versionPropsFile))
def int verCode = versionProps['VERSION_CODE'].toInteger()
return verCode;
} else {
throw new GradleException("Could not read gradle.properties")
}
}
Bugly Q&A
到这里Bugly热更新的相关介绍就到此为止了,在这里向大家简单介绍了Bugly集成是使用中遇到的问题和相关的建议,官方也提供了常见问题解决的介绍:
如果里面找不到你想要的,可以联系他们的客服的QQ,但是客服几乎不回答,有点无奈,客服QQ自动回复推荐去他们的论坛留言,可是发现该论坛禁止注册了,有点悲催。几番波折后,终于在他们的新浪微博上找到了希望:
Demo源码
支持和鼓励
如果你喜欢我的文章的话,可以关注我的博客,感谢大家一直以来给我的支持和鼓励,你们的每一次喜欢和打赏,使我写文章更有动力。