zoukankan      html  css  js  c++  java
  • Android项目实践系列(一) - 探讨ACRA

    前言


     ACRA 是 Application Crash Report for Android 的缩写,看其单词知其意安卓应用程序崩溃报告。 作为安卓应用程序开发者,相信你一定很关注自己的软件在用户实际应用过程中的用户体验、系统稳定性等信息,特别是当系统出现崩溃或者运行不正常的情况下,第一手的崩溃异常信息对提升软件的整体竞争力是相当重要的。而ACRA可以很好的帮助你得到这些宝贵的信息。

    项目实践


    准备:

      0.  Android开发环境(Eclipse + ADT + AndroidSDK)

      1. 下载最新版本的ACRA包 - v4.3.0

      2. 从官网阅读相关文档,设置好相关环境

    说明:

      ACRA 允许你的安卓应用程序通过谷歌电子表格文档(Google Docs spreadsheet),邮件(email),服务端 HTTP POST 脚本(server-side HTTP POST script)等方式来处理崩溃报告。常见的可以使用邮件和服务端 HTTP POST 脚本,以下例子我将首先使用邮件的方式发送崩溃报告,之后大概介绍下如何使用服务端 HTTP POST 脚本的方式发送崩溃报告。

    使用 Email 的方式发送崩溃报告

    项目中使用到的相关文件

    ACRATest

     |- src

       |- com.acra.mobile

         |- IOMobile.java

         |- IOReportSender.java

     |- AndroidManifest.xml

     首先看下IOMobile.java

     1 @ReportsCrashes(
     2     formKey = "",
     3     mailTo = "reports@yourdomain.com",
     4     customReportContent = { 
     5         ReportField.APP_VERSION_NAME, ReportField.APP_VERSION_CODE, 
     6         ReportField.ANDROID_VERSION, ReportField.PHONE_MODEL, 
     7         ReportField.CUSTOM_DATA, ReportField.STACK_TRACE, ReportField.LOGCAT },
     8     mode = ReportingInteractionMode.TOAST,
     9     forceCloseDialogAfterToast = false,
    10     resToastText = R.string.crash_error_report_toast_text)
    11 public class IOMobile extends Application {
    12 
    13   @Override
    14   public void onCreate() {
    15     ACRA.init(this);
    16     ErrorReporter.getInstance().setReportSender(new IOReportSender(this));
    17     super.onCreate();
    18   }
    19 
    20 }
    注意:

      1. IOMobile 继承 Application
      2. IOMobile 在 AndroidManifest.xml 文件中的配置要正确

      3. 第15行代码 ACRA.init(this),将ACRA注入到项目中

      4. 第16行代码 new IOReportSender(this),用于定制自己的ReportSender

     再来看看 IOReportSender.java

    IOReportSender.java
    public class IOReportSender implements ReportSender {

      private static final String TAG = "IOReportSender";

      private Context context = null;

      public IOReportSender(Context context) {
        this.context = context;
      }

      @Override
      public void send(CrashReportData errorContent) throws ReportSenderException {

        sendMailReport(errorContent);
      }

      private void sendMailReport(CrashReportData errorContent) throws ReportSenderException {
        new EmailIntentSender(context).send(errorContent);
      }

    }

     注意:

      1. 你可以在该类中定制异常信息,选择性发送信息。

    最后来看下AndroidManifest.xml 文件

    View Code
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
       ... 
    >

        <uses-sdk
            
    android:minSdkVersion="8"
            android:targetSdkVersion
    ="15" />

        <supports-screens
            
    android:anyDensity="true"
            android:largeScreens
    ="true"
            android:normalScreens
    ="true"
            android:resizeable
    ="true"
            android:smallScreens
    ="true" />

        <uses-permission android:name="android.permission.VIBRATE" />
        <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
        <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
        <uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
        <uses-permission android:name="android.permission.READ_PHONE_STATE" />
        <uses-permission android:name="android.permission.INTERNET" />
        <uses-permission android:name="android.permission.RECEIVE_SMS" />
        <uses-permission android:name="android.permission.RECORD_AUDIO" />
        <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
        <uses-permission android:name="android.permission.READ_CONTACTS" />
        <uses-permission android:name="android.permission.WRITE_CONTACTS" />
        <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
        <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
        <uses-permission android:name="android.permission.GET_ACCOUNTS" />
        <uses-permission android:name="android.permission.BROADCAST_STICKY" />

        <application
            
    android:name=".IOMobile"
            android:icon
    ="@drawable/ic_launcher"
            android:label
    ="@string/app_name"
            android:theme
    ="@style/AppTheme" >
        ...
        </application>

    </manifest>

    使用 server-side HTTP POST script 的方式发送崩溃报告


    这种方式发送崩溃报告,需要服务端有相应的请求响应,重要代码如下

    IOReportSender
      1 public class IOReportSender implements ReportSender {
      2 
      3   private Context mContext = null;
      4   private Map<ReportField, String> mMapping = new HashMap<ReportField, String>();
      5   private String formUri = null;
      6 
      7   public IOReportSender(Context ctx) {
      8     mContext = ctx;
      9     formUri = ctx.getString(R.string.CrashErrorReport_URL);
     10   }
     11 
     12   @Override
     13   public void send(CrashReportData errorContent) throws ReportSenderException {
     14     ErrorReporter.getInstance().putCustomData("Cookie", getCookies());
     15 
     16     if (isNetAvailable(mContext)) {
     17       doHttpReport(errorContent);
     18     } else {
     19       getMailSender().send(errorContent);
     20     }
     21   }
     22 
     23   private ReportSender getMailSender() {
     24     return new EmailIntentSender(mContext);
     25   }
     26 
     27   private void doHttpReport(CrashReportData errorContent) throws ReportSenderException {
     28     try {
     29       URL reportUrl;
     30       Map<String, String> finalReport = remap(errorContent);
     31       URL webViewUrl = new URL(App.getWebViewLoadUrl());
     32       String realFormUri = webViewUrl.getProtocol() + "://" + webViewUrl.getHost() + ((webViewUrl.getPort() == -1) ? "" : ":" + webViewUrl.getPort()) + formUri;
     33       reportUrl = new URL(realFormUri);
     34       doPost(finalReport, reportUrl, ACRA.getConfig().formUriBasicAuthLogin(), ACRA.getConfig().formUriBasicAuthPassword());
     35     } catch (Exception e) {
     36       throw new ReportSenderException("Error while sending report to Http Post Form.", e);
     37     }
     38   }
     39 
     40   private Map<String, String> remap(Map<ReportField, String> report) {
     41     Map<String, String> finalReport = new HashMap<String, String>(report.size());
     42     ReportField[] fields = ACRA.getConfig().customReportContent();
     43     if (fields.length == 0) {
     44       fields = ACRA.DEFAULT_REPORT_FIELDS;
     45     }
     46     for (ReportField field : fields) {
     47       if (mMapping == null || mMapping.get(field) == null) {
     48         finalReport.put(field.toString(), report.get(field));
     49       } else {
     50         finalReport.put(mMapping.get(field), report.get(field));
     51       }
     52     }
     53     return finalReport;
     54   }
     55 
     56   public static boolean isNetAvailable(Context mContext) {
     57     try {
     58       ConnectivityManager nInfo = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
     59       nInfo.getActiveNetworkInfo().isConnectedOrConnecting();
     60 
     61       ConnectivityManager cm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
     62       State mobile = cm.getNetworkInfo(0) != null ? cm.getNetworkInfo(0).getState() : NetworkInfo.State.DISCONNECTED;
     63       State wifi = cm.getNetworkInfo(1) != null ? cm.getNetworkInfo(1).getState() : NetworkInfo.State.DISCONNECTED;
     64       if (wifi == NetworkInfo.State.CONNECTED || wifi == NetworkInfo.State.CONNECTING) {
     65         // wifi
     66         return true;
     67       } else if (mobile == NetworkInfo.State.CONNECTED || mobile == NetworkInfo.State.CONNECTING) {
     68         // mobile
     69         return true;
     70       }
     71 
     72       else {
     73         return false;
     74       }
     75     } catch (Exception e) {
     76       return false;
     77     }
     78   }
     79 
     80   /**
     81    * Send an HTTP(s) request with POST parameters.
     82    * 
     83    * @param parameters
     84    *          parameters
     85    * @param url
     86    *          url
     87    * @param login
     88    *          login
     89    * @param password
     90    *          password
     91    * @throws IOException
     92    *           IOException
     93    */
     94   private void doPost(Map<?, ?> parameters, URL url, String login, String password) throws IOException {
     95 
     96     // Construct data
     97     StringBuilder dataBfr = new StringBuilder();
     98     for (Object key : parameters.keySet()) {
     99       if (dataBfr.length() != 0) {
    100         dataBfr.append('&');
    101       }
    102       Object value = parameters.get(key);
    103       if (value == null) {
    104         value = "";
    105       }
    106       dataBfr.append(URLEncoder.encode(key.toString(), "UTF-8")).append('=').append(URLEncoder.encode(value.toString(), "UTF-8"));
    107     }
    108 
    109     LogHttpRequest req = new LogHttpRequest(isNull(login) ? null : login, isNull(password) ? null : password);
    110     String cookie = getCookies();
    111     req.sendPost(url.toString(), dataBfr.toString(), cookie);
    112   }
    113 
    114   private boolean isNull(String aString) {
    115     return aString == null || aString == ACRA.NULL_VALUE;
    116   }
    117 
    118   private String getCookies() {
    119     String cookie = null;
    120     try {
    121       CookieSyncManager.getInstance().sync();
    122       cookie = CookieManager.getInstance().getCookie(App.getWebViewLoadUrl());
    123     } catch (Exception e) {
    124     }
    125     return cookie;
    126   }
    127 }

    如果需要帮助,可以联系我进行进一步的探讨。

     文章参考链接


     ACRA官方网站: http://code.google.com/p/acra/

    作者信息:

    QQ: 1321518080

    Email: hucaijun520.ok@163.com
  • 相关阅读:
    超棒的微软Metro风格Logo设计
    免费资源:Polaris UI套件 + Linecons图标集(AI, PDF, PNG, PSD, SVG)
    11套免费的wordpress模板主题
    SASS(Syntactically Awesome Stylesheets Sass)绝对新手入门教程
    分享网页加载速度优化的一些技巧?
    帮助开发者快速创建响应式布局的Boilerplate Responsive Boilerplate
    免费素材: Retina Glyph图标集 (包含100个AI & PNG格式的图标)
    响应式的前端框架 Groundwork
    帮助你搜索免费矢量,图标和PSD的搜索引擎 Freepik
    Toolbar.Js 帮助你创建提示风格的工具条jQuery插件
  • 原文地址:https://www.cnblogs.com/youngC/p/2718765.html
Copyright © 2011-2022 走看看