Bugly 网易云捕 Crashlytic 是目前比较流行的崩溃异常的收集工具,能够及时地跟踪我们发布出去的Apk的质量并有专门的统计功能,能够让我们运筹帷幄之中,发现Bug于千里之外。借来将介绍怎么将Bugly,网易云捕这两款产品应用到我们项目中。
在这里我们都只介绍自动导入的方式,如果要手动导入可以到官网查看对应的信息,这个没什么技术含量,一看就会,之所以在这里介绍第一是为了整个知识体系的完整性,其二是为了避免每次都查阅官网耗费时间。

在介绍网易云捕和Bugly之前先贴一个别人关于当前代码质量管理工具对比的文章以便让大家对这些工具有个初步的了解:
移动平台质量跟踪系统对比-crashlytics、网易云捕、友盟、bugly

网易云捕


官方地址
一. 库文件导入
方式一:自动导入(推荐)

在Module的build.gradle文件中添加依赖和属性配置:

android {
defaultConfig {
ndk {
//设置支持的SO库架构
abiFilters "armeabi" //,"armeabi-v7a", "x86","arm64-v8a","x86_64"
}
}
}

dependencies {
compile 'com.netease.nis.plugin:bugrpt:latest.release' //集成最新版本,也可以指定版本号,比如3.6.5
}

注意:自动集成时会自动包含Bugrpt SO库,建议在Module的build.gradle文件中使用NDK的“abiFilter”配置,设置支持的SO库架构。
如果在添加“abiFilter”之后Android Studio出现以下提示:

NDK integration is deprecated in the current plugin. Consider trying the new experimental plugin.
则在项目根目录的gradle.properties文件中添加:

android.useDeprecatedNdk=true

二. 权限信息配置

需要在AndroidManifest.xml中添加以下权限:

<uses-permission android:name="android.permission.READ_PHONE_STATE"/><!-- 获取设备信息 -->
<uses-permission android:name="android.permission.INTERNET"/><!-- 网络通信-->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/><!-- 获取网络状态 -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/><!-- 获取MAC地址-->
<uses-permission android:name="android.permission.READ_LOGS" /><!-- 获取日志-->

在Android M系统以后,android.permission.READ_PHONE_STATE被设定为敏感权限,如果AndroidManifest.xml文件中targetSdkVersion被设置为23以上,且代码中没有请求过该权限,可能导致获取的imei、deviceID等设备信息为空,但是对程序的稳定性并没有影响。

三. AppID配置
还需在AndroidManifest.xml的application中添加标签,其中android:value填写您APP的AppID值,可以在”用户中心“-”设置“-”产品信息“中获取。

<application>
<meta-data android:name="BUGRPT_APPID" android:value="Please input your Appid"/>
</application>

四. 简单的初始化调用

在项目Application类或者主Activity类的onCreate()方法中添加以下代码:

CrashHandler.init(getApplicationContext());

如果Java层或NDK代码发生异常时,bugrpt便会捕获到该异常并发送给服务器。

六. 简单例子

  • Java 例子:
protected void onCreate(Bundle savedInstanceState) {  
super.onCreate(savedInstanceState);
//1.初始化云捕sdk
com.netease.nis.bugrpt.CrashHandler.getInstance().init(this.getApplicationContext(),null);

setContentView(R.layout.activity_main);
btn_crash = (Button)findViewById(R.id.btn_crash);
btn_crash.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
//2.测试异常代码
throw new RuntimeException("This is a crash!");
}
});
}
  • NDK 例子
    static {
    //导入demo.so
      System.loadLibrary("demo");
    }
    public native void msg(String s);

    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    //1.初始化云捕sdk
    com.netease.nis.bugrpt.CrashHandler.getInstance().init(this.getApplicationContext(),null);

    btn_crash.setOnClickListener(new OnClickListener() {
       @Override
       public void onClick(View v) {
    //2.调用ndk层msg函数
         msg("hellondk");
       }
    });
    }
    而msg函数则是打印一个字符串最后触发了一个异常,C++实现代码如下:
    JNIEXPORT void msg(JNIEnv *env, jobject  clazz, jstring str)
    {
    char *pszstr = NULL;
    pszstr = jstringTostring(env, str);
    LOGI("%s", pszstr);
    free(pszstr);
      //以下是触发异常的代码
    pszstr = NULL;
    *pszstr = 0;
    }
    可以尝试生成APK之后,点击按钮触发模拟异常,后台便能查询到如下崩溃日志:

崩溃日志内容:

--- --- --- --- NATIVE CRASH LOG BY BUGRPT- --- --- --- --- ---
CRASH TIME: 1425530709912
CRASH APP: com.example.crash, pid: 12916, tid: 12916
Build fingerprint: 'Meizu/meizu_mx3/mx3:4.4.4/KTU84P/m35x.Flyme_OS_3.7.3.20140909113158:user/release-keys'
signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 00000000
--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
registers:
r0 00000000 r1 00000000 r2 00000001 r3 00000000
r4 774a1458 r5 415ab438 r6 00000000 r7 6d460dd0
r8 beb81508 r9 6d460dc8 10 415ab448 fp beb8151c
ip 00000001 sp beb81500 lr 40047ce1 pc 7528edf2 cpsr 60070030
--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
callstacks:
#00 pc 00000df2 /data/app-lib/com.example.crash-2/libdemo.so (msg + 21)
#01 pc 0001db8c /system/lib/libdvm.so (dvmPlatformInvoke + 70)
#02 pc 0004e174 /system/lib/libdvm.so (_Z16dvmCallJNIMethodPKjP6JValuePK6MethodP6Thread + 18f)
#03 pc 00026fa0 /system/lib/libdvm.so
#04 pc 0002dfb8 /system/lib/libdvm.so (_Z11dvmMterpStdP6Thread + 4c)
#05 pc 0002b61c /system/lib/libdvm.so (_Z12dvmInterpretP6ThreadPK6MethodP6JValue + b8)
#06 pc 0006087a /system/lib/libdvm.so (_Z15dvmInvokeMethodP6ObjectPK6MethodP11ArrayObjectS5_P11ClassObjectb + 189)
#07 pc 00068896 /system/lib/libdvm.so
#08 pc 00026fa0 /system/lib/libdvm.so
#09 pc 0002dfb8 /system/lib/libdvm.so (_Z11dvmMterpStdP6Thread + 4c)
#10 pc 0002b61c /system/lib/libdvm.so (_Z12dvmInterpretP6ThreadPK6MethodP6JValue + b8)
#11 pc 00060596 /system/lib/libdvm.so (_Z14dvmCallMethodVP6ThreadPK6MethodP6ObjectbP6JValueSt9__va_list + 151)
#12 pc 00049d5a /system/lib/libdvm.so
#13 pc 0004dec2 /system/lib/libandroid_runtime.so
#14 pc 0004ebe6 /system/lib/libandroid_runtime.so (_ZN7android14AndroidRuntime5startEPKcS2_ + 161)
#15 pc 4001a090 /system/bin/app_process
#16 pc 0000e41e /system/lib/libc.so (__libc_init + 31)
--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---

可以很清晰地看出崩溃发生在msg函数的某个偏移,pc为00000df2,可以通过addr2line很方便地转换为出错的代码行号。
addr2line -C -f -e libxxx.so 00000df2

五. Proguard混淆配置
避免混淆Bugrpt SDK,请在Proguard混淆文件中配置:

-keep class com.netease.nis.bugrpt.** {*;}

六. 配置mapping

生成APK的时候一般都需要进行混淆处理,此时崩溃发生时产生的崩溃堆栈信息都是混淆后的符号,不便于排查BUG。为了能正确地还原回源码时的堆栈,需要配置一下mapping.txt文件,让“云捕”自动化进行反混淆处理。
混淆处理时,利用proguard在混淆后会生成一个mapping.txt文件,该文件地址Android Studio则是根据配置生成在指定目录下。

Android Studio:

只需要把这个mapping.txt文件上传到后台即可。登录云捕系统,选择您的APP后点击“上传mapping“

七.高级设置:
我们提供UserStrategy类作为Bugrpt的初始化扩展,开发者可以传入一些自定义信息。通过以下方式传入:

Context appCtx = this.getApplicationContext();
UserStrategy strategy = new UserStrategy(appCtx);
//...在这里设置strategy的属性,在bugrpt初始化时传入
CrashHandler.init(appCtx, strategy);

UserStrategy与CrashHandler类的主要API:

  • 设置渠道:
    Bugrpt默认读取AndroidManifest.xml文件中渠道信息,可通过该接口修改渠道信息。

    strategy.setChannel("myChannel");
  • 设置用户账户:
    Bugrpt可以设置用户的账户信息,方便开发者针对性排错。

    strategy.setUserId("myUserID")
  • 设置场景:
    Bugrpt可以设置崩溃场景。

    CrashHandler.setUserScene("myScene");
  • 设置自定义Map参数对:
    Bugrpt支持用户自定义Map参数可以保存发生Crash时的一些自定义的环境信息。在发生Crash时会随着异常信息一起上报并在页面展示。

    CrashHandler.addUserParam("key", "value");

    注意:最多可以有9对自定义的key-value(超过则添加失败),key限长50字节、value限长200字节,过长截断。

  • 主动上报开发者catched的异常
    开发者可能会关注到某个重要异常的catch情况,我们提供了这样的接口:

    try{
    //...
    }catch (Exception e){
    CrashHandler.uploadCatchedException(e);
    }
  • 开发者主动上传信息接口
    为了方便开发者跟踪代码的执行情况,通过主动上传信息接口获取当前程序执行的一些信息(开发者记录的信息+堆栈信息)。使用示例:

    CrashHandler.uploadTrackRecord("myTrackLog");
  • 开发者记录面包屑接口
    开发者通过面包屑功能,追踪程序执行的路径信息,这些信息在App Crash的时候一并上传。使用示例:

    CrashHandler.leaveBreadcrumb("track message");
  • ReLinker.loadLibrary接口
    为了防止Android系统本身的安装逻辑bug导致的java.lang.UnsatisfiedLinkError致命错误,集成了Relinker类的loadLibrary接口,用来替代System.loadLibrary接口。使用说明:
    在原本使用System.loadLibrary调用处

    System.loadLibrary("mylib");

    替换为Relinker.loadLibrary

    ReLinker.loadLibrary(this.getApplicationContext(),"mylib");






网易除了推出了云捕外还推出了云加密,下面是对应的链接:
网易云加密

Bugly

官方地址
Bugly 相对功能会比网易云捕的功能强大些,但是就基本Crash跟踪的话和网易云捕使用方法类似。下面是Bugly的四大核心功能,个人偏向推荐使用这个平台。

一. 库文件导入

如果您使用Gradle编译Apk,我们强烈推荐您使用自动接入方式配置库文件。Bugly支持JCenter仓库和 Maven仓库。
方式1:自动导入(推荐)
为了实现更加灵活的配置,Bugly SDK(2.1.5及以上版本)和NDK(SO库)目前已经分开成两个独立的仓库:

SDK:com.tencent.bugly:crashreport
NDK:com.tencent.bugly:nativecrashreport

其中,集成Bugly NDK时,需要同时集成Bugly SDK。
单独集成Bugly SDK
在Module的build.gradle文件中添加依赖和属性配置:

dependencies {
compile 'com.tencent.bugly:crashreport:latest.release' //其中latest.release指代最新版本号,也可以指定明确的版本号,例如2.1.5
}

同时集成Bugly SDK和NDK
在Module的build.gradle文件中添加依赖和属性配置:

android {
defaultConfig {
ndk {
// 设置支持的SO库架构
abiFilters 'armeabi' //, 'x86', 'armeabi-v7a', 'x86_64', 'arm64-v8a'
}
}
}
dependencies {
compile 'com.tencent.bugly:crashreport:latest.release' //其中latest.release指代最新版本号,也可以指定明确的版本号,例如2.1.5
compile 'com.tencent.bugly:nativecrashreport:latest.release' //其中latest.release指代最新版本号,也可以指定明确的版本号,例如2.2.0
}

注意:自动集成时会自动包含Bugly SO库,建议在Module的build.gradle文件中使用NDK的“abiFilter”配置,设置支持的SO库架构。
如果在添加“abiFilter”之后Android Studio出现以下提示:

NDK integration is deprecated in the current plugin. Consider trying the new experimental plugin.

则在项目根目录的gradle.properties文件中添加:

android.useDeprecatedNdk=true

为了使APP Crash堆栈的可读性更高,建议您配置符号表文件,更准确地定位问题:
纯Java代码的工程:只需要配置混淆后生成的Mapping文件即可;
含有Native代码的工程:建议配置符号表工具从Debug SO中提取的Symbol符号表文件。

Bugly支持手动和自动配置两种方式,具体的配置方法请参考如下:

二. Bugly Android符号表配置

  • 什么是符号表?

符号表是内存地址与函数名、文件名、行号的映射表。符号表元素如下所示:
<起始地址> <结束地址> <函数> [<文件名: 行号>]

  • 为什么要配置符号表
    为了能快速并准确地定位用户APP发生Crash的代码位置,Bugly使用符号表对APP发生Crash的程序堆栈进行解析和还原。

  • 自动配置:使用Android Studio插件

Bugly插件最新版本为:1.3.9,注意插件位于JCenter仓库。
在项目的buid.gradle文件的dependencies(buildscript部分)中添加:

classpath 'com.tencent.bugly:symtabfileuploader:1.3.9'

其中1.3.9为插件版本号
在module的buid.gradle文件的顶部添加:

apply plugin: 'bugly'
bugly {
appId = '<App ID>'
appKey = '<App Key>'
}

除了appId和appKey之外,还可以设置其他属性,属性列表如下:
属性 值 说明
appId String App ID
appKey String App Key
execute boolean 插件开关
upload boolean 上传开关
outputDir String 符号表文件输出路径

/build.gradle文件如下:

buildscript {
repositories {
jcenter()
}
dependencies {
...
classpath 'com.tencent.bugly:symtabfileuploader:1.3.9'
}
}}

其中”1.3.9”为Bugly插件版本号,更新插件只需要修改这个版本号并Rebuild一下工程即可。

//build.gradle文件如下:

apply plugin: 'bugly'
...
bugly {
appId = '900000000'
appKey = 'abcdefghijklmn'
}

项目应用了Bugly插件之后,Gradle会新建出一个“uploadReleaseSymtabFile”的任务,该任 务被“assembleRelease”任务依赖,即在Release编译时执行。

uploadReleaseSymtabFile任务将执行以下动作:
当项目使用了Proguard,将自动上传生成的mapping文件;
当项目使用了NDK,将自动扫描Debug SO文件,生成符号表文件(zip)并自动上传。
其中查找Debug SO文件时,首先会扫描默认的NDK路径,如果未找到,将继续扫描 项目路径。

三、参数配置

在AndroidManifest.xml中添加权限:

<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.READ_LOGS" />

请避免混淆Bugly,在Proguard混淆文件中增加一行配置:

-dontwarn com.tencent.bugly.**
-keep public class com.tencent.bugly.**{*;}

四、最简单的初始化

获取APP ID并将以下代码复制到项目Application类onCreate()中,Bugly会为自动检测环境并完成配置:

CrashReport.initCrashReport(getApplicationContext(), "注册时申请的APPID", false);

为了保证运营数据的准确性,建议不要在异步线程初始化Bugly。

第三个参数为SDK调试模式开关,调试模式的行为特性如下:

● 输出详细的Bugly SDK的Log
● 每一条Crash都会被立即上报;
● 自定义日志将会在Logcat中输出。

建议在测试阶段建议设置成true,发布时设置为false。
此外,Bugly2.0及以上版本还支持通过“AndroidManifest.xml”来配置APP信息。如果同时又通过代码中配置了APP信息,则最终以代码配置的信息为准。

在“AndroidManifest.xml”的“Application”中增加“metadata”配置项:

<application
<!-- 配置APP ID -->
<meta-data
android:name="BUGLY_APPID"
android:value="<APP ID>" />
<!-- 配置APP版本号 -->
<meta-data
android:name="BUGLY_APP_VERSION"
android:value="<APP Version>" />
<!-- 配置APP渠道号 -->
<meta-data
android:name="BUGLY_APP_CHANNEL"
android:value="<APP Channel>" />
<!-- 配置Bugly调试模式(true或者false)-->
<meta-data
android:name="BUGLY_ENABLE_DEBUG"
android:value="<isDebug>" />
</application>

不同于“android:versionName”,“BUGLY_APP_VERSION”配置的是Bugly平台的APP版本号。

通过“AndroidManifest.xml”配置后的初始化方法如下:

CrashReport.initCrashReport(getApplicationContext());

同样 Bugly也提供了UserStrage功能,也就是从功能上看网易云盘有的功能Bugly都有,而Buyly还具备一些网易云盘没有的特色功能如ANR等。
要进一步了解这些功能可以查看如下链接:

https://bugly.qq.com/androidmore
https://bugly.qq.com/document
https://bugly.qq.com/betaDocument

Contents
  1. 1. 网易云捕
  2. 2. Bugly