几周以来我一直在努力解决应用程序中的功能。
我会解释我的项目;我有一个反应本机应用程序,可以连接多个用户。用户可以创建事件(例如会议),而其他用户会收到通知。该事件被添加到创建会议的用户(我们称他为用户 1)的本机日历中,我也想将其添加到受邀参加会议的用户(我们称他为用户 2)中。当用户打开应用程序或应用程序状态更改时,我为用户 2 同步本机日历中的事件的功能工作正常。但我想同步用户 2 的本机日历,即使他没有打开应用程序,就像在后台一样。
为此,我想到了两个解决方案。最好的就是通知。因此,当用户 1 创建会议时,用户 2 总是会收到通知,我的想法是当显示通知时,我可以同步日历。因此,对于通知,我使用 firebase,通知显示在后台,但我的代码没有执行。问题是我的代码运行后台消息时出现一些错误。我的错误表明我使用 id ReactNativeFirebaseMessagingHeadlessTask 运行多个 HeadlessTask。我不知道为什么会收到此错误,但我仍然有后台通知,但没有 console.log()。所以我通过通知放弃了这个想法。
这是我注册后台通知的代码:
import * as React from 'react';
import { useState, useEffect } from 'react';
import { API_KEY, PROJECT_ID, STORAGE_BUCKET, MESSAGING_SENDER_ID, APP_ID } from '@env';
import firebase from '@react-native-firebase/app';
import messaging from '@react-native-firebase/messaging';
import { AppRegistry } from 'react-native';
import { syncCalendarEventId } from '../utils/calendarSync';
const register = async () => {
const firebaseConfig = {
apiKey: `${API_KEY}`,
projectId: `${PROJECT_ID}`,
storageBucket: `${STORAGE_BUCKET}`,
messagingSenderId: `${MESSAGING_SENDER_ID}`,
appId: `${APP_ID}`,
// databaseURL: '...',
// authDomain: '...',
};
firebase
.initializeApp(firebaseConfig)
.then(() => {
registerBackgroundMessage();
})
.catch(error => {
});
};
export async function initializeNotifications() {
await register();
if (!firebase.apps.length) {
register();
} else {
registerBackgroundMessage();
}
}
// Request user permission for notifications
export async function requestUserPermission() {
const authStatus = await messaging().requestPermission();
const enabled =
authStatus === messaging.AuthorizationStatus.AUTHORIZED ||
authStatus === messaging.AuthorizationStatus.PROVISIONAL;
if (enabled) {
const token = await messaging().getToken();
return token;
}
}
// Register background handler
const registerBackgroundMessage = () => {
console.log("bg")
if(Platform.OS === 'ios'){
messaging().setBackgroundMessageHandler(async remoteMessage => {
console.log('Notification reçue en fond ! : ', remoteMessage);
if(remoteMessage.data && remoteMessage.data.sync_required == 1){
syncCalendarEventId();
}
});
} else if(Platform.OS === 'android'){
const headlessNotificationHandler = async (remoteMessage) => {
console.log('Notification reçue en fond ! : ', remoteMessage);
// Ajoutez ici toute logique que vous souhaitez traiter en arrière-plan
};
// Enregistrez la tâche headless
AppRegistry.registerHeadlessTask(
'ReactNativeFirebaseMessagingHeadlessTask',
() => headlessNotificationHandler
);
}
};
我得到的第二个想法(但我认为最糟糕的)是尝试每 30 分钟或每小时同步一次事件。我尝试使用 react-native-background-fetch 库来做到这一点,但仍然不起作用。我不知道为什么,但我的代码在 20 或 25 分钟后没有运行事件。这是我的这个库的代码:
useEffect(() => {
const configureBackgroundFetch = async () => {
console.log("configure bg");
BackgroundFetch.configure(
{
minimumFetchInterval: 15,
stopOnTerminate: false,
startOnBoot: true,
},
async (taskId) => {
console.log("sync")
syncCalendarEventId();
console.log(`Tâche de fetch avec ID ${taskId} exécutée`);
BackgroundFetch.finish(taskId);
},
(error) => {
console.error('Erreur de configuration BackgroundFetch:', error);
}
);
console.log("fetch start");
BackgroundFetch.start();
console.log("fetch started");
};
configureBackgroundFetch();
}, []);
有关信息,useEffect 位于我的 App.js 文件中。对于后台获取库,我认为我已经正确安装了它。
<key>UIBackgroundModes</key>
<array>
<string>remote-notification</string>
<string>fetch</string>
<string>processing</string>
</array>
所以我的问题是:是否可以在后台创建类似日历同步的功能,或者我只是在用户打开我的应用程序时让同步?
感谢您的宝贵帮助:)
让我分解一下可行的方法并提供一些建议:
// NotificationService.js
import messaging from '@react-native-firebase/messaging';
import { AppRegistry, Platform } from 'react-native';
import { syncCalendarEventId } from './calendarSync';
class NotificationService {
async initialize() {
// Request permissions
const authStatus = await messaging().requestPermission();
const enabled =
authStatus === messaging.AuthorizationStatus.AUTHORIZED ||
authStatus === messaging.AuthorizationStatus.PROVISIONAL;
if (!enabled) {
console.log('User notification permissions denied');
return false;
}
// Get FCM token
const token = await messaging().getToken();
console.log('FCM Token:', token);
// Register background handler
if (Platform.OS === 'ios') {
messaging().setBackgroundMessageHandler(this.handleBackgroundMessage);
} else {
// For Android, we only need to register the task once
if (!AppRegistry.getRunnable('ReactNativeFirebaseMessagingHeadlessTask')) {
AppRegistry.registerHeadlessTask(
'ReactNativeFirebaseMessagingHeadlessTask',
() => this.handleBackgroundMessage
);
}
}
// Register foreground handler
messaging().onMessage(this.handleForegroundMessage);
return true;
}
handleBackgroundMessage = async (remoteMessage) => {
console.log('Background Message received:', remoteMessage);
try {
if (remoteMessage.data?.sync_required === '1') {
await syncCalendarEventId();
console.log('Calendar sync completed in background');
}
} catch (error) {
console.error('Error in background sync:', error);
}
}
handleForegroundMessage = async (remoteMessage) => {
console.log('Foreground Message received:', remoteMessage);
try {
if (remoteMessage.data?.sync_required === '1') {
await syncCalendarEventId();
console.log('Calendar sync completed in foreground');
}
} catch (error) {
console.error('Error in foreground sync:', error);
}
}
}
export default new NotificationService();
// App.js
import React, { useEffect } from 'react';
import BackgroundFetch from 'react-native-background-fetch';
import NotificationService from './NotificationService';
const App = () => {
useEffect(() => {
const setupBackgroundTasks = async () => {
// Initialize notifications
await NotificationService.initialize();
// Configure background fetch as a fallback
BackgroundFetch.configure({
minimumFetchInterval: 15, // 15 minutes minimum
stopOnTerminate: false,
startOnBoot: true,
enableHeadless: true,
forceAlarmManager: true, // Use AlarmManager for more reliable scheduling on Android
}, async (taskId) => {
console.log('[BackgroundFetch] Task received:', taskId);
try {
await syncCalendarEventId();
console.log('[BackgroundFetch] Calendar sync completed');
} catch (error) {
console.error('[BackgroundFetch] Sync error:', error);
}
BackgroundFetch.finish(taskId);
}, (error) => {
console.error('[BackgroundFetch] Configure error:', error);
});
// Start background fetch
const status = await BackgroundFetch.status();
console.log('[BackgroundFetch] status:', status);
if (status !== BackgroundFetch.STATUS_RESTRICTED) {
await BackgroundFetch.start();
}
};
setupBackgroundTasks();
// Cleanup
return () => {
BackgroundFetch.stop();
};
}, []);
return (
// Your app components
);
};
export default App;
以下是我对您的情况的分析和建议:
Firebase 云消息传递 (FCM) 方法
后台获取方法
forceAlarmManager: true
以实现更可靠的 Android 调度最佳实践实施
结合使用两种方法:
正确的错误处理和日志记录以进行调试
将关注点分离到不同的文件中以便更好地维护
针对您的具体案例的建议