事件与错误处理
Flutter SDK 用事件通知你数据和状态的变化,用 DRException 报告所有的错误。本页列出全部事件和它们的字段、错误对象的结构、全部错误码与处理建议,以及 SDK 在离线和出错时自动做了什么。
大多数界面不需要直接处理数据变化的事件:会话列表、好友列表等 LiveList 和消息列表会自动更新,见在 Flutter 界面中使用。事件主要用于三类场景:登录和连接状态的变化(回到登录页、显示“连接中”),提醒(新消息通知、来电),以及读取同步状态的值(未读总数、正在输入等)时得知何时重新读取。
订阅与取消
事件是 Dart 的 Stream。im.on<T>() 只订阅某一类事件,im.events 是全部事件:
import 'dart:async';
import 'package:deeprespond_im/deeprespond_im.dart';
final StreamSubscription<MessageReceived> sub = im.on<MessageReceived>().listen((e) {
if (e.notify.notify) showToast('${e.message.sender}:新消息');
});
// 不再需要时取消
await sub.cancel();
// 只等一次
final first = await im.on<SyncCompleted>().first;
debugPrint('第一次同步完成:${first.trigger}');- 每个事件是一个类,都继承自
DREvent。DREvent是sealed类,订阅im.events时可以用switch按类型处理(见下文)。 - 两者都是广播流,可以多处同时订阅;订阅之前发出的事件不会补发,需要当前值时先读取一次(见用事件读取同步状态的值)。
- 事件在主 isolate 中发出。监听函数抛出的异常交给当前 Zone 的未捕获错误处理(Flutter 中为
PlatformDispatcher.instance.onError),不影响其他监听函数,也不影响 SDK。 - 数据变化的事件在本地数据更新之后发出,载荷只说明变了什么(如哪些会话变了),你从对应的列表或方法读取最新的数据。
- 同一个变化只发出一次:本人操作的结果和随后服务端的通知会合并,不会收到重复的事件。
- 客户端与进程同生命周期,没有销毁方法;在 Widget 中订阅的,在
dispose()中取消,见在 Flutter 界面中使用。
登录状态和连接状态另有 im.auth.stateStream、im.connection.stateStream,直接给出新的状态,与 AuthStateChanged、ConnectionStateChanged 相同。
一处处理多种事件:
final sub = im.events.listen((event) {
switch (event) {
case AuthStateChanged(state: SessionEnded()):
goToLoginPage();
case ConnectionStateChanged(:final state):
debugPrint('连接状态:${state.kind}');
case StorageFull():
showToast('手机存储空间不足,请清理后重试');
case SdkUpgradeRequired(:final minVersion):
showToast('请升级到 $minVersion 或以上的版本');
default:
}
});全部事件
以下事件类都从 package:deeprespond_im/deeprespond_im.dart 导出。
登录与连接
| 事件 | 字段 | 说明 |
|---|---|---|
AuthStateChanged | state:AuthState | 登录状态变化:SignedIn、SignedOut、SessionEnded(会话结束,带 code、reason)、Suspended(服务暂停),见初始化、登录与连接 |
ConnectionStateChanged | state:DRConnectionState | 连接状态变化:ConnectionIdle、ConnectionConnecting、ConnectionAuthenticating、ConnectionSyncing、ConnectionReady、ConnectionWaiting、ConnectionOffline、ConnectionStopped,kind 为对应的字符串,见初始化、登录与连接 |
SdkUpgradeRequired | minVersion:String | SDK 版本低于服务端要求的最低版本,连接已停止,本地数据只读,写操作以 invalid_state(upgrade_required)拒绝。请提示用户升级 App |
AppLifecycleReported | background:bool;badge:int? | App 切到后台时,SDK 已向服务端报告前后台状态,badge 为报告的角标数(只在 iOS、Android 上发出) |
PushOpened | payload:PushPayload | 用户点击了 IM 的通知;由点击通知冷启动的,在创建客户端后立即发出。需要 deeprespond_im_push,见离线推送 |
同步与本地数据
| 事件 | 字段 | 说明 |
|---|---|---|
SyncCompleted | modules:List<SyncModule>;trigger:SyncTrigger | 一轮同步完成。modules 为这一轮同步的模块(config、me、friends、groups、messages、push、calls、chatrooms、presence);trigger 为同步的起因:login(登录后)、reconnect(重连后)、syncRequired(服务端要求全量同步)、hint(服务端提示有新数据)、foreground(回到前台)、periodic(定期检查)、fallback(长连接不可用时的定期同步) |
SyncFailed | module:SyncModule;error:DRException | 某个模块同步失败,SDK 会自动重试,一般只需记录日志 |
StorageReset | reason:String;droppedMessages:int? | 本地数据已重置。reason:reset_required(服务端要求重置)、schema_downgrade(App 降级到旧版本后,本地数据库删除重建)、corrupted(本地数据库无法打开,删除重建)、reloaded(本地数据已重新加载)。打开着的列表已自动重新读取,你只需重新读取自己另外保存的数据;droppedMessages 为因此丢弃的未发出消息数 |
StorageFull | 无 | 写入本地数据时磁盘已满(10 分钟内最多发出一次)。SDK 已删除本机上其他用户的本地数据;请提示用户清理手机空间,也可以清除图片缓存(DRImageCache.instance.clear()) |
运行配置与本人
| 事件 | 字段 | 说明 |
|---|---|---|
ConfigChanged | config:ClientConfig? | 应用的运行配置变化,与 im.config 相同;退出后为 null |
MeChanged | me:SelfProfile? | 本人资料变化,与 im.users.me() 相同;退出后为 null |
MeMuteChanged | scope:String;muted:bool;expiresAt:DateTime? | 本人被全局禁言或解除禁言(本次连接期间收到的),scope 为 chat、group 或 room |
UsersChanged | usernames:List<String> | 其他用户的资料缓存更新,用 im.users.get() 显示的界面应重新读取 |
DevicesChanged | devices:List<OnlineDevice> | 本人的在线设备变化,与 im.devices.online() 相同 |
DevicesNewLogin | sessionId、deviceName、platform、loginMethod:String;createdAt:DateTime? | 本人在一台新设备上登录,可以提示“你的账号在 XX 上登录” |
会话与消息
| 事件 | 字段 | 说明 |
|---|---|---|
ConversationsChanged | upserted、removed:List<String> | 会话列表中的会话新增、变化或移除,值为会话键 conversationKey |
ConversationsUnreadChanged | total:int;source:String | 未读总数变化,total 与 im.conversations.getUnreadTotal() 相同;source 为 local 或 server |
MessagesChanged | conversationKey:String;upserted、removed:List<int>;pending:List<String>;renamedFrom:String? | 某个会话的消息变化:upserted、removed 为消息的序号,pending 为发送队列中变化的 clientMsgId;renamedFrom 表示这个会话由草稿会话变为正式会话,值为原来的草稿键 |
MessageReceived | message:MessageView;notify:NotifyDecision | 收到别人发来的新消息,用于提醒:notify 说明是否应该提醒(已考虑免打扰、勿扰时段等)。只在实时收到时发出,补齐的历史消息、重连后同步得到的离线期间的消息不发出 |
MessageSendFailed | clientMsgId、conversationKey:String;error:DRException | 一条消息最终发送失败(自动重试已用完,或被服务端拒绝)。消息留在列表中,状态为 failed,可以让用户重发或删除 |
MessageOnline | message:OnlineMessage | 收到只推在线的消息(sendOnline 发出的,如“对方正在操作”的自定义信令),不保存 |
TypingChanged | conversationKey:String;usernames:List<String> | 会话中正在输入的人变化 |
ReceiptsChanged | conversationId:String;seqs:List<int> | 群消息的已读人数变化,用 im.messages.getReceipt() 读取 |
联系人与群组
| 事件 | 字段 | 说明 |
|---|---|---|
FriendsChanged | upserted、removed:List<String> | 好友新增、资料或备注变化、删除,值为用户名 |
BlacklistChanged | upserted、removed:List<String> | 黑名单变化 |
FriendRequestsChanged | lists:List<String>;unreadCount:int | 收到的(received)或发出的(sent)好友申请变化,unreadCount 为未读的收到的申请数 |
GroupsChanged | upserted、removed:List<String> | 我的群列表或群信息变化,值为群 ID |
GroupMembersChanged | groupId:String;usernames:List<String>? | 群成员变化;usernames 为 null 表示整个成员列表变化 |
GroupRequestsChanged | list:String;groupId:String? | 入群请求变化:pending 为某个群待审批的请求(带 groupId),invitations 为本人收到的入群邀请,applications 为本人的入群申请 |
推送设置与在线状态
| 事件 | 字段 | 说明 |
|---|---|---|
PushChanged | settings:bool;mutes:List<MuteTarget> | 推送设置(settings 为 true)或会话免打扰变化,mutes 为免打扰变化了的会话 |
PresenceChanged | items:List<PresenceState>;reset:bool;cleared:List<String> | 订阅的人在线状态变化;reset 为 true 表示本地的在线状态已全部清除(如重新连接后),cleared 为被清除了状态的人 |
PresenceSubscribeFailed | usernames:List<String>;reason:PresenceFailure? | 订阅没有生效的人:denied(没有权限查看)、limitExceeded(超出订阅上限)、presenceDisabled(应用没有开启在线状态) |
音视频
| 事件 | 字段 | 说明 |
|---|---|---|
CallIncoming | call:CallHandle | 来电开始振铃。App 在前台时由你显示来电界面;在后台时由 deeprespond_im_call 显示系统来电界面 |
CallChanged | call:CallHandle;change:CallChange? | 通话的状态、成员等变化;change 为 null 表示由本设备自己的操作或重新同步引起 |
GroupCallChanged | groupId:String;banner:GroupCallBanner? | 群中正在进行的通话变化,用于显示“群通话进行中”的横幅;通话结束时横幅的 status 为 ended,查询到群里没有通话时 banner 为 null |
通话的详细用法见音视频通话。聊天室的消息、成员进出等在进入聊天室得到的对象上订阅,见聊天室。
用事件读取同步状态的值
以下值可以同步读取,变化时发出对应的事件,“订阅事件 + 读取”就能让界面保持最新:
| 读取 | 变化时的事件 |
|---|---|
im.auth.state、im.auth.currentUser | AuthStateChanged |
im.connection.state | ConnectionStateChanged |
im.config | ConfigChanged |
im.users.me() | MeChanged |
im.users.myMute | MeMuteChanged |
im.users.get(username) | UsersChanged |
im.conversations.getUnreadTotal() | ConversationsUnreadChanged |
im.conversations.getTyping(conversationKey) | TypingChanged |
im.friends.get(username)、im.friends.listInfo | FriendsChanged |
im.friends.blacklist.has(username) | BlacklistChanged |
im.friends.requests.unreadCount | FriendRequestsChanged |
im.messages.getReceipt(conversationId, seq) | ReceiptsChanged |
im.push.settings()、im.push.getMute(target) | PushChanged |
im.presence.get(username) | PresenceChanged |
im.devices.online() | DevicesChanged |
im.calls.current、im.calls.incoming | CallIncoming、CallChanged |
im.calls.groupCallBanner(groupId) | GroupCallChanged |
值没有变化时,读取返回同一个对象。登录、退出、切换用户时,这些值也可能变化,对应的事件同样会发出。
import 'package:flutter/material.dart';
/// 显示未读总数的角标。
class UnreadBadge extends StatelessWidget {
const UnreadBadge({super.key, required this.im});
final DRClient im;
@override
Widget build(BuildContext context) => StreamBuilder<ConversationsUnreadChanged>(
stream: im.on<ConversationsUnreadChanged>(),
builder: (context, _) {
final total = im.conversations.getUnreadTotal(); // 每次重建时读取
return total > 0 ? Badge(label: Text('$total')) : const SizedBox.shrink();
},
);
}错误对象
SDK 的所有错误都是 DRException:返回 Future 的方法以它失败,同步方法以它抛出,MessageSendFailed、SyncFailed 等事件中也是它。
try {
await im.groups.leave('g_123');
} on DRException catch (e) {
debugPrint('${e.code} ${e.reason} ${e.details} ${e.status} ${e.requestId} ${e.retryAfter} ${e.source}');
}| 字段 | 类型 | 说明 |
|---|---|---|
code | String | 错误码:服务端返回的错误码,或 SDK 自己的错误码(见下文) |
reason | String? | 原因,即 details['reason'] |
details | Map<String, Object?>? | 服务端返回的 details,原样,不可修改;SDK 自己的错误中为补充信息 |
status | int? | HTTP 状态码;长连接的错误和 SDK 自己的错误没有 |
requestId | String? | 服务端的 request_id,联系技术支持时提供 |
retryAfter | int? | 建议的等待时间,单位为秒 |
source | ErrorSource | 错误的来源:ErrorSource.http(HTTP 请求)、ErrorSource.ws(长连接)、ErrorSource.local(SDK 本地) |
message | String | 调试用的说明,不要直接显示给用户,提示文字见显示错误提示 |
cause | Object? | 引起这个错误的原始异常(如 SocketException),只用于排查 |
请按 code 和 reason 判断错误,不要按 status 或 message 判断。SDK 自己的错误码有常量,见 LocalErrorCode(如 LocalErrorCode.networkError)。
与服务端错误码的关系
服务端返回的错误原样交给你,code、details 与服务端文档相同,source 为 http 或 ws。各错误码的含义和 details 的取值见服务端的错误码,客户端特有的错误码(如 user_muted、group_muted、not_friend、user_blocked)见其中的控制台和客户端接口的错误码。
SDK 在发出请求之前先在本地检查,确定会被服务端拒绝的直接拒绝,source 为 local:
- 功能没有开启、没有权限的(如应用没有开启群已读回执、普通成员 @所有人),沿用服务端的
permission_denied和原因,如read_ack_disabled、mention_all_denied、presence_disabled; - 超出服务端的固定频率限制的(如“全部已读”每分钟 2 次),沿用
rate_limited,带retryAfter; - 参数和内容不合规的(大小、格式、必填字段、不支持的字符等),一律为
local_validation,details['reason']和details['field']说明原因。local_validation总是表示请求没有发出。
这样你对“功能不可用、没有权限”和“太频繁”只需按服务端的错误码处理一次。
SDK 自己的错误码
code | 常量 | 含义 | 建议 |
|---|---|---|---|
network_error | networkError | 网络不可用或请求没有送达 | 提示检查网络,稍后重试 |
timeout | timeout | 请求超时 | 稍后重试;写操作先确认结果,见离线与重试 |
aborted | aborted | 被你用 DRCancelToken 或 cancel() 取消 | 不提示 |
not_signed_in | notSignedIn | 未登录时调用了需要登录的方法 | 先登录 |
not_connected | notConnected | 必须走长连接的操作(如聊天室的部分操作)在未连接时调用 | 等连接就绪后再试 |
local_validation | localValidation | 本地检查不通过,请求没有发出。reason 为原因(如 required、too_large、control_characters、url_not_allowed),details['field'] 为字段 | 提示用户修改 |
storage_error | storageError | 读写本地数据出错;reason 为 quota_exceeded 时是磁盘已满(同时发出 StorageFull) | 提示清理手机空间,或重新打开 App |
unsupported | unsupported | 当前平台或部署不支持:reason 为 media_disabled(没有开通文件服务)、platform(如桌面端录音)、sqlcipher_required(开启了 encryptDatabase,但 App 没有使用 SQLCipher 构建)、chatroom_attachment(聊天室不能发送文件)等 | 隐藏对应的功能,或修正配置 |
permission_required | permissionRequired | 用户没有授权使用麦克风或摄像头,details['permissions'] 列出缺少的权限(microphone、camera) | 引导用户在系统设置中授权 |
device_error | deviceError | 麦克风或摄像头不存在、被占用或出错,details['device'] 为 microphone 或 camera(通话中),reason 说明原因 | 提示检查设备 |
invalid_state | invalidState | 当前状态下不能调用,reason 说明原因:disposed(列表已释放)、signed_in(不能清除当前用户的本地数据)、upgrade_required(SDK 版本过低,本地数据只读)、recording、not_recording(录音的状态不对)等 | 一般是调用顺序的问题,检查代码 |
send_abandoned | sendAbandoned | SDK 放弃发送一条消息:reason 为 attachment_lost(附件已丢失:超过 OutboxOptions.persistAttachmentMaxBytes(默认 200 MB)的附件不复制,原文件在发出前被删除或移动)或 expired(超过 OutboxOptions.maxAge,默认 48 小时没有发出) | 提示用户重新发送 |
local_validation 的原因
local_validation 的 details['reason'](即 reason)说明哪里不合规,details['field'] 为字段名(如 body.text、username):
reason | 含义 |
|---|---|
required | 必填的参数或字段为空 |
invalid_format | 格式不对,如 appKey、apiUrl、client_msg_id |
invalid_value | 取值不在允许的范围内,或文件不存在 |
invalid_type | 参数的类型不对 |
out_of_range | 数值超出范围 |
too_long | 文字太长 |
too_large | 内容或文件太大,如消息超过运行配置的 max_message_body_bytes、附件超过 max_upload_bytes |
too_many_items | 一次传入的项目太多,如一次删除超过 100 条消息 |
control_characters | 文字中有不支持的控制字符(只有文本消息的正文允许换行、回车和制表符) |
invalid_body、unknown_type | 消息内容不符合消息类型的要求;不支持的消息类型 |
mentions_not_allowed、receipt_not_allowed | @ 提及、群已读回执只能用于群聊 |
url_not_allowed | 应用开启了只接受本服务的文件地址,这个地址不符合要求 |
invalid_purpose | 这种文件不能用于这里(如用视频作头像) |
image_too_large、unsupported_type | 文件不能按请求的类型上传,见文件与图片 |
invalid_ext、invalid_priority、invalid_attribute_value、attributes_too_large | 聊天室的扩展信息、消息优先级、属性不符合要求 |
too_many_invitees | 一次邀请通话的人太多 |
invalid_evidence、self_report | 举报的证据消息不符合要求;不能举报自己 |
not_found | 本地找不到要操作的会话、消息或文件(如重发一条已不在发送队列中的消息) |
describeError 对其中常见的原因给出了专门的提示,其余显示“内容不符合要求”。
常见的服务端错误码
code | 含义 | 建议 |
|---|---|---|
invalid_argument | 参数不符合服务端的规则 | 提示用户修改;reason 说明原因 |
unauthenticated、session_revoked | 登录失效 | SDK 已自动处理(续期或结束会话),你只需处理 AuthStateChanged 中的 SessionEnded |
invalid_credentials | 用户名、密码或凭证错误 | 见初始化、登录与连接 |
permission_denied | 没有权限,或功能没有开启,reason 说明原因 | 按原因提示,或隐藏对应的功能 |
not_found | 用户、群、会话、消息等不存在或已删除 | 提示“内容不存在或已删除” |
already_exists | 要创建的已存在 | 视为成功或提示 |
version_conflict | 数据已被修改 | 重新读取后再提交 |
limit_exceeded | 超出数量上限,reason 说明是哪一项 | 提示已达上限 |
payload_too_large | 内容或文件太大 | 提示用户缩短内容或换小一些的文件 |
rate_limited | 操作太频繁 | 按 retryAfter 稍后再试;SDK 已对可以安全重试的请求自动等待重试 |
too_many_attempts | 密码错误次数过多 | 按 retryAfter 提示稍后再试 |
message_rejected、content_rejected | 消息或资料没有通过内容安全检查 | 提示用户修改内容;reason 为 app_rejected 时,message 是你的服务端给出的提示,可以直接显示 |
user_muted、group_muted | 本人被全局禁言、在群中被禁言或群开启了全员禁言 | 提示禁言,details['expires_at'] 为到期时间 |
user_blocked | 被对方拉黑 | 提示“对方拒收了你的消息” |
not_friend | 应用要求只能给好友发消息,双方不是好友 | 提示先加好友 |
not_group_member | 本人已不在群中 | 提示并刷新界面 |
tenant_unavailable、app_unavailable | 服务暂停或只读 | 提示“服务暂时不可用”,SDK 进入 Suspended 状态,恢复后自动继续 |
internal | 服务端故障 | 稍后重试,持续出现时带上 requestId 联系技术支持 |
显示错误提示
package:deeprespond_im/render.dart 中的 describeError 按 code 和 reason 给出中文的提示文字,如“发送太频繁,请稍后再试”“群主已开启全员禁言”“你已被禁言,至 10 月 5 日 18:00”:
import 'package:deeprespond_im/render.dart';
im.on<MessageSendFailed>().listen((e) => showToast(describeError(e.error)));
try {
await im.friends.requests.send(username: 'lisi', message: '你好');
} on DRException catch (e) {
showToast(describeError(e));
}查找顺序为先找 code.reason(如 permission_denied.mention_all_denied),再找 code,都没有时显示通用的“服务器繁忙,请稍后重试”。例外:message_rejected、permission_denied 的原因为 app_rejected 时,显示服务端返回的 message(你的服务端给出的提示)。禁言(user_muted)带到期时间的,按本地时间显示到期时间。
要修改部分文案,或换成其他语言,传入 locale。内置的中文文案是 zhCN,用 copyWith 替换其中的条目,文案表 errors 的键就是上面说的 code 或 code.reason,没给的键沿用原来的:
import 'package:deeprespond_im/render.dart';
final myLocale = zhCN.copyWith(errors: {
'rate_limited': '手速太快啦,休息一下',
'permission_denied.mention_all_denied': '只有管理员可以 @所有人',
});
showToast(describeError(err, locale: myLocale));
debugPrint('${zhCN.errors.keys}'); // 内置的全部条目会话结束(SessionEnded)的原因也可以这样显示:describeError(DRException(code: ended.code, details: {'reason': ended.reason}, source: ErrorSource.http))。
离线与重试
SDK 按错误的类型自动处理,你只需处理最终返回的错误:
| 类别 | 错误码 | SDK 的处理 |
|---|---|---|
| 登录失效 | unauthenticated、session_revoked | 令牌过期的自动续期并重发一次请求;会话被吊销的结束会话(SessionEnded) |
| 服务暂停或只读 | tenant_unavailable、app_unavailable | 返回给你;确认是服务暂停的,进入 Suspended 状态,恢复后自动继续 |
| 限流 | rate_limited、too_many_attempts | 等待时间不超过 60 秒的,等待后自动重试;更长的返回给你。发送好友申请、建群、邀请入群、申请入群、发起和邀请通话、举报、聊天室发消息,以及 too_many_attempts,不自动重试 |
| 暂时故障 | network_error、timeout、internal、HTTP 5xx | 可以安全重发的请求(查询、带幂等键的写操作、本身幂等的操作如标记已读)按退避自动重试,最多 3 次;其他写操作不自动重试,返回给你 |
| 需要用户处理 | 其余错误码 | 返回给你,按 code 和 details 提示 |
消息的发送另有发送队列:
im.messages.send()把消息写入发送队列后就返回,之后由 SDK 发送。断网时消息在队列中等待,网络恢复后自动发出;App 被杀后,下次启动并登录时继续发送。- 发送遇到网络错误、超时、服务端故障时,按 1、2、4、8、16、30 秒的间隔重试,网络可用的时间累计 2 分钟仍未成功的标为失败;被限流的按服务端给出的时间等待后重试。
- 被服务端拒绝(如被禁言、被拉黑、内容未通过审核)的立即标为失败。
- 失败时消息状态变为
failed,并发出MessageSendFailed。可以调用im.messages.resend(clientMsgId)重发,或im.messages.discard(clientMsgId)删除,见消息。 - 同一条消息重试时使用同一个
client_msg_id,服务端据此去重,不会发出两条。
没有自动重试的写操作(如建群、发送好友申请、修改群资料)遇到 network_error、timeout 时,请求可能已经执行。请先查询结果(如重新读取群列表),确认没有生效再让用户重试。
离线时:本地数据照常可读,界面可以继续显示;会话和消息的操作中只修改本地的(如草稿)立即生效,需要请求服务端的在自动重试后返回 network_error,发送消息进入发送队列。连接状态为 ConnectionOffline 或 ConnectionWaiting,网络恢复(包括在 Wi-Fi 与移动网络之间切换)后 SDK 自动重连并同步离线期间的变化。
接口参考
im.events
全部事件。
类型:Stream<DREvent>,广播流。
im.on()
按类型订阅事件,如 im.on<MessageReceived>()。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
T | extends DREvent | 是(类型参数) | 事件的类型,见全部事件 |
返回值:Stream<T>,广播流。用 listen 订阅,返回的 StreamSubscription 的 cancel() 取消订阅;只要一次时用 first。
im.auth.stateStream、im.connection.stateStream
登录状态、连接状态的变化。
类型:Stream<AuthState>、Stream<DRConnectionState>,广播流,只发出订阅之后的变化;当前的值用 im.auth.state、im.connection.state 读取。
describeError()
从 package:deeprespond_im/render.dart 导入。按错误码给出提示文字。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
err | DRException | 是 | 错误 |
locale | DRLocale | 否(命名参数) | 文案,默认 zhCN |
返回值:String。
formatTemplate()
从 package:deeprespond_im/render.dart 导入。填入文案中的占位符 {name},没有给出的占位符原样保留。自己编写含占位符的文案时可以用它。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
template | String | 是 | 文案,如 '你已被禁言,至 {time}' |
values | Map<String, String> | 是 | 占位符的值 |
返回值:String。
数据结构
DRException
实现 Exception,字段见错误对象。另有:
| 成员 | 说明 |
|---|---|
DRException({required code, message, details, status, requestId, retryAfter, required source, cause}) | 构造函数;message 省略时与 code 相同 |
toJson() | 转为 Map(不含 cause),可以经 isolate 端口传递或写入日志 |
DRException.fromJson(json) | 静态方法,从 toJson() 的结果还原 |
ErrorSource
枚举:http、ws、local。
LocalErrorCode
SDK 自己的错误码的常量:networkError、timeout、aborted、notSignedIn、notConnected、localValidation、storageError、unsupported、permissionRequired、deviceError、invalidState、sendAbandoned,以及本地照搬服务端的 permissionDenied、rateLimited。值为对应的字符串,如 LocalErrorCode.networkError 为 'network_error'。
DREvent
全部事件的基类(sealed),各事件的字段见全部事件。
NotifyDecision
MessageReceived 的 notify,说明这条消息是否应该提醒。
| 字段 | 类型 | 说明 |
|---|---|---|
notify | bool | 是否应该提醒 |
title | String? | 通知的标题,按推送设置的预览方式生成 |
body | String? | 通知的内容 |
reason | String? | 不提醒的原因:dnd(勿扰中)、quiet_hours(勿扰时段)、muted(会话免打扰)、not_mentioned(免打扰为只在 @ 本人时提醒,而这条没有 @ 本人)、excluded(消息不计未读)、self(本人发的)、tip(群提示)、call(通话记录)、not_loaded(推送设置还没有加载) |
提醒的完整用法见提醒、免打扰与举报。
DRLocale
提示文案的表,zhCN 为内置的中文文案。
| 字段 | 类型 | 说明 |
|---|---|---|
errors | Map<String, String> | 错误的提示,键为 code 或 code.reason |
mutedUntil | String | 带到期时间的禁言提示,占位符 {time} |
deletedUser、unnamedGroup、system、you | String | 已删除的用户、没有名称的群、系统、“你”的显示名称 |
summary | Map<String, String> | 会话列表中最后一条消息的摘要 |
recall | Map<String, String> | 撤回提示 |
tip | Map<String, String> | 群提示 |
call | Map<String, String> | 通话记录 |
copyWith(...) 替换其中的条目:各个表按键合并,没给的键沿用原来的。后四项用于会话和消息的显示,见会话和消息。
ChannelChanged 与频道流
ChannelChanged 的 channel 为当前 ChannelHandle 或 null。持续展示使用 channel.stream 快照流和 channel.tracks 完整授权轨道流,均先回放当前值;不要把一次事件当作完整成员状态。示例及退出处理见独立频道。
