You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

应用处于非后台或已被杀死状态下,如何检测呼入与呼出电话?

解决应用被杀后无法检测电话呼入呼出状态的问题

从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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 08:47:41