Android DemoAndroid OtherAndroid开发

Android捕捉崩溃情况推送到钉钉

2018-05-06  本文已影响1506人  在寻找雪见的景天

前言

开发过程中,发测了,如果遇到崩溃情况,想记录下来有哪几个方法?一、用bugly,设置是开发模式,崩溃了会马上上报。二、收集崩溃信息发送到邮箱。那现在再试一种方式,就是推送崩溃信息到钉钉。

钉钉机器人了解

我们参考钉钉的开发文档:自定义机器人 ,先要登录pc版或者网页版的钉钉,然后在聊天群页面增加一个机器人:




记住这个hook地址,这个其实就是相当于一个请求接口。

开始使用机器人

获取到Webhook地址后,用户可以使用任何方式向这个地址发起HTTP POST 请求,即可实现给该群组发送消息。注意,发起POST请求时,必须将字符集编码设置成UTF-8。

当前自定义机器人支持文本(text)、连接(link)、markdown(markdown)三种消息类型,大家可以根据自己的使用场景选择合适的消息类型,达到最好的展示样式。具体的消息类型参考下一节内容。

自定义机器人发送消息时,可以通过手机号码指定“被@人列表”。在“被@人列表”里面的人员,在收到该消息时,会有@消息提醒(免打扰会话仍然通知提醒,首屏出现“有人@你”)

比如,我想推送文本信息:

{
     "msgtype": "text",
     "text": {
         "content": "应用崩溃了,  @1825718XXXX  快去看看是什么回事"
     },
     "at": {
         "atMobiles": [
             "1825718XXXX"
         ], 
         "isAtAll": false
     }
 }

我们请求一个接口,接口地址就是上面的hook地址,请求方式为post,然后设置post的内容为上面这段。那钉钉里面就会收到信息。

崩溃信息收集

知道钉钉的推送原理后,其实我们只要把崩溃信息保存下来,然后请求一下,就可以把崩溃信息推送到钉钉了。我们在网上找到一个收集异常信息的类:

public class CrashHandler implements Thread.UncaughtExceptionHandler {
    //系统默认的异常处理器
    private Thread.UncaughtExceptionHandler defaultCrashHandler;
    private static CrashHandler crashHandler = new CrashHandler();
    private Context mContext;
    //私有化构造函数
    private CrashHandler() {
    }
    //获取实例
    public static CrashHandler getInstance() {
        return crashHandler;
    }
    public void init(Context context) {
        if (L.Debug) {
            mContext = context;
            defaultCrashHandler = Thread.getDefaultUncaughtExceptionHandler();
            //设置系统的默认异常处理器
            Thread.setDefaultUncaughtExceptionHandler(this);
        }
    }
    @Override
    public void uncaughtException(Thread thread, Throwable throwable) {
        //把错误信息保存在sp中,然后在下次进入页面的时候再上传错误信息
        saveErrorInfo(throwable);
        if (defaultCrashHandler != null) {
            //如果在自定义异常处理器之前,系统有自己的默认异常处理器的话,调用它来处理异常信息
            defaultCrashHandler.uncaughtException(thread, throwable);
        } else {
            android.os.Process.killProcess(android.os.Process.myPid());
            System.exit(0);
        }
    }
    public void sendError() {
        if (L.Debug) {
            final SharedPreferences sp = mContext.getSharedPreferences("errorInfo", Context.MODE_PRIVATE);
            String data = sp.getString("data", "");
            if (!data.equals("")) {
                JSONObject jsonObject = new JSONObject();
                try {
                    jsonObject.put("msgtype", "text");
                    JSONObject jsonObject1 = new JSONObject();
                    jsonObject1.put("content", data);
                    jsonObject.put("text", jsonObject1.toString());
                    MMCHttp.<String>post("https://oapi.dingtalk.com/robot/send?access_token=a02fce3ced263e2272dc93867e56394dfe3bf4b44104b6e06b660953cc5a").upJson(jsonObject.toString()).execute(new StringCallback() {
                        @Override
                        public void onSuccess(Response<String> response) {
                            Log.i("---", response.body());
                            sp.edit().putString("data", "").commit();
                        }
                        @Override
                        public void onError(Response<String> response) {
                            super.onError(response);
                            Log.i("---", response.body());
                        }
                    });
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    private void saveErrorInfo(Throwable throwable) {
        StringBuffer stringBuffer = new StringBuffer();
        stringBuffer.append(getAppInfo(mContext));
        stringBuffer.append("崩溃时间:").append(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())).append("\n");
        stringBuffer.append("手机系统:").append(Build.VERSION.RELEASE).append("\n");
        stringBuffer.append("手机型号:").append(Build.MODEL).append("\n");
        stringBuffer.append("崩溃信息:").append(throwable.getMessage());
        SharedPreferences sp = mContext.getSharedPreferences("errorInfo", Context.MODE_PRIVATE);
        sp.edit().putString("data", stringBuffer.toString()).commit();
    }
    /**
     * 获取应用程序信息
     */
    public String getAppInfo(Context context) {
        try {
            PackageManager packageManager = context.getPackageManager();
            PackageInfo packageInfo = packageManager.getPackageInfo(context.getPackageName(), 0);
            return "应用包名:" + packageInfo.packageName + "\n应用版本:" + packageInfo.versionName + "\n";
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
    }
}

就这样完成了推送应用崩溃信息到钉钉群的功能。

拓展

可以利用bugly的异常报告功能,直接推送崩溃异常情况到钉钉。bugly那里可以设置,每天早上9点,会推送一段json信息到你的接口。但这个接口,你要处理一下,不能直接填上面hook的地址,因为bugly推送的json,和上面钉钉发送的json不是一样的。所以,你需要写一个php,例如:

<?php

try {
 $response = $HTTP_RAW_POST_DATA ;  
 $objContent = json_decode($response,true);
 
 $appName =  $objContent['eventContent']['appName'];
 $num = count($objContent['eventContent']["datas"]);

 $crashCount = $objContent['eventContent']["datas"][$num-1]["crashCount"];
 $crashUser = $objContent['eventContent']["datas"][$num-1]["crashUser"];
 $accessUser = $objContent['eventContent']["datas"][$num-1]["accessUser"];
 $version = $objContent['eventContent']["datas"][$num-1]["version"];

 $crashCount2 = 0;
 $crashUser2 = 0;
 $accessUser2 = 0;
 $version2 = "";

 if($num>1){
    $crashCount2 = $objContent['eventContent']["datas"][$num-2]["crashCount"];
    $crashUser2 = $objContent['eventContent']["datas"][$num-2]["crashUser"];
    $accessUser2 = $objContent['eventContent']["datas"][$num-2]["accessUser"];
    $version2 = $objContent['eventContent']["datas"][$num-2]["version"];
 }

 if($appName!=""){
    $webhook = "https://oapi.dingtalk.com/robot/send?access_token=a02fce3ced263e2272dc93867e56394dfe3bf4b44104b6e06b660953cc5";
    if($accessUser>$accessUser2){
        $message="应用:".$appName.",版本:".$version.",联网用户:".$accessUser.",崩溃用户:".$crashUser.",崩溃数:".$crashCount;
    }else{
        $message="应用:".$appName.",版本:".$version2.",联网用户:".$accessUser2.",崩溃用户:".$crashUser2.",崩溃数:".$crashCount2;
    }
    
    $data = array ('msgtype' => 'text','text' => array ('content' => $message));
    $data_string = json_encode($data);

    $ch = curl_init();  
    curl_setopt($ch, CURLOPT_URL, $webhook);
    curl_setopt($ch, CURLOPT_POST, 1); 
    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5); 
    curl_setopt($ch, CURLOPT_HTTPHEADER, array ('Content-Type: application/json;charset=utf-8'));
    curl_setopt($ch, CURLOPT_POSTFIELDS, $data_string);  
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);  
    // 线下环境不用开启curl证书验证, 未调通情况可尝试添加该代码
    curl_setopt ($ch, CURLOPT_SSL_VERIFYHOST, 0); 
    curl_setopt ($ch, CURLOPT_SSL_VERIFYPEER, 0);
    $data = curl_exec($ch);
    curl_close($ch);  
    echo $data;
 }else{
    echo "请输入正确的内容";
 }

} catch (Exception $e) {
    echo $e;
}

这个php其实就是做了一个中转的功能,把bugly传过来的数据,进行解析,然后整理出你想发到钉钉群的内容,再调用钉钉那个接口,把数据推送到钉钉。整个流程大概就这样。

上一篇下一篇

猜你喜欢

热点阅读