/** * 后台保活服务 * 使用 expo-background-fetch 和 expo-task-manager 实现 App 后台保活 * * 功能: * - 定期后台任务保持 App 在内存中 * - 配合 SSE 服务保持长连接 * - 收到消息时触发震动提示 */ import { AppState, AppStateStatus, Platform } from 'react-native'; import * as BackgroundFetch from 'expo-background-fetch'; import * as TaskManager from 'expo-task-manager'; import { wsService } from './wsService'; import { triggerVibration, vibrateOnMessage, setVibrationConfig, getVibrationConfig, setVibrationEnabled, } from './messageVibrationService'; export { triggerVibration, vibrateOnMessage, setVibrationConfig, getVibrationConfig, setVibrationEnabled }; // 后台任务名称 const BACKGROUND_FETCH_TASK = 'background-fetch-keepalive'; const REALTIME_KEEPALIVE_TASK = 'realtime-keepalive'; // 后台任务间隔(Android 最小 15 分钟,iOS 最小 15 分钟) const BACKGROUND_INTERVAL = 15; // 15 分钟 // 后台服务状态 let isInitialized = false; let appStateSubscription: any = null; // 定义后台任务 TaskManager.defineTask(BACKGROUND_FETCH_TASK, async () => { try { // 检查 SSE 连接状态 if (!wsService.isConnected()) { await wsService.connect(); } // 返回收到新数据 return BackgroundFetch.BackgroundFetchResult.NewData; } catch (error) { console.error('[BackgroundService] 后台任务执行失败:', error); return BackgroundFetch.BackgroundFetchResult.Failed; } }); // SSE 保活任务 TaskManager.defineTask(REALTIME_KEEPALIVE_TASK, async () => { try { if (!wsService.isConnected()) { await wsService.connect(); } return BackgroundFetch.BackgroundFetchResult.NewData; } catch (error) { console.error('[BackgroundService] SSE 保活失败:', error); return BackgroundFetch.BackgroundFetchResult.Failed; } }); /** * 注册后台任务 */ async function registerBackgroundTasks(): Promise { if (Platform.OS === 'web') { return; } try { // 检查是否已注册 const isRegistered = await TaskManager.isTaskRegisteredAsync(BACKGROUND_FETCH_TASK); if (!isRegistered) { await BackgroundFetch.registerTaskAsync(BACKGROUND_FETCH_TASK, { minimumInterval: BACKGROUND_INTERVAL * 60, // 转换为秒 stopOnTerminate: false, // App 终止后继续运行 startOnBoot: true, // 设备启动后自动运行 }); } // 注册 SSE 保活任务 const isSseKeepaliveRegistered = await TaskManager.isTaskRegisteredAsync(REALTIME_KEEPALIVE_TASK); if (!isSseKeepaliveRegistered) { await BackgroundFetch.registerTaskAsync(REALTIME_KEEPALIVE_TASK, { minimumInterval: 60, // 1 分钟检查一次 stopOnTerminate: false, startOnBoot: true, }); } } catch (error) { console.error('[BackgroundService] 注册后台任务失败:', error); } } /** * 取消后台任务 */ async function unregisterBackgroundTasks(): Promise { if (Platform.OS === 'web') { return; } try { await BackgroundFetch.unregisterTaskAsync(BACKGROUND_FETCH_TASK); await BackgroundFetch.unregisterTaskAsync(REALTIME_KEEPALIVE_TASK); } catch (error) { console.error('[BackgroundService] 取消后台任务失败:', error); } } /** * 设置 App 状态监听 */ function setupAppStateListener(): void { if (appStateSubscription) { return; } appStateSubscription = AppState.addEventListener('change', (nextAppState: AppStateStatus) => { void nextAppState; if (nextAppState === 'active') { // App 回到前台,确保连接 if (!wsService.isConnected()) { wsService.connect(); } } }); } /** * 初始化后台保活服务 */ export async function initBackgroundService(): Promise { if (isInitialized) { return true; } if (Platform.OS === 'web') { setupAppStateListener(); isInitialized = true; return true; } try { // 检查后台任务状态 const status = await BackgroundFetch.getStatusAsync(); if (status !== BackgroundFetch.BackgroundFetchStatus.Available) { console.warn('[BackgroundService] 后台任务不可用,状态:', status); // 即使后台任务不可用,也继续初始化其他功能 } // 注册后台任务 await registerBackgroundTasks(); // 设置 App 状态监听 setupAppStateListener(); isInitialized = true; return true; } catch (error) { console.error('[BackgroundService] 初始化失败:', error); return false; } } /** * 停止后台保活服务 */ export async function stopBackgroundService(): Promise { try { await unregisterBackgroundTasks(); if (appStateSubscription) { appStateSubscription.remove(); appStateSubscription = null; } isInitialized = false; } catch (error) { console.error('[BackgroundService] 停止服务失败:', error); } } /** * 检查后台服务状态 */ export async function checkBackgroundStatus(): Promise<{ isAvailable: boolean; isInitialized: boolean; registeredTasks: string[]; }> { if (Platform.OS === 'web') { return { isAvailable: false, isInitialized, registeredTasks: [], }; } const status = await BackgroundFetch.getStatusAsync(); const registeredTasks = await TaskManager.getRegisteredTasksAsync(); return { isAvailable: status === BackgroundFetch.BackgroundFetchStatus.Available, isInitialized, registeredTasks: registeredTasks.map(task => task.taskName), }; } // 导出服务实例 export const backgroundService = { init: initBackgroundService, stop: stopBackgroundService, vibrate: triggerVibration, vibrateOnMessage, setVibrationConfig, getVibrationConfig, setVibrationEnabled, checkStatus: checkBackgroundStatus, }; export default backgroundService;