出发点:
开源的acra crash上报库(
)的缺点有: 1. crash上报到google doc里的话,由于被墙了,所以看不到数据。 2 如果基于邮件上报crash的话,不方便统计crash崩溃率。3. acra上报的字段过多,需要过滤一些没用的字段。
目的:
当Android应用程序崩溃时,可以及时通过浏览器查看到崩溃的堆栈信息,同时后台还可以统计每天的崩溃比率,以方便应用程序的体验改进
实践过程:
- public static final ReportField[] DEFAULT_REPORT_FIELDS = { REPORT_ID, APP_VERSION_CODE, APP_VERSION_NAME,
- PACKAGE_NAME, FILE_PATH, PHONE_MODEL, BRAND, PRODUCT, ANDROID_VERSION, BUILD, TOTAL_MEM_SIZE,
- AVAILABLE_MEM_SIZE, CUSTOM_DATA, IS_SILENT, STACK_TRACE, INITIAL_CONFIGURATION, CRASH_CONFIGURATION,
- DISPLAY, USER_COMMENT, USER_EMAIL, USER_APP_START_DATE, USER_CRASH_DATE, DUMPSYS_MEMINFO, LOGCAT,
- DEVICE_ID, INSTALLATION_ID, DEVICE_FEATURES, ENVIRONMENT, SHARED_PREFERENCES, SETTINGS_SYSTEM,
- SETTINGS_SECURE };
复制代码
2.过滤一些无用的字段,当Android应用崩溃后,需要统计的数据只有11个,如下所示:
字段 说明
字段
|
说明
|
platform_id
|
1 =aPad,2=aPhone
|
android_version
|
Android版本号
|
app_version_code
|
应用的版本代码 如 9
|
app_version_name
|
应用的版本名称 如 1.2.2
|
device_id
|
设备的唯一id
|
model
|
手机/平板的模型,如BCM63
|
brand
|
Android设备牌子,如三星
|
product
|
Android产品信息
|
stack_trace
|
崩溃的堆栈信息
|
crash_date
|
崩溃的时间点
|
package_name
|
应用的包名
|
Firgure 1 上报字段
在ACRA.java中的addReportSenders函数中增加Figure1中上报字段的映射:
- if (conf.formUri() != null && !"".equals(conf.formUri())) {
-
- Map<ReportField, String> mapField = new HashMap<ReportField,String>();
- mapField.put(ReportField.ANDROID_VERSION, "android_version");
- mapField.put(ReportField.APP_VERSION_CODE, "app_version_code");
- mapField.put(ReportField.APP_VERSION_NAME, "app_version_name");
- mapField.put(ReportField.DEVICE_ID, "device_id");
- mapField.put(ReportField.PHONE_MODEL, "model");
- mapField.put(ReportField.BRAND, "brand");
- mapField.put(ReportField.PRODUCT, "product");
- mapField.put(ReportField.STACK_TRACE, "stack_trace");
- mapField.put(ReportField.USER_CRASH_DATE, "crash_date");
- mapField.put(ReportField.PACKAGE_NAME, "package_name");
- errorReporter.addReportSender(new HttpPostSender(conf.formUri(), mapField));
- return;
- }
复制代码
在HttpPostSender.java中的remap函数中修改如下:
- for (ReportField field : fields) {
- /* if (mMapping == null || mMapping.get(field) == null) {
- finalReport.put(field.toString(), report.get(field));
- } else {
- finalReport.put(mMapping.get(field), report.get(field));
- }*/
- if(mMapping!=null && mMapping.get(field) != null){
-
- finalReport.put(mMapping.get(field), report.get(field));
- }
-
- }
复制代码
finalReport.put("platform_id", ACRA.getConfig().platformId());
3. 修改完后,只需要在应用程序中增加如下几行代码,就可以实时的上报崩溃的堆栈信息(这点比ios平台方便)
- @ReportsCrashes(formKey = "", // will not be used
- platformId="1",
- formUriBasicAuthLogin = "user",
- formUriBasicAuthPassword = "password",
- formUri = "http://weiwangzi.com:8080/CrashReport/CrashServerlet")
- public class TestApplication extends Application {
-
- @Override
- public void onCreate() {
- // TODO Auto-generated method stub
- super.onCreate();
- ACRA.init(this);
- }
复制代码
4. 实现serverlet来统计上报的crash数据到数据库中
- public void doPost(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
-
- Connection conn = null;
- PreparedStatement pstmt = null;
- try{
- conn = DBUtil.getConnection();
- String platformId=request.getParameter("platform_id");
- String androidVersion=request.getParameter("android_version");
- String appVersionCode=request.getParameter("app_version_code");
- String appVersionName=request.getParameter("app_version_name");
- String deviceId=request.getParameter("device_id");
- String model=request.getParameter("model");
- String brand=request.getParameter("brand");
- String product=request.getParameter("product");
- String stackTrace=request.getParameter("stack_trace");
- String crashDate=request.getParameter("crash_date");
- String packageName=request.getParameter("package_name");
- pstmt = conn.prepareStatement("insert into report(platform_id, android_version, app_version_code,appversion_name,device_id,model,brand,product,stack_trace,crash_date,package_name) values (?, ?, ?,?,?,?,?,?,?,?,?)");
- pstmt.setString(1, platformId);
- pstmt.setString(2, androidVersion);
- pstmt.setString(3, appVersionCode);
- pstmt.setString(4, appVersionName);
- pstmt.setString(5, deviceId);
- pstmt.setString(6, model);
- pstmt.setString(7, brand);
- pstmt.setString(8, product);
- pstmt.setString(9, stackTrace);
- pstmt.setString(10, crashDate);
- pstmt.setString(11, packageName);
- pstmt.executeUpdate();
-
-
- }catch(Exception e){
- e.printStackTrace();
-
- }finally{
- if(pstmt!=null){
- try {
- pstmt.close();
- } catch (SQLException e) {
- // TODO Auto-generated catch block
- //e.printStackTrace();
- }
- }
- if(conn!=null){
- try {
- conn.close();
- } catch (SQLException e) {
- // TODO Auto-generated catch block
- //e.printStackTrace();
- }
- }
- }
-
-
- }
复制代码
实践结果:通过数据库可以导出一个excel的crash报表,或者直接通过浏览器查看