在Android应用开发的过程中,有时候我们总觉得自己写的代码天衣无缝,根本不会有bug。。。(一切都是幻觉),但在后期的版本迭代中总会让你猝不及防的报各种crash,我们称之为“崩溃”。出错的原因一般都千奇百怪。
在《结合源码深入理解Android Crash处理流程》中可知:当发生crash时,系统会kill掉正在执行的程序,并弹一个crash提示框给用户去选择。
在继续写之前,先说下前提:我是做ROM开发的,在公司负责一个“应用管控”的apk,主要作用就是对系统中的应用程序一些行为进行管控,这个apk没有一个界面显示,并且有persistent属性。如果对persistent属性不是太了解的朋友,可以看下我的《谈谈Android中的persistent属性》一文。由于前不久对它进行了重构,现在处于迭代的阶段。但最近有用户报应用管控apk的crash提示框,如下所示:
报crash弹框对用户体验不好,有个别用户直接报到客服那边,然后我总监和经理都知道了,有点尴尬。。。因为我的apk没有界面显示,用户根本不会去进行交互操作,且具有persistent属性。然后还报crash弹框,这确实有点说不过去!所以我的修改宗旨是:apk你可以crash,当你不要给我弹框,然后将crash信息上传到后台就行了。
结合上面的报错场景和修改宗旨,下面我将提供两种屏蔽crash弹框的方案。
1. 从Framework层去修改
我是做ROM开发的,有直接修改framework层的代码。从《结合源码深入理解Android Crash处理流程》中可知:AMS.crashApplication方法中会通过mUiHandler发送message,且消息的msg.what=SHOW_ERROR_MSG,然后交由mUiHandler中的handleMessage去处理。这里面会创建crash提示框:
final class UiHandler extends Handler {
public UiHandler() {
super(com.android.server.UiThread.get().getLooper(), null, true);
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case SHOW_ERROR_MSG: {
HashMap<String, Object> data = (HashMap<String, Object>) msg.obj;
boolean showBackground = Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0;
synchronized (ActivityManagerService.this) {
ProcessRecord proc = (ProcessRecord)data.get("app");
AppErrorResult res = (AppErrorResult) data.get("result");
...省略...
if (mShowDialogs && !mSleeping && !mShuttingDown) {
//创建crash提示框,等待用户选择,等待时间为5分钟
Dialog d = new AppErrorDialog(mContext,
ActivityManagerService.this, res, proc);
d.show();
proc.crashDialog = d;
}
}
ensureBootCompleted();
} break;
...省略...
}
}
修改思路:
在上面有ProcessRecord对象,那我们就可以拿到app对应的processName,那我们就可以自定义一个类似于黑名单的字符串数组,将不要显示crash弹框的进程名(一般都是包名)写在数组中,如下所示:
private String[] dontShowDialogsP = {"com.pptv.terminalmanager","com.pptv.launcher"};
然后我们在显示crash Dialog前,判断要报错的进程名是否在上面定义的字符串数组中?
* 如果进程名在定义的字