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

Android Oreo:BroadcastReceiver+JobIntentService与GCM通知异常求助

针对你的GCM推送两个异常问题的解决方案

嘿,我来帮你拆解这两个问题,都是和Android不同版本的推送机制适配有关的,咱们一个个来解决:

问题1:Android 8.0以下设备进程被杀后无法接收推送

可能原因

你当前用BroadcastReceiver调用enqueueWork启动JobIntentService的方式,在低版本Android(Oreo以下)进程被杀后,存在一个关键问题:系统唤醒你的BroadcastReceiver后,如果没有持有唤醒锁(WakeLock),系统可能在JobIntentService开始执行前就进入休眠状态,导致推送任务被中断。另外,部分厂商定制ROM的后台查杀策略,也可能拦截静态广播的触发,让推送无法被接收。

解决方案

  1. 手动管理唤醒锁
    BroadcastReceiveronReceive方法中主动获取唤醒锁,确保JobIntentService能完成任务后再释放:

    // 在BroadcastReceiver的onReceive中
    PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
    PowerManager.WakeLock wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "YourApp:PushWakeLock");
    wakeLock.acquire(60 * 1000); // 设置60秒超时,防止意外持有锁
    
    Intent intent = new Intent(context, YourJobService.class);
    intent.putExtra("wake_lock", wakeLock);
    enqueueWork(context, YourJobService.class, 1001, intent);
    

    然后在JobIntentServiceonHandleWork中释放锁:

    @Override
    protected void onHandleWork(@NonNull Intent intent) {
        PowerManager.WakeLock wakeLock = (PowerManager.WakeLock) intent.getParcelableExtra("wake_lock");
        try {
            // 执行推送通知的逻辑
            showNotification();
        } finally {
            if (wakeLock != null && wakeLock.isHeld()) {
                wakeLock.release();
            }
        }
    }
    

    别忘了在Manifest中添加权限:

    <uses-permission android:name="android.permission.WAKE_LOCK" />
    
  2. 改用FirebaseMessagingService接收推送
    官方早已把GCM整合到FCM,FirebaseMessagingService本身已经内置了唤醒锁管理,比手动用BroadcastReceiver更可靠。你只需要继承这个类,重写onMessageReceived方法,在这里直接处理通知推送即可,能避免很多低版本的适配问题。


问题2:Android 8.0以上设备必须点亮屏幕才能收到通知

可能原因

Android 8.0(Oreo)引入了**通知渠道(Notification Channel)**和更严格的后台限制:

  1. 如果没有创建对应的通知渠道,或者渠道的重要性设置过低(比如IMPORTANCE_LOW),系统会把通知归为低优先级,只有屏幕点亮时才会显示。
  2. JobIntentService在Android 8.0以上是通过JobScheduler实现的,而JobScheduler的任务在设备休眠或后台时会被系统延迟执行,导致通知不能及时弹出。

解决方案

  1. 创建高优先级通知渠道
    必须在应用启动时创建通知渠道,并且设置重要性为IMPORTANCE_HIGH,这样通知才能在锁屏或设备休眠时弹出:

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        NotificationChannel channel = new NotificationChannel(
                "push_channel_id",
                "CMS推送通知",
                NotificationManager.IMPORTANCE_HIGH
        );
        channel.setDescription("来自CMS的推送消息");
        NotificationManager notificationManager = getSystemService(NotificationManager.class);
        notificationManager.createNotificationChannel(channel);
    }
    

    构建通知时指定这个渠道ID:

    NotificationCompat.Builder builder = new NotificationCompat.Builder(context, "push_channel_id")
            .setSmallIcon(R.drawable.ic_notification)
            .setContentTitle("通知标题")
            .setContentText("通知内容")
            .setPriority(NotificationCompat.PRIORITY_HIGH); // 兼容低版本系统
    
  2. 绕过JobIntentService处理即时推送
    如果是需要即时到达的推送,建议直接在FirebaseMessagingServiceonMessageReceived中处理通知,而不是通过JobIntentService——因为JobIntentService在Android 8.0以上的后台执行会受系统限制,容易延迟。如果必须用后台任务,要把JobIntentService改为前台服务,启动时调用startForeground,避免被系统杀死。

  3. 适配厂商后台限制
    部分国产厂商(小米、华为、OPPO等)有额外的后台查杀策略,需要引导用户把你的应用加入“后台白名单”或开启“自启动权限”,否则即使适配了系统规则,推送也可能被拦截。


最后给你个小建议:尽快迁移到FCM(Firebase Cloud Messaging),GCM已经被官方弃用,FCM在兼容性和可靠性上都更优,内置了很多不同Android版本的适配逻辑,能减少你手动踩坑的麻烦。

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

火山引擎 最新活动