调用NfcAdapter.enableReaderMode出现PACKAGE_USAGE_STATS权限崩溃如何解决
NFC enableReaderMode触发PACKAGE_USAGE_STATS权限崩溃解决方案
问题根因
该异常出现在Android 11(API 30)及以上版本的部分ROM中,NFC系统服务在执行setReaderMode逻辑时,内部调用了isUidActive接口校验应用状态,该接口强制要求android.permission.PACKAGE_USAGE_STATS权限,和NFC本身的权限无关。
权限适配方案
- 先在AndroidManifest.xml中新增权限声明:
<!-- 适配Android11+部分ROM调用NFC reader模式的额外权限要求 --> <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
- 该权限属于特殊权限,无法通过普通动态权限申请流程获取,需要先校验权限是否已授予,未授予时引导用户到「应用使用情况访问权限」设置页手动开启:
private static final int REQUEST_CODE_USAGE_PERM = 1001; private boolean checkUsageStatsPermission(Context context) { AppOpsManager appOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); int opMode = appOpsManager.checkOpNoThrow( AppOpsManager.OPSTR_GET_USAGE_STATS, Process.myUid(), context.getPackageName() ); return opMode == AppOpsManager.MODE_ALLOWED; } // 未授权时跳转设置页 if (!checkUsageStatsPermission(this)) { Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS); intent.setData(Uri.parse("package:" + getPackageName())); startActivityForResult(intent, REQUEST_CODE_USAGE_PERM); }
调用前前置校验规则
每次在onResume中调用enableReaderMode前,必须依次做以下校验:
- 校验设备是否支持NFC:
NfcAdapter.getDefaultAdapter(context)返回非空才继续 - 校验NFC功能已开启:
nfcAdapter.isEnabled()返回true才继续 - 校验Activity未处于销毁/finishing状态:
!isFinishing() && !isDestroyed()返回true才继续 - 对调用逻辑做异常兜底捕获,避免极端场景崩溃:
try { nfcAdapter.enableReaderMode(this, yourReaderCallback, NfcAdapter.FLAG_READER_NFC_A | NfcAdapter.FLAG_READER_SKIP_NDEF_CHECK, null); } catch (SecurityException e) { // 权限不足时做降级处理,比如提示用户开启对应权限后重试 }
补充优化建议
- 如果你应用的minSdkVersion >=34,可先在对应版本ROM上测试是否还触发该异常,部分厂商和AOSP已经在Android14中修复了这个不必要的权限依赖,确认修复后可以给权限加上
android:maxSdkVersion="33"属性减少不必要的权限申请 - 如果应用场景允许,也可以在用户未授权PACKAGE_USAGE_STATS权限时,降级使用
enableForegroundDispatch方案实现NFC卡读取,不需要额外权限
内容的提问来源于stack exchange,提问作者Putra Nugraha
相关产品推荐
相关产品推荐

