import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:get/get.dart'; import 'package:im_flutter_sdk/im_flutter_sdk.dart'; import '../pages/message/chat_page.dart'; import '../controller/message/conversation_controller.dart'; /// 本地通知服务 class LocalNotificationService { // 单例模式 static final LocalNotificationService _instance = LocalNotificationService._internal(); factory LocalNotificationService() => _instance; static LocalNotificationService get instance => _instance; final FlutterLocalNotificationsPlugin _localNotifications = FlutterLocalNotificationsPlugin(); bool _notificationsInitialized = false; static int _notificationId = 0; // 通知ID计数器 LocalNotificationService._internal(); /// 初始化本地通知 Future initialize() async { if (_notificationsInitialized) { return; } try { // Android 初始化设置 const AndroidInitializationSettings initializationSettingsAndroid = AndroidInitializationSettings('@mipmap/ic_launcher'); // iOS 初始化设置 const DarwinInitializationSettings initializationSettingsIOS = DarwinInitializationSettings( requestAlertPermission: true, requestBadgePermission: true, requestSoundPermission: true, ); // 初始化设置 const InitializationSettings initializationSettings = InitializationSettings( android: initializationSettingsAndroid, iOS: initializationSettingsIOS, ); // 初始化插件 final bool? initialized = await _localNotifications.initialize( initializationSettings, onDidReceiveNotificationResponse: _onNotificationTapped, ); if (initialized == true) { _notificationsInitialized = true; if (Get.isLogEnable) { Get.log('✅ [LocalNotificationService] 本地通知初始化成功'); } } else { if (Get.isLogEnable) { Get.log('⚠️ [LocalNotificationService] 本地通知初始化失败'); } } } catch (e) { if (Get.isLogEnable) { Get.log('❌ [LocalNotificationService] 本地通知初始化异常: $e'); } } } /// 通知点击回调 void _onNotificationTapped(NotificationResponse response) { try { final payload = response.payload; if (payload != null && payload.isNotEmpty) { // payload 格式: "type|fromId" final parts = payload.split('|'); if (parts.length >= 2) { final fromId = parts[1]; // 跳转到聊天页面 Get.to(() => ChatPage( userId: fromId, userData: null, )); } } } catch (e) { if (Get.isLogEnable) { Get.log('⚠️ [LocalNotificationService] 处理通知点击失败: $e'); } } } /// 获取消息内容文本 String _getMessageContent(EMMessage message) { try { if (message.body.type == MessageType.TXT) { final body = message.body as EMTextMessageBody; return body.content ?? ''; } else if (message.body.type == MessageType.IMAGE) { return '[图片]'; } else if (message.body.type == MessageType.VOICE) { return '[语音]'; } else if (message.body.type == MessageType.VIDEO) { return '[视频]'; } else if (message.body.type == MessageType.FILE) { return '[文件]'; } else if (message.body.type == MessageType.LOCATION) { return '[位置]'; } else if (message.body.type == MessageType.CUSTOM) { final body = message.body as EMCustomMessageBody; if (body.event == 'live_room_invite') { return '[分享房间]'; } else if (body.event == 'gift') { return '[礼物]'; } else if (body.event == 'call') { // 解析通话类型 try { if (body.params != null) { final callType = body.params!['callType'] ?? 'voice'; if (callType == 'video') { return '[视频通话]'; } else if (callType == 'voice') { return '[语音通话]'; } } } catch (e) { if (Get.isLogEnable) { Get.log('⚠️ [LocalNotificationService] 解析通话消息类型失败: $e'); } } return '[通话消息]'; } return '[自定义消息]'; } } catch (e) { if (Get.isLogEnable) { Get.log('⚠️ [LocalNotificationService] 获取消息内容失败: $e'); } } return ''; } /// 显示本地通知(当 APP 在后台时) Future showNotification(EMMessage message, {Set? activeChatUserIds}) async { if (!_notificationsInitialized) { await initialize(); } try { // 获取消息发送者ID final fromId = message.from; if (fromId == null || fromId.isEmpty) { return; } // 检查发送者是否是当前正在聊天的用户 if (activeChatUserIds != null && activeChatUserIds.contains(fromId)) { // 是当前正在聊天的用户,不显示通知 return; } // 获取消息内容 String messageContent = _getMessageContent(message); if (messageContent.isEmpty) { return; } // 从消息扩展字段中获取用户信息(头像、昵称) Map? attributes; try { attributes = message.attributes; } catch (e) { if (Get.isLogEnable) { Get.log('⚠️ [LocalNotificationService] 无法访问消息扩展字段: $e'); } return; } String? nickName; String? avatarUrl; if (attributes != null) { // 从扩展字段中获取发送者信息 nickName = attributes['sender_nickName'] as String?; avatarUrl = attributes['sender_avatarUrl'] as String?; } // 如果从消息扩展字段中获取不到,尝试从 ConversationController 的缓存中获取 if ((nickName == null || nickName.isEmpty) || (avatarUrl == null || avatarUrl.isEmpty)) { try { if (Get.isRegistered()) { final conversationController = Get.find(); final cachedUserInfo = conversationController.getCachedUserInfo(fromId); if (cachedUserInfo != null) { nickName = nickName ?? cachedUserInfo.nickName; avatarUrl = avatarUrl ?? cachedUserInfo.avatarUrl; } } } catch (e) { if (Get.isLogEnable) { Get.log('⚠️ [LocalNotificationService] 从ConversationController获取用户信息失败: $e'); } } } // 使用默认值 final finalNickName = nickName ?? fromId; // 处理视频通话消息 Map? callInfo; String? callType; String? callStatus; try { // 自定义消息 if (message.body.type == MessageType.CUSTOM) { final customBody = message.body as EMCustomMessageBody; if (customBody.event == 'call' && customBody.params != null) { final params = customBody.params!; callType = params['callType'] ?? 'voice'; callStatus = params['callStatus'] ?? 'missed'; callInfo = { 'callType': callType, 'callStatus': callStatus, }; } } // 如果是视频通话且状态为 missed 或 calling if (callInfo != null && callType != null && callStatus != null) { if (callType == 'video' && (callStatus == 'missed' || callStatus == 'calling')) { // 显示视频通话通知 final notificationId = _notificationId++; const AndroidNotificationDetails androidPlatformChannelSpecifics = AndroidNotificationDetails( 'video_call_channel', '视频通话', channelDescription: '视频通话通知', importance: Importance.max, priority: Priority.high, showWhen: true, ); const DarwinNotificationDetails iOSPlatformChannelSpecifics = DarwinNotificationDetails( presentAlert: true, presentBadge: true, presentSound: true, ); const NotificationDetails platformChannelSpecifics = NotificationDetails( android: androidPlatformChannelSpecifics, iOS: iOSPlatformChannelSpecifics, ); await _localNotifications.show( notificationId, '视频通话', '$finalNickName 邀请您进行视频通话', platformChannelSpecifics, payload: 'video_call|$fromId', ); if (Get.isLogEnable) { Get.log('📱 [LocalNotificationService] 显示视频通话本地通知: $fromId'); } return; } } } catch (e) { if (Get.isLogEnable) { Get.log('⚠️ [LocalNotificationService] 处理视频通话通知失败: $e'); } } // 显示普通消息通知 final notificationId = _notificationId++; const AndroidNotificationDetails androidPlatformChannelSpecifics = AndroidNotificationDetails( 'message_channel', '消息通知', channelDescription: '新消息通知', importance: Importance.high, priority: Priority.high, showWhen: true, ); const DarwinNotificationDetails iOSPlatformChannelSpecifics = DarwinNotificationDetails( presentAlert: true, presentBadge: true, presentSound: true, ); const NotificationDetails platformChannelSpecifics = NotificationDetails( android: androidPlatformChannelSpecifics, iOS: iOSPlatformChannelSpecifics, ); await _localNotifications.show( notificationId, finalNickName, messageContent, platformChannelSpecifics, payload: 'message|$fromId', ); if (Get.isLogEnable) { Get.log('📱 [LocalNotificationService] 显示本地通知: $fromId, $messageContent'); } } catch (e) { if (Get.isLogEnable) { Get.log('❌ [LocalNotificationService] 显示本地通知失败: $e'); } } } }