AppWidgetProvider的onReceive收到第三方数据引发崩溃的原因及解决方案
问题原因
- 你的
CalendarAppWidgetProvider设置了android:exported="true",这是桌面部件的必要配置,用于接收系统的部件更新广播,但同时也意味着任何第三方应用都可以向该组件发送任意Intent。 - 本次崩溃来自其他应用发送的异常Intent:
id.dana.model.CurrencyAmountModel是印尼支付应用DANA的内部类,该应用存在发送广播时未正确指定接收方、或者错误携带自身私有Parcelable类的问题,导致Intent被发送到了你的组件。 - 你在自定义的
onReceive方法中调用了super.onReceive,父类AppWidgetProvider的实现会尝试读取Intent携带的Bundle数据,系统解析Bundle时会自动反序列化其中的Parcelable对象,你的应用不存在对应类就会抛出BadParcelableException。
修复方案
- 优先过滤合法Action:你只需要处理自己声明的、以及桌面部件相关的系统Action(比如
AppWidgetManager.ACTION_APPWIDGET_UPDATE、ACTION_APPWIDGET_DELETED等你实际用到的Action),其余未知Action直接返回,不要调用super.onReceive,从根源上避免解析非法数据。
示例代码:
@Override public void onReceive(Context context, Intent intent) { final String action = intent.getAction(); // 只处理你需要的合法Action if (!TextUtils.equals(action, AppWidgetManager.ACTION_APPWIDGET_UPDATE) && !TextUtils.equals(action, "你的自定义Action1") && !TextUtils.equals(action, "你的自定义Action2")) { // 陌生Action直接丢弃,不做后续处理 return; } // 原有逻辑 ... super.onReceive(context, intent); }
- 增加异常捕获兜底:如果需要处理的Action里也可能携带非法数据,可以在调用
super.onReceive的逻辑外套一层异常捕获,拦截Parcel相关的异常:
try { super.onReceive(context, intent); } catch (BadParcelableException | ClassNotFoundException e) { // 忽略外部非法数据导致的异常,不做额外处理 }
- 安全处理Bundle(可选):如果确实需要读取外部Intent携带的Bundle数据,可以先为Bundle设置你应用的类加载器,避免系统使用默认加载器找不到类的问题:
Bundle extras = intent.getExtras(); if (extras != null) { extras.setClassLoader(getClass().getClassLoader()); }
内容的提问来源于stack exchange,提问作者Cheok Yan Cheng
相关产品推荐
相关产品推荐

