使用通知监听服务从StatusBarNotification获取应用名出现NameNotFoundException
问题原因
抛出NameNotFoundException的核心原因如下:
- Android 11(API 30)及以上版本引入了包可见性过滤机制,默认情况下应用仅能查询系统预置应用、自身以及manifest中显式声明可访问的应用,未配置对应权限时查询第三方应用信息会触发该异常
- 部分通知来自工作 profile、多用户空间下的应用,当前用户空间无权限查询对应包的信息
- 少数系统临时通知携带的包名本身无效,不存在对应应用
修复步骤
1. 配置AndroidManifest.xml
适配包可见性要求,添加对应权限:
<!-- 适配Android 11+包可见性要求,通知管理类应用可申请该权限,上架谷歌商店需符合对应政策说明用途 --> <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
如果你明确知道需要监听的应用范围,不想申请全量查询权限,也可以用queries标签逐一声明包名,仅适配声明的应用:
<queries> <package android:name="com.tencent.mm" /> <package android:name="com.tencent.mobileqq" /> <!-- 其余需要监听的应用包名逐一添加 --> </queries>
2. 优化代码查询逻辑
调整查询参数适配多用户场景,优化兜底逻辑:
public class NotificationListener extends NotificationListenerService { private final ArrayList<Integer> postedIds = new ArrayList<>(); @Override public void onNotificationPosted(StatusBarNotification sbn) { ArrayList<Integer> connectedThreadNotifications = new ArrayList<>(); for (BluetoothConnectionThread bluetoothConnectionThread : Utils.getCurrentlyRunningThreads()) { connectedThreadNotifications.add(bluetoothConnectionThread.getNotificationID()); } if (sbn.getId() != 800 && !connectedThreadNotifications.contains(sbn.getId())) { if (!postedIds.contains(sbn.getId())) { postedIds.add(sbn.getId()); HashMap<String, Object> notification = new HashMap<>(); String pkgName = sbn.getPackageName(); if (pkgName == null || pkgName.isEmpty()) { notification.put("appName", "Unknown"); } else { try { PackageManager packageManager = getPackageManager(); // 添加MATCH_ANY_USER标志,适配多用户/工作profile场景 ApplicationInfo appInfo = packageManager.getApplicationInfo(pkgName, PackageManager.MATCH_ANY_USER); String appName = packageManager.getApplicationLabel(appInfo).toString(); notification.put("appName", appName); } catch (PackageManager.NameNotFoundException e) { // 兜底逻辑:查不到应用名时直接展示包名,比Unknown更具参考性 notification.put("appName", pkgName); } } notification.put("title", sbn.getNotification().extras.get("android.title")); notification.put("subText", sbn.getNotification().extras.get("android.subText")); notification.put("text", sbn.getNotification().extras.get("android.text")); notification.put("infoText", sbn.getNotification().extras.get("android.infoText")); Gson gson = new Gson(); System.out.println(gson.toJson(notification)); } } } @Override public void onNotificationRemoved(StatusBarNotification sbn) { if (postedIds.contains(sbn.getId())) { postedIds.remove((Integer) sbn.getId()); } } public void broadcastNotification() { } }
注意事项
使用通知监听服务前需要引导用户手动在系统设置的「通知使用权」页面开启对应权限,否则无法正常接收系统通知回调。
内容的提问来源于stack exchange,提问作者Chris Ray
相关产品推荐
相关产品推荐

