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

Android应用周期性自启动实现及FCM通知厂商干扰问题解决

Android 推送相关问题解决方案

1. 实现Android应用周期性自启动以接收通知

首先得明确:Android从8.0开始对后台启动管控越来越严格,国内厂商还会叠加额外限制,所以必须用官方推荐的合规方案,尽量降低被系统拦截的概率:

  • 使用WorkManager(官方首选)
    WorkManager是Jetpack组件,专门处理延迟/周期性后台任务,能自动适配不同Android版本,哪怕应用被划掉、设备重启,只要满足约束条件就会执行。
    示例代码:

    1. 定义Worker类:
    class NotificationCheckWorker(context: Context, params: WorkerParameters) : Worker(context, params) {
        override fun doWork(): Result {
            // 在这里执行通知检查、请求服务器拉取通知等逻辑
            return Result.success()
        }
    }
    
    1. 配置并启动周期性任务:
    val periodicRequest = PeriodicWorkRequestBuilder<NotificationCheckWorker>(1, TimeUnit.HOURS)
        .setConstraints(Constraints.Builder()
            .setRequiredNetworkType(NetworkType.CONNECTED) // 可选:仅在有网络时执行
            .build())
        .build()
    
    WorkManager.getInstance(context).enqueueUniquePeriodicWork(
        "NotificationCheck",
        ExistingPeriodicWorkPolicy.KEEP,
        periodicRequest
    )
    
  • AlarmManager(适合时间精度要求高的场景)
    Android 12+对精确闹钟要求SCHEDULE_EXACT_ALARM权限,普通重复闹钟会被系统延迟调度。如果用AlarmManager,需要配合BroadcastReceiver:
    示例代码:

    1. 动态注册BroadcastReceiver(Android8+静态注册大部分广播失效):
    class AlarmReceiver : BroadcastReceiver() {
        override fun onReceive(context: Context?, intent: Intent?) {
            // 执行通知接收逻辑,比如启动服务处理
            context?.startForegroundService(Intent(context, NotificationService::class.java))
        }
    }
    
    1. 设置重复闹钟:
    val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
    val intent = Intent(context, AlarmReceiver::class.java)
    val pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_IMMUTABLE)
    
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
        // Android12+需先申请精确闹钟权限
        if (alarmManager.canScheduleExactAlarms()) {
            alarmManager.setRepeating(
                AlarmManager.RTC_WAKEUP,
                System.currentTimeMillis(),
                3600000, // 1小时重复一次
                pendingIntent
            )
        }
    } else {
        alarmManager.setRepeating(
            AlarmManager.RTC_WAKEUP,
            System.currentTimeMillis(),
            3600000,
            pendingIntent
        )
    }
    
  • 关键注意事项

    • 申请必要权限:比如RECEIVE_BOOT_COMPLETED(设备重启后重新调度任务)、SCHEDULE_EXACT_ALARM(若使用精确闹钟)。
    • 引导用户添加厂商自启动白名单:国内小米、华为、OPPO等厂商会拦截未授权的后台任务,必须让用户手动在系统设置里开启应用的自启动权限,否则上述方法可能失效。

2. 解决FCM通知被厂商拦截的问题

这个问题核心是国内厂商的后台进程管控:用户划掉应用栈时,系统会强制杀死进程,导致FCM推送服务无法正常运行。结合你提到的「打开应用能获取到未展示的通知」,可以试试这些方案:

  • 引导用户开启核心权限与白名单
    这是最直接有效的方法,厂商拦截逻辑主要针对未授权应用:

    • 开启自启动权限:不同厂商路径不同,比如小米:设置→应用设置→应用管理→你的应用→权限管理→自启动;华为:设置→应用和服务→应用启动管理→你的应用→手动管理→允许自启动。
    • 开启忽略电池优化:设置→电池→电池优化→找到你的应用→选择「不允许」。
    • 开启后台弹出权限:部分厂商会拦截后台通知弹出,需开启此权限。
  • 优化FCM消息配置

    • 使用高优先级通知:发送FCM消息时,将priority设为high(Android)或10(iOS),系统会优先处理这条通知,哪怕应用在后台。
    • 结合数据消息:数据消息会触发FirebaseMessagingService的onMessageReceived方法(应用后台时也能触发,但进程被杀死后不行),你可以在这个方法里手动创建本地通知,确保展示:
    class MyFirebaseMessagingService : FirebaseMessagingService() {
        override fun onMessageReceived(remoteMessage: RemoteMessage) {
            super.onMessageReceived(remoteMessage)
            // 处理数据消息,构建并展示本地通知
            val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
            val notification = NotificationCompat.Builder(this, "NOTIFICATION_CHANNEL")
                .setContentTitle(remoteMessage.data["title"])
                .setContentText(remoteMessage.data["content"])
                .setSmallIcon(R.drawable.ic_notification)
                .build()
            notificationManager.notify(1, notification)
        }
    }
    
  • 启动前台服务
    如果你的应用有合法前台场景(比如音乐播放、定位追踪),可以启动前台服务,系统不会轻易杀死前台进程,FCM服务就能持续运行。注意要显示合规的前台通知:

    class NotificationService : Service() {
        override fun onCreate() {
            super.onCreate()
            val notification = NotificationCompat.Builder(this, "FOREGROUND_CHANNEL")
                .setContentTitle("应用运行中")
                .setContentText("正在接收通知")
                .setSmallIcon(R.drawable.ic_notification)
                .build()
            startForeground(1, notification)
        }
    
        override fun onBind(intent: Intent?): IBinder? = null
    }
    
  • 同步未展示的通知
    既然用户打开应用能获取到未展示的通知,你可以:

    • 在应用启动时,调用FCM相关API拉取未接收的消息;
    • 或者在服务器端记录已发送但未确认接收的消息,应用启动时请求服务器同步,然后本地展示这些消息。
  • 集成厂商推送通道
    国内厂商对自家推送服务优先级更高,比如华为HMS Push、小米Mi Push、OPPO OPush等。你可以在应用中集成这些厂商的推送SDK,检测到对应厂商设备时,优先使用厂商推送通道发送通知,能大幅提升送达率。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 09:00:08