Android 8及以上开机后Broadcast Receiver失效及通话广播问题求助
兄弟,这个问题我太熟了——Android 8.0(API 26)引入的后台执行限制就是元凶!
为什么旧版正常,Android 8+就不行了?
从Android O开始,谷歌为了砍后台耗电,对隐式广播下了狠手。NEW_OUTGOING_CALL刚好属于被限制的隐式广播范畴,不在系统允许的例外列表里。这就导致:
- 你在Manifest里注册的静态BroadcastReceiver,只有当应用处于前台状态或者持有前台服务时,才能收到广播
- 设备重启后,应用没启动,静态接收器直接躺平,完全收不到任何广播
- 应用启动后能工作几小时,只是因为那段时间应用进程还活着,系统暂时放行,等进程被回收就彻底失效了
怎么解决?给你三个靠谱方案
方案1:改用动态注册BroadcastReceiver
把接收器从Manifest里移出来,在应用启动时(比如主Activity的onCreate,或者Application的onCreate)动态注册。只要应用进程活着,就能正常监听。
示例代码:
// 定义接收器 private BroadcastReceiver outgoingCallReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { // 这里处理你的通话记录逻辑 String phoneNumber = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER); // 比如存到数据库或者上传服务器... } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 动态注册 IntentFilter filter = new IntentFilter(Intent.ACTION_NEW_OUTGOING_CALL); registerReceiver(outgoingCallReceiver, filter); } @Override protected void onDestroy() { super.onDestroy(); // 一定要注销,不然会内存泄漏! unregisterReceiver(outgoingCallReceiver); }
缺点:如果应用进程被系统杀死,接收器就失效了,适合对后台持续监听要求不高的场景。
方案2:用前台服务保活+动态注册
如果需要后台持续监听,就得搞个前台服务——前台服务的进程优先级高,系统不会轻易杀它。
步骤很简单:
- 写个前台服务,在服务里动态注册接收器
- 服务启动时显示一个低优先级通知(Android O+强制要求)
- 让服务能在应用启动时自动启动(比如用户打开APP后启动,或者通过
BOOT_COMPLETED广播,但Android O+需要先唤醒应用一次)
示例服务代码片段:
public class CallMonitorService extends Service { private BroadcastReceiver callReceiver; @Override public void onCreate() { super.onCreate(); // 注册接收器 callReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { // 处理通话逻辑 } }; IntentFilter filter = new IntentFilter(Intent.ACTION_NEW_OUTGOING_CALL); registerReceiver(callReceiver, filter); // Android O+必须启动前台服务,显示通知 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { // 创建通知渠道 NotificationChannel channel = new NotificationChannel("call_monitor", "通话监控", NotificationManager.IMPORTANCE_LOW); NotificationManager manager = getSystemService(NotificationManager.class); manager.createNotificationChannel(channel); // 构建通知 Notification notification = new NotificationCompat.Builder(this, "call_monitor") .setContentTitle("通话监控中") .setSmallIcon(R.drawable.ic_notify) .build(); startForeground(1, notification); } } @Override public int onStartCommand(Intent intent, int flags, int startId) { return START_STICKY; // 服务被杀死后,系统会尝试重启 } @Override public void onDestroy() { super.onDestroy(); unregisterReceiver(callReceiver); } @Nullable @Override public IBinder onBind(Intent intent) { return null; } }
然后在Manifest里注册服务(Android 12+要加前台服务类型):
<service android:name=".CallMonitorService" android:foregroundServiceType="phoneCall" />
缺点:会在通知栏显示一个常驻通知,要提前跟用户说明用途,避免被当成流氓APP。
方案3:AccessibilityService(适合特殊场景)
如果用户能接受开启辅助权限,用辅助功能服务也是个好办法——AccessibilityService的进程优先级极高,几乎不会被系统杀死。不过这个需要用户手动去设置里开启权限,适合对后台监听要求极高的场景。
最后提醒
- 动态注册的接收器一定要在合适的时机注销,别搞内存泄漏
- 前台服务的通知尽量做的低调点,比如用低重要性,避免打扰用户
- Android 12+以上,前台服务必须指定对应的
foregroundServiceType,不然会报错
内容的提问来源于stack exchange,提问作者Varun
相关产品推荐
相关产品推荐

