之前一直都是采用友盟的全家桶进行的异常收集,索性最近有时间就给新项目集成了Bugly的异常手机 ~
此篇主要记录我使用AndroidStudio自动集成Bugly的整体过程与最终实现,具体的集成方式还是以Bugly官方文档为准 – Bugly Android SDK 使用指南
目前我仅知俩种捕获异常方式(主讲第二种方式)
系统自带的异常机制,一般是通过实现Thread.UncaughtExceptionHandler接口来实现异常监听
集成三方平台用于捕获异常,我有使用Bugly集成测试过 ~
本篇Bugly的集成Demo,我已上传此处 ~
自动集成
准备工作
新建产品
产品详情
集成场景
集成SDK
同时集成SDK和NDK
SDK与NDK最新版本
参数配置
添加权限
避免混淆Bugly
Bugly初始化
提要
方式1:Application 初始化
最简单方式
项目方式
方式2:AndroidManifest.xml 初始化
实战检验
自造错误
平台查看
大功告成
个性化需求
增加上报进程控制
设置App版本、渠道、包名
设置延迟Bugly初始化
动态设置开发设备
准备工作
首先去官网,然后右上角登录帐户(我是用的QQ快捷登录了)
新建产品
右上角 → 我的产品 → 新建产品
自行创建新产品即可 ~
产品详情
选择对应产品的的操作设置
产品详情 – 这里我们主要用到APP ID
集成场景
注:下方依赖中的 latest.release = 对应的SDK、NDK版本号
集成SDK
在Module的build.gradle文件中添加依赖和属性配置:
//注意:其中latest.release指代最新Bugly SDK版本号,也可以指定明确的版本号,例如2.2.0
implementation 'com.tencent.bugly:crashreport:latest.release'
同时集成SDK和NDK
在Module的build.gradle文件中添加依赖和属性配置:
android {
defaultConfig {
ndk {
// 设置支持的SO库架构
abiFilters ‘armeabi’ //, ‘x86’, ‘armeabi-v7a’, ‘x86_64’, ‘arm64-v8a’
}
}
}
dependencies {
//其中latest.release指代最新Bugly SDK版本号,也可以指定明确的版本号,例如2.1.9
implementation ‘com.tencent.bugly:crashreport:latest.release’
//其中latest.release指代最新Bugly NDK版本号,也可以指定明确的版本号,例如3.0
implementation ‘com.tencent.bugly:nativecrashreport:latest.release’
}
如下
SDK与NDK最新版本
Android 异常上报 SDK 更新日志(版本)
注:如需集成SDK可将下图中最近的 3.2.422更新版本号 替换 依赖中的 latest.release
Android NDK 动态库更新日志(版本)
注:如需集成 NDK 可将下图中最近的 3.7.5更新版本号 替换 依赖中的 latest.release
参数配置
添加权限
在AndroidManifest.xml中添加权限:
注:如果您的App需要上传到google play store,您需要将READ_PHONE_STATE权限屏蔽掉或者移除,否则可能会被下架
避免混淆Bugly
请避免混淆Bugly,在Proguard混淆文件中增加以下配置:
注:这点建立在你的项目有混淆的基础上,如果你没有混淆的话,可以忽略此处 ~
-dontwarn com.tencent.bugly.**
-keep public class com.tencent.bugly.*{;}
Bugly初始化
以下俩种初始化方式,二选其一即可,建议采用项目方式!
注:如同时采用俩种方式进行初始化,那么以Application的初始化方式为准!
提要
因Bugly初始化一般都在Application内,而在项目开发中我们都会有自己的Application,例如我写Demo的时候就是创建的BuglyApplication继承了Application,当我们有自己的Application时记得在清单文件中进行注册,否则一切配置均无效 ~,如下
<!--主要声明:android:name=".BuglyApplication"-->
<application
android:allowBackup="true"
android:name=".BuglyApplication"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:networkSecurityConfig="@xml/network_security_config"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
方式1:Application 初始化
注:为了保证运营数据的准确性,建议不要在异步线程初始化Bugly
最简单方式
获取APP ID并将以下代码复制到项目Application类onCreate()中,Bugly会为自动检测环境并完成配置:
CrashReport.initCrashReport(getApplicationContext(), “注册时申请的APPID”, false);
项目方式
主要增加了上报进程控制和一些个性化需求,从而更贴近项目的实战场景 ~ 此处代码完全Copy到项目中使用 !
BuglyApplication
package nk.com.buglytest;
import android.app.Application;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.text.TextUtils;
import com.tencent.bugly.Bugly;
import com.tencent.bugly.crashreport.CrashReport;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
/**
- @author MrLiu
- @date 2020/10/14
- desc
*/
public class BuglyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();Context context = getApplicationContext(); // 获取当前包名 String packageName = context.getPackageName(); // 获取当前进程名 String processName = getProcessName(android.os.Process.myPid()); // 设置是否为上报进程 CrashReport.UserStrategy strategy = new CrashReport.UserStrategy(context); strategy.setUploadProcess(processName == null || processName.equals(packageName)); //设置渠道 strategy.setAppChannel("自行设置或动态读取渠道 ~"); //App的版本 strategy.setAppVersion(getVersionCode(this)); //App的包名 strategy.setAppPackageName(packageName);
// CrashReport.setIsDevelopmentDevice(context, true);
/*
*第三个参数为SDK调试模式开关, true:测试环境 false:正式环境,调试模式的行为特性如下:
*- 输出详细的Bugly SDK的Log
*- 每一条Crash都会被立即上报
*- 自定义日志将会在Logcat中输出
*建议在测试阶段建议设置成true,发布时设置为false ~
*/
CrashReport.initCrashReport(getApplicationContext(), “APPID”, true, strategy);
//userId
CrashReport.setUserId(“2020”);
} /**- 获取进程号对应的进程名
* - @param pid 进程号
- @return 进程名
*/
private static String getProcessName(int pid) {
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader(“/proc/” + pid + “/cmdline”));
String processName = reader.readLine();
if (!TextUtils.isEmpty(processName)) {
processName = processName.trim();
}
return processName;
} catch (Throwable throwable) {
throwable.printStackTrace();
} finally {
try {
if (reader != null) {
reader.close();
}
} catch (IOException exception) {
exception.printStackTrace();
}
}
return null;
}
/**
- 返回版本号
- 对应build.gradle中的versionCode
* - @param context context
- @return String
*/
public static String getVersionCode(Context context) {
String versionCode = “”;
try {
PackageManager packageManager = context.getPackageManager();
PackageInfo packInfo = packageManager.getPackageInfo(context.getPackageName(), 0);
versionCode = String.valueOf(packInfo.versionCode);
} catch (Exception e) {
e.printStackTrace();
}
return versionCode;
}
}
- 获取进程号对应的进程名
方式2:AndroidManifest.xml 初始化
Bugly2.0及以上版本还支持通过”AndroidManifest.xml”来配置APP信息。如果同时又通过代码中配置了APP信息,则最终以代码配置的信息为准
在AndroidManifest.xml的”Application”中增加“meta-data”配置项:
注:”BUGLY_APP_VERSION”配置的是Bugly平台的APP版本号!而不是”android:versionName”!
通过”AndroidManifest.xml”配置后的初始化方法如下:
CrashReport.initCrashReport(getApplicationContext());
实战检验
自造错误
package nk.com.buglytest;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import com.tencent.bugly.crashreport.CrashReport;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.tv_btn1).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//Bugly自带的一个造错方法,想自己写个崩溃也行
CrashReport.testJavaCrash();
}
});
}
}
平台查看
我的产品 – 点击已创建好的商品
崩溃分析
大功告成
查看具体崩溃详情后,发现错误详情还是蛮详细的,所以可以收工咯 ~
个性化需求
关于个性化需求在我认为都是针对的项目开发场景进行的功能扩展,其具体的扩展内容可 前往官方文档进行查看 ~
增加上报进程控制
如果App使用了多进程且各个进程都会初始化Bugly(例如在Application类onCreate()中初始化Bugly),那么每个进程下的Bugly都会进行数据上报,造成不必要的资源浪费 ~
因此,为了节省流量、内存等资源,建议初始化的时候对上报进程进行控制,只在主进程下上报数据:判断是否是主进程(通过进程名是否为包名来判断),并在初始化Bugly时增加一个上报进程的策略配置
Context context = getApplicationContext();
// 获取当前包名
String packageName = context.getPackageName();
// 获取当前进程名
String processName = getProcessName(android.os.Process.myPid());
// 设置是否为上报进程
UserStrategy strategy = new UserStrategy(context);
strategy.setUploadProcess(processName == null || processName.equals(packageName));
// 初始化Bugly
CrashReport.initCrashReport(context, “注册时申请的APPID”, isDebug, strategy);
// 如果通过“AndroidManifest.xml”来配置APP信息,初始化方法如下
// CrashReport.initCrashReport(context, strategy);
其中获取进程名的方法“getProcessName”有多种实现方法,推荐方法如下:
/**
- 获取进程号对应的进程名
- @param pid 进程号
- @return 进程名
*/
private static String getProcessName(int pid) {
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader(“/proc/” + pid + “/cmdline”));
String processName = reader.readLine();
if (!TextUtils.isEmpty(processName)) {
processName = processName.trim();
}
return processName;
} catch (Throwable throwable) {
throwable.printStackTrace();
} finally {
try {
if (reader != null) {
reader.close();
}
} catch (IOException exception) {
exception.printStackTrace();
}
}
return null;
}
设置App版本、渠道、包名
Bugly默认读取AndroidManifest.xml文件中VersionName、Package信息。若您有自己的版本或渠道设定需求,可通过该接口修改
strategy.setAppChannel(“myChannel”); //设置渠道
strategy.setAppVersion(“1.0.1”); //App的版本
strategy.setAppPackageName(“com.tencent.xx”); //App的包名
设置延迟Bugly初始化
Bugly会在启动10s后联网同步数据。若您有特别需求,可以修改这个时间 ~
方式1:将此属性在初始化钱就设置完成
strategy.setAppReportDelay(20000); //改为20s
方式2:初始化完成后,通过 CrashReport.setUserId(“userId”)进行设置
CrashReport.initCrashReport(getApplicationContext(), "APPID", true, strategy);
//设置 userId
CrashReport.setUserId("2020");
动态设置开发设备
在开发测试阶段,可以在初始化Bugly之前通过以下接口把调试设备设置成“开发设备”
CrashReport.setIsDevelopmentDevice(context, true);
ADT 17增加了BuildConfig特性,可以通过获取BuildConfig类的DEBUG变量来设置:
CrashReport.setIsDevelopmentDevice(context, BuildConfig.DEBUG);
这里主要通过BuildConfig.DEBUG来判断当前apk是debug包还是release包,故个人感觉可以在项目初始化时让第三个参数使用BuildConfig.DEBUG
//改前
CrashReport.initCrashReport(getApplicationContext(), “2329160dcf”, true, strategy);
//改后
CrashReport.initCrashReport(getApplicationContext(), “2329160dcf”, BuildConfig.DEBUG, strategy);