firebase通知在一段时间后(一天或几天)停止工作



我对这个问题感到非常沮丧:(

我正在为android和ios开发一个应用程序(使用电容器3(,并通过firebase通知向该应用程序发送通知。(电容器包:@cacitor community/fcm和@cacitor/推送通知(。

它可以工作一段时间,在一天或几天后,应用程序在后台或前台运行(并且没有被杀死(,它停止工作,应用程序不会收到通知(这在安卓设备中发生过(。

我使用主题发送通知,我也尝试通过firebase控制台发送通知,但没有成功。

我不确定这是否意味着注册令牌已经过期,因为我认为电容器封装应该处理它,因为他们没有谈论这个问题。

我做了所有的事情,从电容器推送通知的文档。

当我查看日志时,我可以看到下一个错误:无法同步主题。不会重试同步。INVALID_PARAMETERS。

我的javascript代码:

import '@capacitor/core';
import { ActionPerformed, PushNotificationSchema, PushNotifications } from '@capacitor/push-notifications'
import { FCM } from '@capacitor-community/fcm';
import { getMessaging, getToken as firebaseGetToken, onMessage, deleteToken, isSupported } from "firebase/messaging";
import { myAxios } from './generic-functions/my-axios';
const platform = window.Capacitor && window.Capacitor.platform;
const topicIos = `${process.env.REACT_APP_TOPIC}_ios`;
const topicAnd = `${process.env.REACT_APP_TOPIC}_and`;
function isCapacitor(): boolean {
//check if we are in a capacitor platform
return window.Capacitor && (window.Capacitor.platform === "android" || window.Capacitor.platform === "ios")
}
export async function InitFCM(destination: string) {
if (!isCapacitor()) {
const isNtfSupported = await isSupported()
if (!isNtfSupported) return
// web notifications
Notification.requestPermission().then(function (permission) {
if (permission === 'granted') {
subscribeTo(destination);
} else {
// Show some error
}
});
const messaging = getMessaging();
onMessage(messaging, (payload) => {
let notification = payload.data;
const notificationOptions: NotificationOptions = {
badge: notification?.largeIco,
body: notification?.body,
icon: notification?.largeIcon
};
const title = notification?.title || "";
// show notification
navigator.serviceWorker
.getRegistrations()
.then((registration) => {
if (notification?.sound) {
const audio = new Audio(`/notifications/${notification?.sound}`)
audio.play()
}
registration[0].showNotification(title, notificationOptions);
});
})
return
}
try {
console.log('Initializing Push Notifications');
// Request permission to use push notifications
// iOS will prompt user and return if they granted permission or not
// Android will just grant without prompting
PushNotifications.requestPermissions().then(result => {
if (result.receive === 'granted') {
// Register with Apple / Google to receive push via APNS/FCM
// PushNotifications.register();
subscribeTo(destination);
} else {
// Show some error
}
});
// Some issue with our setup and push will not work
PushNotifications.addListener('registrationError',
(error: any) => {
console.log('Error on registration: ' + JSON.stringify(error));
}
);
// Show us the notification payload if the app is open on our device
PushNotifications.addListener('pushNotificationReceived',
(notification: PushNotificationSchema) => {
console.log('Push received: ' + JSON.stringify(notification));
}
);
// Method called when tapping on a notification
PushNotifications.addListener('pushNotificationActionPerformed',
(notification: ActionPerformed) => {
console.log('Push action performed: ' + JSON.stringify(notification));
}
);
} catch (e) {
console.log('err in push notifications: ', e);
}
}
async function subscribeTo(destination: string) {
if (!isCapacitor()) {
//subscribe to web topic
const messaging = getMessaging();
firebaseGetToken(messaging, { vapidKey: process.env.REACT_APP_FIREBASE_VAPID_KEY }).then(
async (token) => {
if (token) {
await myAxios.post("/api/notifications/subscribe-to-topic", { token, destination });
}
}).catch((err) => {
console.log('An error occurred while retrieving token. ', err);
});
return
}
try {
await PushNotifications.register();
if (platform === "ios") {
//subscribe to ios topic
const resIos = await FCM.subscribeTo({ topic: `${topicIos}_${destination}` });
console.log(`subscribed to ios Topic ${JSON.stringify(resIos)}`);
}
if (platform === "android") {
//subscribe to android topic
const resAnd = await FCM.subscribeTo({ topic: `${topicAnd}_${destination}` });
console.log(`subscribed to android Topic ${JSON.stringify(resAnd)}`);
}
} catch (error) {
console.log(JSON.stringify(error));
}
}
export async function getToken() {
try {
/* const result = */ await FCM.getToken();
// console.log("TOKEN", result.token);
} catch (error) {
console.log(error);
}
}
export async function unsubscribeFrom(destination?: string) {
if (!isCapacitor()) {
const isNtfSupported = await isSupported()
if (!isNtfSupported || !destination) return
const messaging = getMessaging();
//unsubscribe from web topic
firebaseGetToken(messaging, { vapidKey: process.env.REACT_APP_FIREBASE_VAPID_KEY }).then(
async (token) => {
if (token) {
await myAxios.post("/api/notifications/unsubscribe-from-topic", { token, destination });
}
}).catch((err) => {
console.log('An error occurred while retrieving token. ', err);
});
return
}
try {
await PushNotifications.removeAllListeners();
if (destination) {
if (platform === "ios") {
//unsubscribe from ios topic
const resIos = await FCM.unsubscribeFrom({ topic: `${topicIos}_${destination}` });
console.log(`unsubscribed from ios topic ${resIos}`);
}
if (platform === "android") {
//unsubscribe from android topic
const resAndroid = await FCM.unsubscribeFrom({ topic: `${topicAnd}_${destination}` });
console.log(`unsubscribed from android topic ${topicAnd}_${destination}: ${resAndroid.message}`);
}
}
} catch (error) {
console.log(error)
}
if (platform === 'android') {
await FCM.deleteInstance();
}
}

提前感谢大家!

这是自Android 7.0以来常见的问题。出现此问题是因为您使用了数据消息。您的代码onMessage(messaging, (payload) => {的这一部分告诉我您依赖它。这意味着,当收到消息时,即使在后台,你的应用程序代码也会处理传递。例如,它会创建一个通知,在设备上显示它并播放声音。

电源管理走得太远

一些设备制造商在电源管理方面改进得太多了。这导致了以下问题:在几天的不活动之后,一个应用程序被Android操作系统完全杀死。这意味着该应用程序无法再在后台处理传入消息。供应商做得太过分了。但你对此无能为力。

该怎么办

要解决此问题,您应该使用通知消息。这些消息直接发送到Android操作系统,而不是您的应用程序。这意味着消息不需要应用程序的后台处理。在服务器(发送(端,这意味着您必须修改当前邮件,并在发送的邮件中添加通知信息。

缺点

通知消息的缺点是,您无法处理作为通知一部分的数据。如果你之前用每个通知的数据和通知消息填充了你的应用程序,那么只有当你的应用处于前台或点击通知时,你才能获得数据。要获取应用程序中的所有数据,您需要一个服务器API解决方案或其他解决方案。

为了克服这个问题,你可以在你的应用程序中添加一个NotificationListener。我不知道如何在电容器中做到这一点。本地示例可在此处找到:https://github.com/Chagall/notification-listener-service-example.NotificationListener可以在后台监听发送到Android设备的通知。使用此解决方案,您可以确保始终发送通知,并在后台发送数据。但也许,我不知道,这个听众也被权力管理扼杀了。当您使用NotificationListener时,您需要一个特殊权限,该权限必须通过设备设置进行设置(请参阅上述示例(。

结论

从数据消息更改为通知消息。提供一种不同的方式在应用程序中获取消息数据。你可以使用NotificationListener,但我不知道这是否可靠。最明显的解决方案是引入服务器端API,为您的应用程序提供数据。在新的情况下,通知可以可靠地传递到应用程序。

最新更新