Android 11+设备来电检测崩溃:Permission Denial异常求助
Android 11+ 来电检测权限授予后崩溃问题
问题详情
开发来电检测功能时,在API >=30(Android 11及以上)设备上,用户授予权限后应用直接崩溃,Logcat输出如下异常信息:
FATAL EXCEPTION: main Process: com.example.callerdetecter, PID: 11623 java.lang.SecurityException: Permission Denial: not allowed to send broadcast android.intent.action.PHONE_STATE from pid=11623, uid=11219 at android.os.Parcel.createExceptionOrNull(Parcel.java:2374) at android.os.Parcel.createException(Parcel.java:2358) at android.os.Parcel.readException(Parcel.java:2341) at android.os.Parcel.readException(Parcel.java:2283) at android.app.IActivityManager$Stub$Proxy.broadcastIntentWithFeature(IActivityManager.java:5623) at android.app.ContextImpl.sendBroadcast(ContextImpl.java:1115) at android.content.ContextWrapper.sendBroadcast(ContextWrapper.java:468) at android.content.ContextWrapper.sendBroadcast(ContextWrapper.java:468) at com.example.callerdetecter.MainActivity.prepareBroadcast(MainActivity.java:73) at com.example.callerdetecter.MainActivity.lambda$onCreate$0$com-example-callerdetecter-MainActivity(MainActivity.java:33) at com.example.callerdetecter.MainActivity$$ExternalSyntheticLambda0.onClick(Unknown Source:2) at android.view.View.performClick(View.java:7503) at com.google.android.material.button.MaterialButton.performClick(MaterialButton.java:1218) at android.view.View.performClickInternal(View.java:7480) at android.view.View.access$3600(View.java:813) at android.view.View$PerformClick.run(View.java:28445) at android.os.Handler.handleCallback(Handler.java:938) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:223) at android.app.ActivityThread.main(ActivityThread.java:7950) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:603) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947) Caused by: android.os.RemoteException: Remote stack trace: at com.android.server.am.ActivityManagerService.broadcastIntentLocked(ActivityManagerService.java:16429) at com.android.server.am.ActivityManagerService.broadcastIntentLocked(ActivityManagerService.java:162 at com.android.server.am.ActivityManagerService.broadcastIntentWithFeature(ActivityManagerService.java:17116) at android.app.IActivityManager$Stub.onTransact(IActivityManager.java:2306) at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:2926)
问题原因
Android 11(API 30)及以上版本对系统广播做了严格限制:android.intent.action.PHONE_STATE是受保护的系统广播,仅系统应用有权发送。你的代码在MainActivity.prepareBroadcast方法(第73行)中调用sendBroadcast发送该广播,直接触发了SecurityException。
修复方案
1. 删除非法广播发送逻辑
找到MainActivity.java第73行的sendBroadcast调用,删除发送android.intent.action.PHONE_STATE广播的代码。
2. 正确实现来电检测(接收系统广播)
来电检测的核心是接收系统发出的通话状态广播,而非自行发送:
- 动态注册广播接收器(推荐方式,适配Android 12+的隐式广播限制):
private BroadcastReceiver callStateReceiver; @Override protected void onResume() { super.onResume(); callStateReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (TelephonyManager.ACTION_PHONE_STATE_CHANGED.equals(action)) { // 处理来电状态变化逻辑 String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE); if (TelephonyManager.EXTRA_STATE_RINGING.equals(state)) { String incomingNumber = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER); // 处理来电号码 } } } }; IntentFilter filter = new IntentFilter(TelephonyManager.ACTION_PHONE_STATE_CHANGED); registerReceiver(callStateReceiver, filter); } @Override protected void onPause() { super.onPause(); if (callStateReceiver != null) { unregisterReceiver(callStateReceiver); } } - 若使用静态注册(仅适配Android 11及以下,Android 12+需动态注册):
<receiver android:name=".CallStateReceiver"> <intent-filter> <action android:name="android.intent.action.PHONE_STATE" /> </intent-filter> </receiver>
3. 确保权限配置完整
在AndroidManifest.xml中添加权限:
<uses-permission android:name="android.permission.READ_PHONE_STATE" /> <!-- 若需读取来电号码,Android 10+还需添加以下权限 --> <uses-permission android:name="android.permission.READ_CALL_LOG" />
并在运行时请求权限:
private static final int REQUEST_PHONE_PERMISSIONS = 100; private void requestPhonePermissions() { String[] permissions = { Manifest.permission.READ_PHONE_STATE, Manifest.permission.READ_CALL_LOG }; if (ContextCompat.checkSelfPermission(this, permissions[0]) != PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(this, permissions[1]) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, permissions, REQUEST_PHONE_PERMISSIONS); } }
内容的提问来源于stack exchange,提问作者SUSMITA BHATTACHARYA
相关产品推荐
相关产品推荐

