You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Oppo、小米等机型关闭应用后Broadcast Receiver失效问题求助

解决Oppo/小米机型后台杀进程后短信Receiver失效问题

看起来你遇到的是国产定制ROM里非常常见的后台管控问题——Oppo、小米这些厂商为了优化设备续航,会在应用从最近列表移除后主动终止整个应用进程,连带静态注册的BroadcastReceiver也会被系统回收,导致短信监听直接失效。下面给你几个可行的解决方案:

一、引导用户开启应用的后台权限/自启动权限

这是最直接的破局点,因为这类机型的后台限制是系统级的,必须用户手动授权让你的应用在后台保持活跃:

  • 小米:设置 → 应用设置 → 应用管理 → 找到你的应用 → 权限管理 → 自启动 → 允许
  • Oppo:设置 → 应用管理 → 找到你的应用 → 权限管理 → 自启动管理 → 允许
  • Vivo:设置 → 更多设置 → 权限管理 → 自启动 → 找到你的应用开启

建议在应用首次启动时弹窗引导用户完成这个设置,否则后台短信监听功能大概率无法正常工作。

二、使用前台服务(Foreground Service)提升进程优先级

前台服务会在状态栏显示一个持续的低优先级通知,系统不会轻易杀死这类进程,你可以把短信处理逻辑和前台服务绑定,大幅提升存活概率:

1. 给MyService添加前台服务能力

首先在AndroidManifest.xml中添加前台服务权限:

<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

然后修改MyService的代码,在启动时触发前台服务(注意Android O及以上需要先创建通知渠道):

public class MyService extends Service {
    private static final int NOTIFICATION_ID = 1001;
    private static final String CHANNEL_ID = "SMS_LISTENER_CHANNEL";

    @Override
    public void onCreate() {
        super.onCreate();
        // 适配Android O+的通知渠道
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel(CHANNEL_ID,
                    "短信监听服务", NotificationManager.IMPORTANCE_LOW);
            NotificationManager manager = getSystemService(NotificationManager.class);
            if (manager != null) {
                manager.createNotificationChannel(channel);
            }
        }
        // 启动前台服务
        Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
                .setContentTitle("短信监听中")
                .setContentText("正在接收验证码短信")
                .setSmallIcon(R.drawable.ic_notification) // 替换成你的应用通知图标
                .build();
        startForeground(NOTIFICATION_ID, notification);
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // 处理短信逻辑
        String sender = intent.getStringExtra("s");
        String message = intent.getStringExtra("m");
        // 这里写你的业务处理代码...
        
        return START_STICKY; // 服务被系统杀死后尝试自动重启
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}

2. 优化Receiver的服务启动逻辑

确保在Receiver中启动服务时,适配Android版本的启动规则:

@Override
public void onReceive(Context context, Intent intent) {
    Toast.makeText(context, " reciever called ", Toast.LENGTH_SHORT).show();
    Bundle data = intent.getExtras();
    Object[] pdus = (Object[]) data.get("pdus");
    for (int i = 0; i < pdus.length; i++) {
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
            currentMessage = SmsMessage.createFromPdu((byte[]) pdus[i]);
        } else {
            currentMessage = SmsMessage.createFromPdu((byte[]) pdus[i]);
        }
        String sender = currentMessage.getDisplayOriginatingAddress();
        if (sender.contains("HP-CRAZND")) {
            String messageBody = currentMessage.getMessageBody();
            if (messageBody != null && !messageBody.isEmpty()) {
                Intent ii = new Intent(context, MyService.class);
                ii.putExtra("s", sender);
                ii.putExtra("m", messageBody);
                // Android O+ 必须用startForegroundService启动前台服务
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                    context.startForegroundService(ii);
                } else {
                    context.startService(ii);
                }
            }
        }
    }
}

三、动态注册BroadcastReceiver(Android 8.0+适配)

从Android 8.0开始,系统对静态注册的隐式广播做了严格限制(SMS_RECEIVED虽属例外,但后台被杀后仍会失效),你可以在前台服务中动态注册Receiver,这样只要服务存活,Receiver就能正常工作:

MyServiceonCreate方法中添加注册逻辑:

private SmsReceiver smsReceiver;

@Override
public void onCreate() {
    super.onCreate();
    // ... 前面的前台服务初始化代码 ...
    // 动态注册短信Receiver
    smsReceiver = new SmsReceiver();
    IntentFilter filter = new IntentFilter("android.provider.Telephony.SMS_RECEIVED");
    filter.setPriority(100);
    registerReceiver(smsReceiver, filter);
}

@Override
public void onDestroy() {
    super.onDestroy();
    // 服务销毁时取消注册Receiver,避免内存泄漏
    if (smsReceiver != null) {
        unregisterReceiver(smsReceiver);
    }
}

同时记得在AndroidManifest.xml中移除静态注册的Receiver,避免重复接收短信。

注意事项

  • 即使做了以上优化,部分机型的极端省电模式下还是可能杀死进程,所以引导用户开启后台权限是必不可少的步骤。
  • 前台服务的通知可以设置成低优先级,尽量减少对用户的日常干扰。

内容的提问来源于stack exchange,提问作者user6325227

火山引擎 最新活动