/** * 后台保活服务 * 使用 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 * as Haptics from 'expo-haptics'; import { sseService } from './sseService'; // 后台任务名称 const BACKGROUND_FETCH_TASK = 'background-fetch-keepalive'; const REALTIME_KEEPALIVE_TASK = 'realtime-keepalive'; // 后台任务间隔(Android 最小 15 分钟,iOS 最小 15 分钟) const BACKGROUND_INTERVAL = 15; // 15 分钟 // 震动配置 interface VibrationConfig { enabled: boolean; // 是否启用震动 onChatMessage: boolean; // 私聊消息震动 onGroupMessage: boolean; // 群聊消息震动 onNotification: boolean; // 系统通知震动 style: Haptics.ImpactFeedbackStyle; // 震动样式 } // 默认震动配置 const defaultVibrationConfig: VibrationConfig = { enabled: true, onChatMessage: true, onGroupMessage: true, onNotification: true, style: Haptics.ImpactFeedbackStyle.Light, }; // 后台服务状态 let isInitialized = false; let vibrationConfig: VibrationConfig = { ...defaultVibrationConfig }; let appStateSubscription: any = null; // 定义后台任务 TaskManager.defineTask(BACKGROUND_FETCH_TASK, async () => { try { // 检查 SSE 连接状态 if (!sseService.isConnected()) { await sseService.connect(); } // 返回收到新数据 return BackgroundFetch.BackgroundFetchResult.NewData; } catch (error) { console.error('[BackgroundService] 后台任务执行失败:', error); return BackgroundFetch.BackgroundFetchResult.Failed; } }); // SSE 保活任务 TaskManager.defineTask(REALTIME_KEEPALIVE_TASK, async () => { try { if (!sseService.isConnected()) { await sseService.connect(); } return BackgroundFetch.BackgroundFetchResult.NewData; } catch (error) { console.error('[BackgroundService] SSE 保活失败:', error); return BackgroundFetch.BackgroundFetchResult.Failed; } }); /** * 触发震动反馈 * @param type 震动类型 */ export async function triggerVibration( type: 'light' | 'medium' | 'heavy' | 'success' | 'warning' | 'error' = 'light' ): Promise { if (!vibrationConfig.enabled) { return; } try { switch (type) { case 'light': await Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light); break; case 'medium': await Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium); break; case 'heavy': await Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Heavy); break; case 'success': await Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success); break; case 'warning': await Haptics.notificationAsync(Haptics.NotificationFeedbackType.Warning); break; case 'error': await Haptics.notificationAsync(Haptics.NotificationFeedbackType.Error); break; } } catch (error) { console.error('[BackgroundService] 震动反馈失败:', error); } } /** * 收到消息时触发震动 * @param messageType 消息类型 */ export async function vibrateOnMessage(messageType: 'chat' | 'group_message' | 'notification'): Promise { if (!vibrationConfig.enabled) { return; } switch (messageType) { case 'chat': if (vibrationConfig.onChatMessage) { await triggerVibration('light'); } break; case 'group_message': if (vibrationConfig.onGroupMessage) { await triggerVibration('light'); } break; case 'notification': if (vibrationConfig.onNotification) { await triggerVibration('medium'); } break; } } /** * 配置震动设置 */ export function setVibrationConfig(config: Partial): void { vibrationConfig = { ...vibrationConfig, ...config }; } /** * 获取当前震动配置 */ export function getVibrationConfig(): VibrationConfig { return { ...vibrationConfig }; } /** * 启用/禁用震动 */ export function setVibrationEnabled(enabled: boolean): void { vibrationConfig.enabled = enabled; } /** * 注册后台任务 */ async function registerBackgroundTasks(): Promise { 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 { 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 (!sseService.isConnected()) { sseService.connect(); } } }); } /** * 初始化后台保活服务 */ export async function initBackgroundService(): Promise { if (isInitialized) { 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[]; }> { 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;