bugly 支持异常上报,应用升级与热更新;异常上报与应用升级使用较为简单,也没有什么难点。
下面看一下热更新,官网的文档说的虽然非常明白,但是罗里吧嗦,看的让人头大。
下面给出一个特别简单的集成与使用方式。
打开下面 bugly 给出的 GitHub 示例,下面是链接:
https://github.com/BuglyDevTeam/Bugly-Android-Demo
下载完毕,会看到有两个 demo ,如下图所示:
可以看到里面有两个:官网推荐 BuglyHotfixDemo;一键接入 BuglyHotfixEasyDemo ;
我们直接打开第二个,也就是 BuglyHotfixEasyDemo ,这个 demo 是热更新一键接入示例,后续也不再更新这个;
热更新sdk版本至1.3.6, tinker-support版本至1.1.5,对应tinker版本 1.9.9;
虽然不再更新这个,但是作为普通的用户,目前使用这个是完全够用的。
如果你想使用第一个 demo ,也建议先看第二个,因为这个非常简单,看完这个再看第一个会感觉并不复杂。
在接入热更新之前,我们要去申请 appid 过程很简单,打开官网登录 qq 账号申请即可,就不说了,下面是官网地址:
https://bugly.qq.com/
下面就看一下如何接入,我并不是按照官网来的,因为官网过于复杂;如果第一次使用建议新建一个 demo ,作为测试使用;
首先在项目的 build.gradle 中添加下面代码:
classpath 'com.tencent.bugly:tinker-support:1.1.5'
如下图:
在 app 下的 build.gradle 中添加:
// 依赖插件脚本,添加在最上面
apply from: 'tinker-support.gradle'
和
// 远程依赖集成方式(推荐)compile "com.tencent.bugly:crashreport_upgrade:1.3.6"// 指定tinker依赖版本(注:应用升级1.3.5版本起,不再内置tinker)compile 'com.tencent.tinker:tinker-android-lib:1.9.9'
如下图所示:
和
新建 tinker-support.gradle 与 app 的 build.gradle 同级,代码如下:
apply plugin: 'com.tencent.bugly.tinker-support'def bakPath = file("${buildDir}/bakApk/")/*** 此处填写每次构建生成的基准包目录*/
def baseApkDir = "app-1119-14-54-04"/*** 对于插件各参数的详细解析请参考*/
tinkerSupport {// 开启tinker-support插件,默认值trueenable = true// 自动生成tinkerId, 你无须关注tinkerId,默认为falseautoGenerateTinkerId = true// 指定归档目录,默认值当前module的子目录tinkerautoBackupApkDir = "${bakPath}"// 是否启用覆盖tinkerPatch配置功能,默认值false// 开启后tinkerPatch配置不生效,即无需添加tinkerPatchoverrideTinkerPatchConfiguration = true//测试baseApk = "${bakPath}/${baseApkDir}/app-debug.apk"baseApkProguardMapping = "${bakPath}/${baseApkDir}/app-debug-mapping.txt"baseApkResourceMapping = "${bakPath}/${baseApkDir}/app-debug-R.txt"//正式
// baseApk = "${bakPath}/${baseApkDir}/app-release.apk"
// baseApkProguardMapping = "${bakPath}/${baseApkDir}/app-release-mapping.txt"
// baseApkResourceMapping = "${bakPath}/${baseApkDir}/app-release-R.txt"// 构建基准包跟补丁包都要修改tinkerId,主要用于区分
// tinkerId = "1.0.3-ccc"// 打多渠道补丁时指定目录buildAllFlavorsDir = "${bakPath}/${baseApkDir}"// 是否使用加固模式,默认为false// isProtectedApp = true// 是否采用反射Application的方式集成,无须改造ApplicationenableProxyApplication = true// 支持新增ActivitysupportHotplugComponent = true}/*** 一般来说,我们无需对下面的参数做任何的修改* 对于各参数的详细介绍请参考:* https://github.com/Tencent/tinker/wiki/Tinker-%E6%8E%A5%E5%85%A5%E6%8C%87%E5%8D%97*/
tinkerPatch {tinkerEnable = trueignoreWarning = falseuseSign = falsedex {dexMode = "jar"pattern = ["classes*.dex"]loader = []}lib {pattern = ["lib/*/*.so"]}res {pattern = ["res/*", "r/*", "assets/*", "resources.arsc", "AndroidManifest.xml"]ignoreChange = []largeModSize = 100}packageConfig {}sevenZip {zipArtifact = "com.tencent.mm:SevenZip:1.1.10"
// path = "/usr/local/bin/7za"}buildConfig {keepDexApply = false
// tinkerId = "base-2.0.1"}
}
如下图,作为参考:
在 tinkerSupport { } 里面有很多参数,请不要修改,还有需要看一下里面每个参数的意义;
这里说明几个比较重要的参数:
// 自动生成tinkerId, 你无须关注tinkerId,默认为falseautoGenerateTinkerId = true
参数 autoGenerateTinkerId = ture 自动生成 tinkerId,无需手动填写,方便了很多,也是和官网推荐 BuglyHotfixDemo 的一个区别;
添加这个参数也无需指定 tinkerId = "1.0.3-ccc" 这个参数;
正式和测试切换:
//测试baseApk = "${bakPath}/${baseApkDir}/app-debug.apk"baseApkProguardMapping = "${bakPath}/${baseApkDir}/app-debug-mapping.txt"baseApkResourceMapping = "${bakPath}/${baseApkDir}/app-debug-R.txt"//正式
// baseApk = "${bakPath}/${baseApkDir}/app-release.apk"
// baseApkProguardMapping = "${bakPath}/${baseApkDir}/app-release-mapping.txt"
// baseApkResourceMapping = "${bakPath}/${baseApkDir}/app-release-R.txt"
测试使用 debug ,正式使用 release;
参数 buildAllFlavorsDir,配置多渠道打包请打开,不需要请注释,最下面要配置多渠道打包,所有我就打开了;
// 打多渠道补丁时指定目录buildAllFlavorsDir = "${bakPath}/${baseApkDir}"
参数 isProtectedApp = true;测试千万不要开启,会引发不必要的 bug ,当应用需要加固时再开启;
// 是否使用加固模式,默认为false// isProtectedApp = true
参数 enableProxyApplication = true,无需改造 Application;
// 是否采用反射Application的方式集成,无须改造ApplicationenableProxyApplication = true
新建 MyApplication 加入下面代码:
public class MyApplication extends Application {@Overridepublic void onCreate() {super.onCreate();setStrictMode();// 设置是否开启热更新能力,默认为trueBeta.enableHotfix = true;// 设置是否自动下载补丁Beta.canAutoDownloadPatch = true;// 设置是否提示用户重启Beta.canNotifyUserRestart = false;// 设置是否自动合成补丁Beta.canAutoPatch = true;/*** 补丁回调接口,可以监听补丁接收、下载、合成的回调*/Beta.betaPatchListener = new BetaPatchListener() {@Overridepublic void onPatchReceived(String patchFileUrl) {//补丁包下载地址为patchFileUrl}@Overridepublic void onDownloadReceived(long savedLength, long totalLength) {//热修复回调成功}@Overridepublic void onDownloadSuccess(String patchFilePath) {//热修复下载成功}@Overridepublic void onDownloadFailure(String msg) {//热修复下载失败}@Overridepublic void onApplySuccess(String msg) {//补丁包应用成功}@Overridepublic void onApplyFailure(String msg) {//补丁包应用失败}@Overridepublic void onPatchRollback() {//补丁回滚}};long start = System.currentTimeMillis();Bugly.setUserId(this, "falue");Bugly.setUserTag(this, 123456);Bugly.putUserData(this, "key1", "123");Bugly.setAppChannel(this, "bugly");// 这里实现SDK初始化,appId替换成你的在Bugly平台申请的appId,调试时将第三个参数设置为trueBugly.init(this, "4bf2a8d8eb", true);long end = System.currentTimeMillis();Log.e("init time--->", end - start + "ms");
}@Overrideprotected void attachBaseContext(Context base) {super.attachBaseContext(base);// 热更新必须添加MultiDex.install(base);// 安装tinkerBeta.installTinker();}@TargetApi(9)protected void setStrictMode() {StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().permitAll().build());StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectAll().penaltyLog().build());}
}
别忘记在 AndroidManifest.xml 中使用:
需要注意的是,下面的代码中要换成你申请的 appId:
// 这里实现SDK初始化,appId替换成你的在Bugly平台申请的appId,调试时将第三个参数设置为trueBugly.init(this, "4bf2a8d8eb", true);
AndroidManifest.xml 文件中添加下面代码:
参考下图:
加入权限:
在 xml 中的 provider_paths 加入代码,没有请创建:
参考下图:
MainActivity 中加入代码:
public class MainActivity extends AppCompatActivity {private Button button; @Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);button = (Button) findViewById(R.id.button);button.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Toast.makeText(MainActivity.this, "这是存在bug的", Toast.LENGTH_SHORT).show();}});}
}
里面只有一个 button ;
最后加入混淆:
# Bugly混淆规则
-dontwarn com.tencent.bugly.**
-keep public class com.tencent.bugly.**{*;}
# tinker
-dontwarn com.tencent.tinker.**
-keep class com.tencent.tinker.** { *; }
参考下图:
多渠道打包配置,暂时配置三个:
productFlavors {huawei {// applicationId "com.tencent.bugly.hotfix.huawei"manifestPlaceholders = [CHANNEL_VALUE: "huawei"]}qihu360 {
// applicationId "com.tencent.bugly.hotfix.qihu360"manifestPlaceholders = [CHANNEL_VALUE: "qihu360"]}oppo {
// applicationId "com.tencent.bugly.hotfix.oppo"manifestPlaceholders = [CHANNEL_VALUE: "oppo"]}}
作为参考我给出我的 build.gradle 所有代码:
apply plugin: 'com.android.application'// 依赖插件脚本
apply from: 'tinker-support.gradle'android {compileSdkVersion 26buildToolsVersion '26.0.2'defaultConfig {applicationId "com.tencent.bugly.hotfix.easy"minSdkVersion 14targetSdkVersion 26versionCode 3versionName "1.0"flavorDimensions "versionCode"// 开启multidexmultiDexEnabled 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 truesigningConfig signingConfigs.releaseproguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'}debug {debuggable trueminifyEnabled false// signingConfig signingConfigs.debug}}sourceSets {main {jniLibs.srcDirs = ['libs']}}repositories {flatDir {dirs 'libs'}}// productFlavors 示例//flavorDimensions "tier"productFlavors {huawei {// applicationId "com.tencent.bugly.hotfix.huawei"manifestPlaceholders = [CHANNEL_VALUE: "huawei"]}qihu360 {
// applicationId "com.tencent.bugly.hotfix.qihu360"manifestPlaceholders = [CHANNEL_VALUE: "qihu360"]}oppo {
// applicationId "com.tencent.bugly.hotfix.oppo"manifestPlaceholders = [CHANNEL_VALUE: "oppo"]}}lintOptions {checkReleaseBuilds falseabortOnError false}
}dependencies {compile fileTree(dir: 'libs', include: ['*.jar'])compile 'com.android.support:appcompat-v7:26.1.0'// 多dex配置compile "com.android.support:multidex:1.0.2"// 本地集成aar方式// compile(name: 'bugly_crashreport_upgrade-1.3.6', ext: 'aar')// 远程依赖集成方式(推荐)compile "com.tencent.bugly:crashreport_upgrade:1.3.6"// 指定tinker依赖版本(注:应用升级1.3.5版本起,不再内置tinker)compile 'com.tencent.tinker:tinker-android-lib:1.9.9'}
上面的签名配置是我从 BuglyHotfixEasyDemo 中直接复制过来的;
所有配置完毕,下面就测试打包,点击右侧 Gradle ==> app ==> Tasks ==> build ==>assembleDebug ,如下图:
打包完毕,在左侧 app ==> bakApk 可以看到躺着三个包,这就是基准包,如下图:
需要注意的是:一般在正式的情况下,需要将 bakApk 文件夹里面的内容保存到本地,方便以后打补丁包使用,如果不存在了,直接复制到 bakApk 文件夹下面就可以了。
记住上面的 app-1126-16-12-58,也就是 bakApk ==> app-1126-16-12-58 ,这个是随机生成的,下面会使用到这个;
打开 tinker-support.gradle,找到 baseApkDir 参数,将里面的内容替换为 app-1126-16-12-58 ;如下图:
需要注意的是:你生成的是什么就写什么,这个是每打一次基准包,需要填写一次,打补丁包不需要改变;
一定要保证该目录下面有对应的包,这也就是上面为什么让你把基准包保存到本地的原因,以防丢失;
为了方便测试,将 MainActivity 中的提示改为下面:
Toast.makeText(MainActivity.this, "修复了bug,以便测试", Toast.LENGTH_SHORT).show();
点击右侧 Gradle ==> app ==> Tasks ==> tinker-support ==>buildAllFlavorsTinkerPatchDebug ,如下图:
等待过后,补丁包就打完了,在左侧 app ==> outputs ==> patch 中可以看到三个补丁包,如下图:
上面以 7-zip 结尾就是我们的补丁包了,也就是 patch_signed_7zip.apk ,也就是把这个包放到 bugly 官网就可以了;
下面就可以测试了,测试的时候需要注意:一定先将基本包安装到手机上,保证有网络的情况下打开 app ,让热更新代码走完补丁包才可以上传到 bugly 官网,否则上传不上去;
下面将基本包放到手机上面运行,因为打了三个包,就拿华为的包测试;
安装完毕,点击按钮可以发现,提示:这是存在bug的;与基本包一致,emmm;
打开 bugly 官网,将补丁包上传到官网,点击应用升级==>热更新==>发布新补丁,如下图所示:
不要上传错了,我们测试的是华为的基本包,所以补丁包也应该上传华为下面的 patch_signed_7zip.apk ;
上传如果提示,改包不合法,那么刷新页面再试一下,或者重新打开基本包的 app ;因为我也遇到过,是 bugly 后台的问题;
上传完毕,会自动识别版本,选择全量更新,写上备注,然后点击立即下发就可以了,如下图:
稍等片刻,就可以出现了,如下图:
我上面有两个,因为我已经测试过一次了,如果你们第一次测试,应该是一个。
热更新官网说是重启 app 就可以修复了,经过我测试,大概需要5分钟的时间,补丁才会生效,所以不必着急;
经过几分钟的重启 app ,点击按钮测试,发现提示语变成了:修复了bug,以便测试;
说明补丁包应用成功了,打开 bugly 官网,刷新页面,可以看到已经下发了一个了,如下图所示:
可以看到激活的数量为0,但我们已经应用成功了,因为有延迟,所以再过大概10分钟就可以看到激活量为1了,所以不用着急;
看完这个简单集成方式以后,再看 BuglyHotfixDemo 或者官网文档就会感觉简单多了。
如果你有什么问题,可以看下面我写的 demo ,或者留言;
https://github.com/wuqingsen/BuglyDemo
到这里就结束了。
记录一个bug,测试上没问题,但是我在正式上面先发成功,但是激活数量一直为0,如下图所示:
解决方法,在项目的 bulid.gradle 中的配置改为:
classpath "com.tencent.bugly:tinker-support:latest.release"
就好了,我之前用的是:
// classpath 'com.tencent.bugly:tinker-support:1.1.5' //之前配置classpath "com.tencent.bugly:tinker-support:latest.release" //修改后
做一下记录。