1. 程式人生 > >Android應用崩潰檢測----Bugly捕獲Crash異常

Android應用崩潰檢測----Bugly捕獲Crash異常

在開發當中,當程式釋出出去之後,如果出現了崩潰的問題,開發者應該及時獲取在該裝置上導致崩潰的資訊,這對於下一個版本的bug修復幫助極大,所以捕獲Crash,獲取裝置引數資訊和錯誤日誌就顯得尤為重要,現在有很多第三方平臺可以實現這些功能,在我們這裡介紹的是騰訊的Bugly.

註冊APP應用

  • 註冊成功以後在我的產品裡面找到APP,點選“設定”。
    這裡寫圖片描述

  • 進入設定後找到App ID,在初始化的時候會用。
    這裡寫圖片描述

庫檔案匯入

Bugly支援自動整合和手動整合兩種方式,如果您使用Gradle編譯Apk,強烈推薦您使用自動接入方式配置庫檔案。

自動整合步驟

Bugly支援JCenter倉庫和Maven Central倉庫。為了實現更加靈活的配置,Bugly SDK(2.1.5及以上版本)和NDK(SO庫)目前已經分開成兩個獨立的倉庫:

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

其中,整合Bugly NDK時,需要同時整合Bugly SDK。

同時整合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指代最新Bugly SDK版本號,也可以指定明確的版本號,例如2.1.9 compile 'com.tencent.bugly:nativecrashreport:latest.release' //其中latest.release指代最新Bugly NDK版本號,也可以指定明確的版本號,例如3.0 }

同時整合Bugly SDK和NDK的配置如下圖所示,後續更新Bugly SDK和NDK時,只需變更配置指令碼中的版本號即可。
這裡寫圖片描述

注意:自動整合時會自動包含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

這裡寫圖片描述

許可權配置

  • 在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.**{*;}

這裡沒有做混淆處理,所以只給出Proguard混淆檔案位置。如圖所示:
這裡寫圖片描述

初始化

獲取APP ID並將以下程式碼複製到專案Application類onCreate()中,Bugly會為自動檢測環境並完成配置:

//為了保證運營資料的準確性,建議不要在非同步執行緒初始化Bugly。

CrashReport.initCrashReport(getApplicationContext(), "註冊時申請的APPID", false); 

第三個引數為SDK除錯模式開關,除錯模式的行為特性如下:

  • 輸出詳細的Bugly SDK的Log;
  • 每一條Crash都會被立即上報;
  • 自定義日誌將會在Logcat中輸出。

    建議在測試階段建議設定成true,釋出時設定為false。

此外,Bugly2.0及以上版本還支援通過“AndroidManifest.xml”來配置APP資訊。如果同時又通過程式碼中配置了APP資訊,則最終以程式碼配置的資訊為準。

在“AndroidManifest.xml”的“Application”中增加“meta-data”配置項:

<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預設從“AndroidManifest.xml”檔案中讀取“VersionName”作為版本號,自定義設定請使用參考“高階設定”。

MultiDex注意事項

MultiDex問題簡介

Android 的classLoader在載入APK的時候限制了class.dex包含的Java方法總數不能超過65535,如果超出會報異常。但是現在隨便一個複雜一點的App,輕而易舉就能超過65535。MultiDex是google為了解決這個問題推出了官方的解決方案。(百度關鍵詞:MultiDex)

如果使用了MultiDex,建議通過Gradle的“multiDexKeepFile”配置等方式把Bugly的類放到主Dex,Bugly 類放到主Dex,方式有兩種(以下兩種方式使用一種即可):

multiDexKeepFile 屬性

build.gradle的同級目錄下建立 multiDexKeep.txt,在 multiDexKeep.txt 中配置進需要手動插入的 類的完整路徑 即 包名+類名.class
這裡寫圖片描述

然後在bulid.gradle裡配置

android {
    defaultConfig {
        multiDexEnabled true
        multiDexKeepFile file('multiDexKeep.txt') // keep specific classes
    }
}

multiDexKeepProguard 屬性

build.gradle的同級目錄下建立multiDexKeep.pro,multiDexKeep.pro中的配置與混淆檔案的配置相同 使用 -keep class xxxx 指定類名
這裡寫圖片描述
然後在bulid.gradle裡配置

android {
    defaultConfig {
        multiDexEnabled true
        multiDexKeepProguard file('multidexKeep.pro')
    }
}

另外建議在Application類的”attachBaseContext”方法中主動載入非主dex:

public class MyApplication extends SomeOtherApplication {
  @Override
  protected void attachBaseContext(Context base) {
     super.attachBaseContext(context);
     Multidex.install(this);
  }
}

增加上報程序控制

如果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;
}

測試

現在您可以製造一個Crash(建議通過“按鍵”來觸發),來體驗Bugly的能力了。在初始化Bugly的之後,呼叫Bugly測Java Crash介面。

CrashReport.testJavaCrash();

執行到這段程式碼時會發生一個Crash,Logcat的TAG=CrashReportInfo中輸出為:
這裡寫圖片描述
現在您已經可以在“崩潰”頁面看到剛才觸發的Crash issue了(延遲一般在10s以內)。

如果專案包含了Native工程或者使用了程式碼混淆,建議配置符號表檔案,具體請參考“符號表配置

總結

其實這篇部落格大部分還是從官方文件拷貝的,因為步驟是相同的,寫出來的東西肯定也是萬變不離其宗,其中在每一步都加了圖片參考,會有一個更直觀的展示。再一個,在multiDex處理時有些需要注意的地方,都已經註明了,如果有疑問和錯誤歡迎各位小夥伴留言批評指正。