繁体   English   中英

使用 Firebase 处理后台推送通知,支持 Doze

[英]Handle background push notifications with Firebase, supporting Doze

我有一个 Android 应用程序配置为通过 Firebase 接收推送通知,但在手机处于打盹模式时无法正常工作。

应用程序正确接收推送通知,无论它是在前台还是在后台。 为此,我仅使用推送通知中的data字段来处理任何传入的内容,而不管应用程序的状态如何。

我已经实现了我的服务来接收通知,如下所示:

class MyFirebaseMessagingService : FirebaseMessagingService() {

   override fun onMessageReceived(p0: RemoteMessage?) {
        Timber.d("Push notification received")
        super.onMessageReceived(p0)
        when (p0!!.data["ch"]) {
            NotificationType.VoIP.channelType() -> handleVoIPNotification(p0.data)
            NotificationType.Push.channelType() -> handlePushNotification(p0.data)
        }
    }

}

ch属性定义了通知的类型并从我的后端发送:由于我的应用程序具有视频通话功能,当有人呼叫后端时,会发送一个带有ch = voip的通知并将消息优先级设置为high ,如中所述Firebase 指南

handleVoIPNotification函数包含以下内容:

private fun handleVoIPNotification(data: Map<String, String>) {
        val gson = Gson()
        val jsonElement = gson.toJsonTree(data)

        try {
            val voIPNotification = gson.fromJson(jsonElement, VoIPNotification::class.java)

            Timber.i("VoIP Notification received: %s", voIPNotification.action.name)

            // pass the incoming call data to the Call Manager.
            CallManager.getInstance().handleNotification(voIPNotification)
        } catch (exc: Exception) {
            Timber.e(exc)
            Timber.i("Invalid VoIP notification received: %s", data)
        }
    }

然后呼叫管理器更新名为currentCall的属性并终止:

this.currentCall.apply {
        token = notification.token
        roomName = notification.room
        username = notification.nickname

        status.value = Call.CallStatus.Ringing
    }

status属性是一个BehaviorSubject实现,它被另一个对象观察到,该对象对调用状态的变化做出反应:

currentCall.status.observable
                .distinctUntilChanged()
                .subscribe {
                    Timber.d("Call status changed: $it")

                    when (it) {
                        Call.CallStatus.Ringing -> {
                            this.showIncomingCallNotification()
                        }
                        Call.CallStatus.Declined, Call.CallStatus.Ended -> {
                            this.dismissIncomingCallNotification()
                            this.refreshIncomingCallActivity()
                        }
                        Call.CallStatus.Connecting -> {
                            this.dismissIncomingCallNotification()
                            this.presentOngoingCallActivity()
                        }
                        else -> { /* ignored */ }
                    }
                }.disposedBy(this.disposeBag)

showIncomingCallNotification如下:

fun showIncomingCallNotification() {
        val intent = Intent(Intent.ACTION_MAIN, null).apply {
            flags = Intent.FLAG_ACTIVITY_NO_USER_ACTION or Intent.FLAG_ACTIVITY_NEW_TASK
            setClass(configuration.context, configuration.incomingCallActivityType.java)
        }

        val pendingIntent = PendingIntent.getActivity(configuration.context, configuration.requestCode, intent, 0)

        val builder = NotificationCompat.Builder(configuration.context, configuration.notificationChannel)
                .setOngoing(true)
                .setContentIntent(pendingIntent)
                .setFullScreenIntent(pendingIntent, true)
                .setSmallIcon(configuration.notificationIcon)
                .setContentTitle(currentCall.username)
                .setContentText(configuration.context.getString(configuration.notificationText))

        val notification = builder.build()
        notification.flags = notification.flags or Notification.FLAG_INSISTENT

        configuration.notificationsManager.getSystemNotificationManager().notify(0, notification)
    }

此代码显示一个通知,当按下该通知时,将打开 IncomingCallActivity 并让用户接受或拒绝呼叫。 此通知还负责使电话响铃和振动。

当应用程序在前台或后台打开时,只要屏幕打开或刚刚关闭,所有这些都可以完美运行。 如果我等待一段时间(从 5 分钟到几小时,视情况而定),一切都会停止工作:当我的后端发送推送通知时,我的 Firebase 服务不会被调用(我可以看到推送通知已正确发送)。 打开屏幕,使来电通知正确显示。

我的日志清楚地表明,在我打开屏幕之前,甚至没有调用 Firebase 服务onMessageReceived函数。

我已经阅读了一千遍Android Developers - Optimize for Doze 和 App Standby ,他们清楚地指出带有高优先级消息的 FCM 是在手机空闲时唤醒应用程序的正确方法。

FCM 经过优化,可通过高优先级 FCM 消息在 Doze 和 App Standby 空闲模式下工作。 FCM 高优先级消息可让您可靠地唤醒应用程序以访问网络,即使用户的设备处于 Doze 或应用程序处于应用程序待机模式也是如此。 在 Doze 或 App Standby 模式下,系统传递消息并让应用程序临时访问网络服务和部分唤醒锁,然后将设备或应用程序返回到空闲状态。

无论如何,这是行不通的。 我在不同的手机上尝试过,我可以说这种行为在 Android 9 上更糟糕,而在 Android 7 及更低版本上,这种情况并不常见。

我已经看到并尝试了在另一个问题中提出的解决方案,但它们似乎都不起作用,即使在其中一个答案中他们说只有当用户从多任务处理中刷掉应用程序时才会发生这种情况,我也可以说即使应用程序没有被强制停止,它也会发生在我身上。

还有另一个问题,更类似于我的问题, 这里但所有提出的解决方案都不起作用。

我不知道如何解决这个问题,这是一个非常糟糕的问题,会影响我的应用程序的可用性,因为用户在不使用手机时无法接听视频通话。 我还发现其他人在网上报告了这个问题,但所有这些对话似乎都在某个时候没有实际解决方案就消失了……

谁能帮我?

事实证明,这不是 FCM 问题,但实际上是 Azure 通知中心(我们的后端用于发送通知的系统)的问题。

如果您在使用高优先级消息、Azure 通知中心和打盹模式方面遇到问题,请参阅此问题的所选答案: 设置 Fcm 通知优先级 - Azure 通知中心

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM