異常崩潰怎麼辦?
關於異常崩潰是每個App都要面對的,平時開發還好,在除錯狀態下遇到的問題,可以通過LogCat列印的異常日誌資訊進行分析處理,但是一旦App上線後,大量使用者安裝了你的應用,每個使用者的手機大小、感測器、SDK版本都不盡相同,可能你在測試機上跑的穩穩的應用,到了客戶手機上就會出現一些莫名其妙的異常,如果只是一些記憶體洩露的問題可能還好,最起碼不會瞬間崩潰,但是如果遇到一些可以導致手機崩潰Bug的話,你讓出問題的使用者來複現Bug是不可能的,所以,全域性異常捕獲就顯得很重要了,而DhccCrashLib就是一個全域性異常捕獲的元件。
DhccCrashLib怎麼用?
使用方法還是比較簡單的,首先在專案的根目錄下的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,建議你先看這篇:
之後將你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欄位。
整體設計架構
原始碼就不細說了,大家可以自己去看,有什麼問題可以給我留言,謝謝你看完。