import 'package:flutter_openim_sdk/flutter_openim_sdk.dart'; import 'im_service.dart'; /// 统一消息发送服务:所有消息(文字/表情/语音/图片/文件/通话信令)都走这里。 /// /// 职责: /// 1. 发送前置校验:已登录、连接正常、接收方非空; /// 2. 单聊时校验好友状态(非好友明确提示,不静默失败); /// 3. 失败时把 SDK 原始 code/message 记进日志(不含 token 与正文), /// 并返回可直接展示的中文错误,杜绝「只吞异常看不到原因」。 class MessageSendService { MessageSendService._(); static final MessageSendService instance = MessageSendService._(); /// 发送消息。成功返回 SDK 回执消息;失败抛出带中文提示的异常。 /// 单聊且非好友时抛 [FriendRequiredException]。 Future send({ required Message message, String? userID, String? groupID, String? offlinePushInfo = '', }) async { final im = IMService.instance; if (!im.loggedIn || im.currentUserID == null) { throw const SendException('登录状态失效,请重新登录'); } if (im.connectStatus != ConnectStatus.success) { throw const SendException('正在重连,请稍后再试'); } final isGroup = groupID != null && groupID.isNotEmpty; final peer = userID ?? ''; if (!isGroup && peer.isEmpty) { throw const SendException('请先添加对方为同事,再发起会话'); } // 单聊:非好友提示先添加(OpenIM 服务端是否拦截交给服务端,但提示要明确) if (!isGroup) { final isFriend = await _isFriend(peer); if (!isFriend) { throw FriendRequiredException('请先添加对方为同事,再发送消息'); } } try { final sent = await OpenIM.iMManager.messageManager.sendMessage( message: message, userID: isGroup ? null : peer, groupID: isGroup ? groupID : null, offlinePushInfo: OfflinePushInfo( title: '畅联', desc: '你收到一条新消息', iOSBadgeCount: true, iOSPushSound: '+1', ), ); return sent; } catch (e) { // 记录原始错误码(不含 token / 消息正文) // ignore: avoid_print print('[MessageSendService] 发送失败 peer=$peer groupID=$groupID err=$e'); throw SendException(_mapError(e)); } } /// 判断 peer 是否已是好友。查询失败按非好友处理(宁可让用户先加好友)。 Future _isFriend(String userID) async { try { final friends = await OpenIM.iMManager.friendshipManager.getFriendList(); return friends.any((f) => (f.userID ?? f.friendUserID) == userID); } catch (_) { return false; } } /// 把 SDK 原始错误映射成中文提示 String _mapError(dynamic e) { final s = e.toString(); // SDK 错误码常量,见 flutter_openim_sdk/lib/src/enum/sdk_error_code.dart if (s.contains('1303')) return '对方还不是你的同事,请先添加对方'; if (s.contains('1304')) return '已经是同事了,可以正常聊天'; if (s.contains('1302')) return '对方已把你加入黑名单,无法发送'; if (s.contains('1101')) return '对方账号不存在'; if (s.contains('1501')) return '登录已过期,请重新登录'; if (s.contains('1502') || s.contains('1503')) return '登录凭证无效,请重新登录'; if (s.contains('10000') || s.contains('10001') || s.contains('网络') || s.contains('timeout')) { return '网络异常,请检查网络后重试'; } return '消息没发出去,请重试'; } } /// 发送失败的中文提示 class SendException implements Exception { final String message; const SendException(this.message); @override String toString() => message; } /// 单聊非好友时的明确提示 class FriendRequiredException extends SendException { const FriendRequiredException(super.message); }