targetSdkVersion 31下TelephonyManager相关SecurityException问题求助
Android 12(targetSdkVersion 31)TelephonyManager 权限崩溃解决方案
问题场景
应用将targetSdkVersion设置为31后,出现以下SecurityException崩溃:
java.lang.SecurityException: listen at android.os.Parcel.createExceptionOrNull(Parcel.java:3023) at android.os.Parcel.createException(Parcel.java:3007) at android.os.Parcel.readException(Parcel.java:2990) at android.os.Parcel.readException(Parcel.java:2932) at com.android.internal.telephony.ITelephonyRegistry$Stub$Proxy.listenWithEventList(ITelephonyRegistry.java:1074) at android.telephony.TelephonyRegistryManager.listenFromListener(TelephonyRegistryManager.java:265) at android.telephony.TelephonyManager.listen(TelephonyManager.java:7210) at kr.co.test.test.zn.run(EBZRNNoneVideoCallActivity.java:1206) at android.os.Handler.handleCallback(Handler.java:942) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loopOnce(Looper.java:226) at android.os.Looper.loop(Looper.java:313) at android.app.ActivityThread.main(ActivityThread.java:8741) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:571) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1067) Caused by: android.os.RemoteException: Remote stack trace: at com.android.internal.telephony.TelephonyPermissions.enforceCarrierPrivilege(TelephonyPermissions.java:676) at com.android.internal.telephony.TelephonyPermissions.checkReadPhoneState(TelephonyPermissions.java:169) at com.android.internal.telephony.TelephonyPermissions.checkCallingOrSelfReadPhoneState(TelephonyPermissions.java:94) at com.android.server.TelephonyRegistry.checkListenerPermission(TelephonyRegistry.java:3424) at com.android.server.TelephonyRegistry.listen(TelephonyRegistry.java:1090)
按官方文档提示改用registerTelephonyCallback方法后,未授权调用仍触发SecurityException,且存在Android 11+权限适配混淆(误以为READ_PHONE_NUMBERS可替代READ_PHONE_STATE)。
解决方案
1. 纠正权限认知
registerTelephonyCallback用于监听电话状态(来电、信号等)时,Android 11+仍需READ_PHONE_STATE权限,READ_PHONE_NUMBERS仅用于读取电话号码,无法替代前者完成状态监听。
2. 正确配置与申请权限
- Manifest声明:在
AndroidManifest.xml中添加权限声明:<uses-permission android:name="android.permission.READ_PHONE_STATE" /> - 权限申请逻辑:Android 11+(API30)起,
READ_PHONE_STATE属于受保护权限,无法通过常规弹窗请求,需引导用户到应用设置页手动开启:private static final int REQ_CODE_PHONE_STATE = 1001; private void checkPhoneStatePermission() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { if (checkSelfPermission(Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) { // 引导到应用设置页 Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); Uri uri = Uri.fromParts("package", getPackageName(), null); intent.setData(uri); startActivity(intent); } } else { // Android 10及以下可正常请求权限 requestPermissions(new String[]{Manifest.permission.READ_PHONE_STATE}, REQ_CODE_PHONE_STATE); } }
3. 调用前强制校验权限
在调用registerTelephonyCallback前必须检查权限状态,未授权时禁止调用:
TelephonyManager telephonyManager = getSystemService(TelephonyManager.class); Executor mainExecutor = ContextCompat.getMainExecutor(this); TelephonyCallback telephonyCallback = new TelephonyCallback() { @Override public void onCallStateChanged(int state) { super.onCallStateChanged(state); // 处理电话状态变化逻辑 } }; // 权限校验后再调用 if (checkSelfPermission(Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED) { telephonyManager.registerTelephonyCallback(mainExecutor, telephonyCallback); } else { // 提示用户授权或处理无权限场景 }
4. 适配TelephonyCallback的正确实现
根据业务需求选择对应监听接口,比如监听来电状态使用TelephonyCallback.CallStateListener,避免不必要的权限申请:
TelephonyCallback callStateCallback = new TelephonyCallback.CallStateListener() { @Override public void onCallStateChanged(int state) { switch (state) { case TelephonyManager.CALL_STATE_RINGING: // 来电响铃逻辑 break; case TelephonyManager.CALL_STATE_OFFHOOK: // 通话中逻辑 break; case TelephonyManager.CALL_STATE_IDLE: // 空闲状态逻辑 break; } } };
内容的提问来源于stack exchange,提问作者왕감자
相关产品推荐
相关产品推荐

