应用处于非后台或已被杀死状态下,如何检测呼入与呼出电话?
解决应用被杀后无法检测电话呼入呼出状态的问题
从Android 8.0(API 26)开始,系统对静态注册的隐式广播做了严格限制,TelephonyManager.ACTION_PHONE_STATE_CHANGED不在允许静态注册的广播列表中,所以应用被杀后,你之前的静态BroadcastReceiver无法触发。下面是可行的解决方案:
方案一:前台服务 + TelephonyManager 监听器
这是最可靠的方案,前台服务拥有较高的进程优先级,不容易被系统回收,且可以直接通过PhoneStateListener监听电话状态变化,无需依赖广播。
步骤1:实现前台服务
创建一个继承自Service的类,在其中注册电话状态监听器,并启动前台服务:
public class CallMonitorService extends Service { private TelephonyManager telephonyManager; private PhoneStateListener phoneStateListener; private static final int NOTIFICATION_ID = 1001; private static final String CHANNEL_ID = "call_monitor_channel"; @Override public void onCreate() { super.onCreate(); // 初始化TelephonyManager telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE); // 构建电话状态监听器 phoneStateListener = new PhoneStateListener() { @Override public void onCallStateChanged(int state, String phoneNumber) { super.onCallStateChanged(state, phoneNumber); switch (state) { case TelephonyManager.CALL_STATE_RINGING: // 来电响铃,Android 10+需READ_CALL_LOG权限才能获取phoneNumber Log.d("CallMonitor", "来电号码: " + (phoneNumber == null ? "无法获取" : phoneNumber)); break; case TelephonyManager.CALL_STATE_OFFHOOK: // 通话中(接听或呼出) Log.d("CallMonitor", "通话已接通"); break; case TelephonyManager.CALL_STATE_IDLE: // 通话结束或无活跃通话 Log.d("CallMonitor", "通话结束/无通话"); break; } } }; // 注册监听器,监听通话状态 telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE); // 启动前台服务,必须显示通知 startForeground(NOTIFICATION_ID, createNotification()); } private Notification createNotification() { NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID) .setSmallIcon(R.drawable.ic_notification) // 替换为你的通知图标 .setContentTitle("通话监控") .setContentText("正在监控通话状态") .setPriority(NotificationCompat.PRIORITY_LOW); // Android 8.0+需要创建通知渠道 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { NotificationChannel channel = new NotificationChannel(CHANNEL_ID, "通话监控渠道", NotificationManager.IMPORTANCE_LOW); NotificationManager notificationManager = getSystemService(NotificationManager.class); notificationManager.createNotificationChannel(channel); } return builder.build(); } @Override public void onDestroy() { super.onDestroy(); // 取消监听器注册,避免内存泄漏 if (telephonyManager != null && phoneStateListener != null) { telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_NONE); } } @Nullable @Override public IBinder onBind(Intent intent) { return null; } }
步骤2:在Manifest中注册服务
<manifest ...> <!-- 申请必要权限 --> <uses-permission android:name="android.permission.READ_PHONE_STATE" /> <uses-permission android:name="android.permission.READ_CALL_LOG" /> <!-- Android 10+获取号码需要 --> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> <!-- Android 13+需要 --> <application ...> <service android:name=".CallMonitorService" android:foregroundServiceType="phoneCall" /> <!-- 声明前台服务类型为通话相关 --> </application> </manifest>
步骤3:启动前台服务
在应用启动时(比如主Activity的onCreate)启动服务,注意先申请权限:
public class MainActivity extends AppCompatActivity { private static final int PERMISSION_REQUEST_CODE = 100; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 检查并申请权限 String[] permissions = { Manifest.permission.READ_PHONE_STATE, Manifest.permission.READ_CALL_LOG, Manifest.permission.POST_NOTIFICATIONS }; if (!hasPermissions(permissions)) { ActivityCompat.requestPermissions(this, permissions, PERMISSION_REQUEST_CODE); } else { startCallMonitorService(); } } private boolean hasPermissions(String[] permissions) { for (String permission : permissions) { if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) { return false; } } return true; } private void startCallMonitorService() { Intent serviceIntent = new Intent(this, CallMonitorService.class); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { startForegroundService(serviceIntent); } else { startService(serviceIntent); } } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == PERMISSION_REQUEST_CODE) { boolean allGranted = true; for (int result : grantResults) { if (result != PackageManager.PERMISSION_GRANTED) { allGranted = false; break; } } if (allGranted) { startCallMonitorService(); } else { // 权限被拒绝,提示用户开启 Toast.makeText(this, "需要权限才能监控通话状态", Toast.LENGTH_SHORT).show(); } } } }
方案二:动态注册广播 + 前台服务
如果坚持使用广播,可以在前台服务中动态注册BroadcastReceiver,因为动态注册的广播在进程存活时有效,前台服务能维持进程存活。不过这种方式不如直接用PhoneStateListener高效:
// 在CallMonitorService的onCreate中添加 BroadcastReceiver callReceiver = new CallStateReceiver(); IntentFilter filter = new IntentFilter(TelephonyManager.ACTION_PHONE_STATE_CHANGED); registerReceiver(callReceiver, filter); // 在onDestroy中取消注册 unregisterReceiver(callReceiver);
关键注意事项
- 国产ROM限制:部分国产安卓系统(如小米、华为)有额外的后台管控,需要用户手动给应用开启「自启动权限」「后台运行权限」,否则服务可能被强制杀死。
- 前台服务通知:Android要求前台服务必须显示通知,不能隐藏,否则会触发ANR或被系统停止。
- 权限适配:Android版本不同,所需权限有差异,务必按API等级适配权限申请逻辑。
内容的提问来源于stack exchange,提问作者sreejith
相关产品推荐
相关产品推荐

