Android 崩潰日誌採集元件-DhccCrashLib

賈亦真亦賈發表於2019-05-10

異常崩潰怎麼辦?

關於異常崩潰是每個App都要面對的,平時開發還好,在除錯狀態下遇到的問題,可以通過LogCat列印的異常日誌資訊進行分析處理,但是一旦App上線後,大量使用者安裝了你的應用,每個使用者的手機大小、感測器、SDK版本都不盡相同,可能你在測試機上跑的穩穩的應用,到了客戶手機上就會出現一些莫名其妙的異常,如果只是一些記憶體洩露的問題可能還好,最起碼不會瞬間崩潰,但是如果遇到一些可以導致手機崩潰Bug的話,你讓出問題的使用者來複現Bug是不可能的,所以,全域性異常捕獲就顯得很重要了,而DhccCrashLib就是一個全域性異常捕獲的元件。

DhccCrashLib怎麼用?

Github地址

使用方法還是比較簡單的,首先在專案的根目錄下的build.gradle中加入Jcenter倉庫:

 repositories {
        jcenter()
    }
複製程式碼

然後在你的專案的build.gradle中新增依賴:

implementation 'com.dhcc.crashlib:CrashLib:1.0.3'
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.github.zhaokaiqiang.klog:library:1.6.0'
implementation "com.sun.mail:android-mail:1.6.0"
複製程式碼

這四個依賴都需要加,因為擔心版本衝突,所以我在元件中使用的依賴方式是compileOnly,那麼你在你的專案中如果有引用除了CrashLib外的這三個依賴的話,就可以換成你自己的版本號即可。

使用方式 在你專案的自定義Application中:

public class MyApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        initCrash();
    }

    /**
     * 初始化崩潰採集服務
     */
    private void initCrash() {
        EmailConfigBean emailConfigBean = new EmailConfigBean("你的傳送郵箱", "你的接收郵箱", "你的傳送郵箱密碼");
        Configuration configuration=Configuration.getInstance()
                //你的郵件配置例項
                .setEmailConfig(emailConfigBean)
                //是否通過郵件傳送異常
                .setSendWithEmail(true)
                //是否通過郵件傳送異常並將本地儲存的異常已附件的形式傳送
                .setSendEmailWithFile(true)
                //異常伺服器的API
                .setCrashServerUrl("http://111.222.333.444:9999/api/crashs")
                //是否給伺服器傳送異常資訊
                .setSendWithNet(true)
                //異常的描述資訊
                .setCrashDescription("測試異常~~")
                //捕獲異常後退出App的等待時間 毫秒
                .setExitWaitTime(5000)
                ;
        LogCenter.getLogCenter("程式名", configuration)
                //可以自定義異常 只要實現ICollector 並傳入網路提交時所需要的key即可
                .strategy(new TestCollectInfo(), "網路屬性的Key")
                .init(this);
    }
}
複製程式碼

就這麼簡單,首先先把你的傳送郵箱和接收郵箱的相關資訊都配置到EmailConfigBean中去,然後再呼叫LogCenter初始化相關引數即可,不過這裡有一個細節需要講一下,注意看TestCollectInfo()這個方法:

public class TestCollectInfo implements ICollector {
    @Override
    public String collectInfo(Context context) {
        return "這是一條測試採集異常資訊";
    }
}
複製程式碼

由於每個專案不同,可能需要採集的異常資訊外的其他一些手機資訊都不盡相同,我這裡在原始碼中只設計了Key為deviceInfo和Key為exceptionInfo的兩種捕獲資訊,deviceInfo主要是為了捕獲手機資訊的而exceptionInfo就是捕獲異常崩潰資訊的了,如果你的專案中還需要捕獲其他型別的資訊,可以通過實現ICollector介面來定義自己想提交的採集資訊即可,記得在初始化時呼叫.strategy(new TestCollectInfo(), "網路屬性的Key")將採集資訊傳入即可。

配套的Express檔案

你可能會納悶了,什麼是Express?這檔案是幹嘛的?

看過前面的部分後,你可能知道了這個元件是可以將異常資訊傳送給伺服器的,而看這篇文章的很多可能都是移動端的開發人員,不一定懂服務端,就算懂,也未必能很快的搭建一個可以接受異常資訊的服務端來測試,那麼為了大家測試方便,我就把我的Express檔案分享出來,如果你還不知道什麼是Express或者Node.js,建議你先看這篇:

Express快速搭建移動端測試用Api服務端

之後將你Nodejs根目錄下的app.js改為:

var fs = require('fs');
var path = require('path');
var express = require('express');
var bodyParser = require('body-parser');
var app = express();
var CRASH_FILE = path.join(__dirname, 'api/crashs.json'); // user.json檔案的路徑

app.set('port', (process.env.PORT || 9999));
app.use('/', express.static(path.join(__dirname, 'public')));
//使用body-parser中介軟體
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
app.use(function(req, res, next) {
    // Set permissive CORS header - this allows this server to be used only as
    // an API server in conjunction with something like webpack-dev-server.
    res.setHeader('Access-Control-Allow-Origin', '*');
    // Disable caching so we'll always get the latest comments.
    res.setHeader('Cache-Control', 'no-cache');
    next();
});


//處理/api/crashs的POST請求
app.post('/api/crash', function(req, res) {
  fs.readFile(CRASH_FILE, function(err, data) {
    if (err) {
      console.error(err);
      process.exit(1);
    }
    var crashs = JSON.parse(data);
    //控制post提交的引數型別
    var crash = {
      deviceinfo: req.body.deviceInfo,
      exceptioninfo: req.body.exceptionInfo,
		  testinfo:req.body.testInfo
    };
    //將user加入到users中去。
    crashs.push(crash);
    fs.writeFile(CRASH_FILE, JSON.stringify(crashs, null, 4), function(err) {
      if (err) {
        console.error(err);
        process.exit(1);
      }
      //請求成功後返回的提示json
      res.json("{code: 200, message: 'upload crash successful.'}");
    });
  });
});


app.listen(app.get('port'), function() {
  console.log('Server started: http://localhost:' + app.get('port') + '/');
});
複製程式碼

並且在同目錄的資料夾:api中放入crashs.json:

[
    {
        "deviceinfo": "手機資訊異常===========================================<br>DISPLAY=Flyme 6.8.3.31R beta<br>REGION=CN<br>SERIAL=d4aa09c3<br>BOOTLOADER=unknown<br>SOFT_VERSION=Y.30<br>SUPPORTED_64_BIT_ABIS=[Ljava.lang.String;@e6de412<br>PERMISSIONS_REVIEW_REQUIRED=false<br>AUTO_TEST_ONEPLUS=false<br>ID=NMF26F<br>TAG=Build<br>HOST=xs-MacBookPro<br>TAGS=test-keys<br>TIME=1522481855000<br>TYPE=user<br>USER=xs<br>BOARD=QC_Reference_Phone<br>BRAND=OnePlus<br>MODEL=ONEPLUS A3010<br>RADIO=unknown<br>SUPPORTED_ABIS=[Ljava.lang.String;@833c7e3<br>MANUFACTURER=OnePlus<br>PRODUCT=OnePlus3<br>UNKNOWN=unknown<br>versionCode=1<br>versionName=1.0<br>IS_EMULATOR=false<br>FINGERPRINT=OnePlus/OnePlus3/OnePlus3T:7.1.1/NMF26F/builder.20180331153735_R:user/test-keys<br>HARDWARE=qcom<br>SUPPORTED_32_BIT_ABIS=[Ljava.lang.String;@b31279d<br>IS_BETA_ROM=true<br>CPU_ABI2=<br>CPU_ABI=arm64-v8a<br>IS_DEBUGGABLE=false<br>DEBUG_ONEPLUS=false<br>DEVICE=OnePlus3T<br>===========================================<br>",
        "exceptioninfo": "Time:Fri May 10 14:23:32 GMT+08:00 2019  [Thread(id:3321, name:pool-2-thread-1, priority:5, groupName:main): LogCenter.java:184 run java.lang.RuntimeException: 測試CrashLib\n\tat com.dhcc.test.MainActivity$1.onClick(MainActivity.java:18)\n\tat android.view.View.performClick(View.java)\n\tat android.view.View$PerformClick.run(View.java:22549)\n\tat android.os.Handler.handleCallback(Handler.java:751)\n\tat android.os.Handler.dispatchMessage(Handler.java:95)\n\tat android.os.Looper.loop(Looper.java:154)\n\tat android.app.ActivityThread.main(ActivityThread.java)\n\tat java.lang.reflect.Method.invoke(Native Method)\n\tat com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)\n\tat com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)\n ] - 測試異常~~",
        "testinfo": "這是一條測試採集異常資訊"
    }
]
複製程式碼

然後啟動服務:

在Cmd下輸入:
> node app.js
複製程式碼

之後在移動端,我們就可以設定成一下程式碼來捕獲我們的異常資訊了:

...
    .setCrashServerUrl("http://你的ip:9999/api/crashs")
...

LogCenter.getLogCenter("com.dhcc.crashInfo", configuration)
                //可以自定義異常 只要實現ICollector 並傳入網路提交時所需要的key即可
                .strategy(new TestCollectInfo(), "testInfo")
                .init(this);
複製程式碼

這裡注意.strategy(new TestCollectInfo(), "testInfo")的testInfo,其實就是app.js中的req.body.testInfo和crashs.json中的testInfo欄位。

整體設計架構

Android 崩潰日誌採集元件-DhccCrashLib

原始碼就不細說了,大家可以自己去看,有什麼問題可以給我留言,謝謝你看完。

感謝

這是一份詳細清晰的 上傳Android Library到JCenter 教程

編寫 Android Library 的最佳實踐

Android程式製作自己Log日誌收集系統

Android進階:一、日誌列印和儲存策略

相關文章