【发布时间】:2019-11-10 11:29:36
【问题描述】:
我有一个配置为通过 Firebase 接收推送通知的 Android 应用,但我在手机处于打盹模式时遇到问题。
应用程序正确接收推送通知,无论它是在前台还是在后台。为此,我只使用推送通知中的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,据记录在 in the Firebase guide。
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 and App Standby,他们清楚地指出,具有高优先级消息的 FCM 是在手机空闲时唤醒应用程序的正确方法。
FCM 通过高优先级 FCM 消息进行了优化,可在打盹和应用待机空闲模式下工作。 FCM 高优先级消息让您可以可靠地唤醒您的应用程序以访问网络,即使用户的设备处于打盹或应用程序处于应用程序待机模式。在 Doze 或 App Standby 模式下,系统传递消息并让应用程序临时访问网络服务和部分唤醒锁,然后将设备或应用程序返回到空闲状态。
无论如何,这不起作用。我在不同的手机上试过,我可以说在 Android 9 上的行为更糟糕,而从 Android 7 及更低版本开始就不那么常见了。
我已经看到并尝试了其他 question 中提出的解决方案,但它们似乎都不起作用,即使在其中一个答案中他们说只有当用户从多个应用程序中刷掉应用程序时才会发生这种情况-tasking,我可以说即使应用程序没有被强制停止,它也会发生在我身上。
还有另一个问题,与我的问题更相似,here,但所有建议的解决方案都不起作用。
我不知道如何解决这个问题,这是一个非常糟糕的问题,会影响我的应用程序的可用性,因为用户在不使用手机时无法接听视频通话。我还发现其他人在网上报告了这个问题,但所有这些对话似乎都在没有实际解决方案的情况下消失了……
谁能帮帮我?
【问题讨论】:
-
这么说吧,这个问题在 Android 10 上也一直存在。你找到解决办法了吗?
-
不幸的是,我没有。我仍然面临同样的问题,我可以确认 Android 10 没有任何改变。我还尝试检查 Telegram 源代码(因为它们似乎不受此问题的影响),但我没有发现任何东西特别是。我的印象(但这只是一个印象,我没有数据支持)是 Android 的政策是基于应用在 Play 商店中的知名度。
-
这很奇怪,我能够绕过打盹模式。我想,我知道问题可能出在哪里。你能发布你的推送通知结构,整个结构。我也许可以调试它。
-
您指的是 VoIPNotification 对象还是发送到 Firebase 的实际 JSON?
-
不,根本不需要 VOIPNotification。它只是来自推送的数据,它说明了谁在打电话以及那里的号码。我需要将整个 JSON 发送到 firebase。
标签: android firebase push-notification firebase-cloud-messaging