群組
群組(下文簡稱群)有固定的成員,適合同事群、家長群、興趣群等場景。使用者可以在客戶端建群、邀請他人、申請加入公開群、透過入群連結加入;群主和管理員可以修改群資料、管理成員、審批入群申請。
Flutter SDK 把“我的群”和讀取過的群成員列表儲存在本地資料庫中,以可訂閱的列表(LiveList)提供:登入、重連、回到前臺後自動同步,其他成員和其他裝置上的變化實時反映到列表中,App 重新啟動後不必重新獲取。入群申請、邀請這類只需要翻頁檢視的資料按頁查詢。
本頁介紹群本身和成員的操作。傳送群訊息見訊息(目標寫成 SendTarget.group(groupId)),群檔案見檔案與圖片。群的概念(型別、角色、設定、狀態)與服務端相同,完整的規則見服務端的群組管理。
| 要做什麼 | 看哪裡 |
|---|---|
| 建群、顯示“我的群” | 建群、我的群 |
| 改群名、公告、頭像 | 修改群資料和設定 |
| 顯示成員、邀請和移出成員 | 成員列表、邀請成員、移出成員 |
| 設管理員、禁言、群黑名單 | 設定管理員、禁言、群黑名單 |
| 讓使用者搜尋並申請加入公開群,審批申請 | 公開群與入群申請 |
| 處理別人發來的入群邀請 | 被邀請時是否需要確認 |
| 用連結或二維碼拉人 | 入群連結 |
| 退群、解散、轉讓群主 | 退出與解散、轉讓群主 |
基本概念
群型別
GroupType | 說明 |
|---|---|
private | 私有群,預設。只能由成員邀請、透過入群連結加入或由你的服務端新增;非成員看不到這個群,對它的任何操作都得到 not_found |
public | 公開群。使用者可以搜尋到它,看到名稱、頭像、簡介和人數,並申請加入 |
角色與許可權
| 操作 | 群主 owner | 管理員 admin | 普通成員 member |
|---|---|---|---|
| 修改群資料和設定 | 可以 | 可以(群型別除外) | 不可以 |
| 邀請他人 | 可以 | 可以 | 按群設定 member_invite |
| 移出、禁言成員,管理群黑名單 | 可以 | 只能處理普通成員 | 不可以 |
| 開啟全員禁言,審批入群申請,生成入群連結 | 可以 | 可以 | 不可以 |
| 設定管理員、轉讓群主、解散群 | 可以 | 不可以 | 不可以 |
| 修改自己的群暱稱 | 可以 | 可以 | 可以 |
角色在 Dart 中是列舉 GroupRole(owner、admin、member)。每個群最多 20 個管理員。群主不能被移出、禁言或加入群黑名單;群主要退出,須先轉讓群主。
群設定
| 設定 | Dart 列舉 | 取值 | 說明 |
|---|---|---|---|
member_invite | MemberInvite | free(預設)、approval、disabled | 普通成員能否邀請他人:直接邀請、邀請後要群主或管理員審批、不能邀請 |
join_mode | JoinMode | approval(預設)、free | 公開群的申請方式:需要審批、申請即加入。私有群為 null,不能設定 |
mute_all | — | true、false | 全員禁言,開啟後只有群主和管理員可以發言 |
max_members | — | 只讀 | 群的人數上限,只能由你的服務端或控制檯設定 |
讀取群資訊時這些設定是字串(如 group.memberInvite == 'approval'),修改時傳列舉。
建群
使用者在客戶端建群時自己是群主,可以同時邀請初始成員(最多 100 人)。初始成員按邀請的規則處理:對方的入群設定為需要確認時,他收到一條邀請,接受後才入群。
import 'package:deeprespond_im_flutter/deeprespond_im_flutter.dart';
final group = await im.groups.create(
name: '产品研发群',
type: GroupType.private,
description: '产品和研发日常沟通',
members: ['lisi', 'wangwu', 'zhaoliu'],
message: '拉你进项目群', // 给需要确认的被邀请人看的附言
);
for (final r in group.results) {
if (!r.ok) {
print('${r.username} 没有加入:${r.code}');
} else if (r.status == 'invited') {
print('${r.username} 需要确认后入群');
}
}- 返回值是
CreateGroupResult:新群的全部資訊,另加results,按請求的順序列出每個初始成員的結果。初始成員加入失敗不影響建群。 - 新群隨即出現在“我的群”列表中。
- 應用在執行策略中關閉了客戶端建群時,以
permission_denied拒絕。可以先讀取im.config?.clientGroupCreateEnabled決定是否顯示建群入口。 - 本人加入的群數已滿時以
limit_exceeded(details['reason']為user_group_limit)拒絕,不建群;應用的群數已達套餐的上限時為app_group_limit。 - 群名稱、簡介、公告、頭像要經過內容安全檢查,不透過時以
content_rejected拒絕,details['field']為欄位名。
建群不會自動重試
網路錯誤或超時後,SDK 先重新整理本人的群列表:找到這次新建的群(群主是本人、建立時間在這次呼叫之後)的按成功返回,這時 results 為空列表,可以用 members() 檢視實際入群的人;找不到的以 timeout 拒絕,由使用者決定是否再建。遇到 rate_limited 時請提示使用者,不要自動重試。
我的群
im.groups.list() 返回本人加入的全部群的可訂閱列表,每項為 GroupView,按群名排序。登入後 SDK 自動同步;建群、入群、退群、被移出、群解散,以及群資料的變化都會反映到列表中。列表不再顯示時呼叫 dispose()。
import 'package:deeprespond_im_flutter/deeprespond_im_flutter.dart';
import 'package:flutter/material.dart';
class MyGroupsPage extends StatefulWidget {
const MyGroupsPage({super.key, required this.im});
final DRClient im;
@override
State<MyGroupsPage> createState() => _MyGroupsPageState();
}
class _MyGroupsPageState extends State<MyGroupsPage> {
late final LiveList<GroupView> _groups = widget.im.groups.list();
@override
void dispose() {
_groups.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) => LiveListBuilder<GroupView>(
list: _groups,
builder: (context, snapshot) => ListView(
children: [
for (final g in snapshot.items)
ListTile(
title: Text(g.group.name.isNotEmpty ? g.group.name : '群聊'),
trailing: Text('${g.group.memberCount}'),
),
],
),
);
}本人在群裡的角色、群暱稱和禁言狀態在 group.self 中:
final view = await im.groups.get('1840012345678901');
final self = view?.group.self;
final canManage = self?.role == GroupRole.owner || self?.role == GroupRole.admin;im.groups.get(groupId)先讀本地,本地有就直接返回;本地沒有(如別人分享的公開群)或refresh: true時向服務端查詢。看不到的群(不存在、本人不是成員的私有群)返回null。- 已離開的群
inMyGroups為false,group為離開前最後一次的資訊,會話列表仍可以用它顯示群名和頭像。 - 一次查詢多個群用
im.groups.lookup(groupIds)(最多 100 個),本人不是成員的公開群只返回公開的欄位,看不到的群不在結果中。
群資料和我的群列表的變化以 GroupsChanged 事件通知,upserted 為新增或變化的群,removed 為離開了“我的群”的群:
im.on<GroupsChanged>().listen((e) {
print('变化的群:${e.upserted},离开的群:${e.removed}');
});修改群資料和設定
群主和管理員可以修改群資料和設定,只提交傳入的引數。群型別只有群主能改。修改後群的線上成員收到變化,本地的群資訊隨之更新。
await im.groups.update(
'1840012345678901',
name: '产品研发群(2 期)',
announcement: '本周五发布 2.3 版本',
attributes: {'project_id': 'P-1024', 'old_key': null}, // 按项合并,null 删除这个键
memberInvite: MemberInvite.approval,
);- 公開群改為私有群時,尚未處理的入群申請全部失效;私有群改為公開群時,申請方式預設為需要審批。
- 為私有群設定
joinMode以invalid_argument拒絕。 - 自定義屬性全體成員可見,按項合併;
clearAttributes: true清空全部。 - 多人可能同時修改時,帶上讀取到的
group.infoVersion作為version,群資料已被別人修改時以version_conflict拒絕,不做任何修改。 - 修改的名稱、簡介、公告、頭像要經過內容安全檢查,不透過時以
content_rejected拒絕。 - 群被封禁時以
group_disabled拒絕。
設定群頭像
群頭像要先以用途 group_avatar 上傳,得到公開地址後再寫入群資料(建群前就可以上傳):
Future<void> changeGroupAvatar(String groupId, String path) async {
final info = await im.files.upload(DRFile(path), purpose: UploadPurpose.groupAvatar).result;
await im.groups.update(groupId, avatarUrl: info.url);
}成員列表
im.groups.members(groupId) 返回群成員的可訂閱列表(LiveList<GroupMember>),按群主、管理員、普通成員排列,同一角色按入群時間排列。只有成員可以檢視。
final members = im.groups.members(groupId);
final sub = members.stream.listen((s) {
if (s.error != null) {
showToast('成员列表加载失败:${s.error!.code}');
} else if (!s.loading) {
print(s.items.map((m) => m.groupNickname.isNotEmpty ? m.groupNickname : (m.nickname.isNotEmpty ? m.nickname : m.username)));
}
});
// 只看管理员、只看被禁言的成员
final admins = im.groups.members(groupId, role: GroupRole.admin);
final muted = im.groups.members(groupId, muted: true);
// 页面关闭时
await sub.cancel();
members.dispose();
admins.dispose();
muted.dispose();- 第一次開啟某個群的成員列表時,SDK 獲取全部成員並儲存在本地;之後再開啟時只檢查是否有變化,App 重新啟動後同樣有效。篩選在本地進行。
- 成員的加入、離開,角色、群暱稱、禁言的變化實時反映到列表中,同時發出
GroupMembersChanged。 - 列表不再顯示時呼叫
dispose()。在 Widget 中用LiveListBuilder顯示,寫法同我的群。
只需要顯示少數人的群暱稱(如訊息傳送者)時,不必取整個成員列表,用 lookupMembers(最多 100 人,不是成員的不在結果中):
final found = await im.groups.lookupMembers(groupId, ['lisi', 'wangwu']);顯示名字時可以用 package:deeprespond_im_flutter/render.dart 中的 displayName(im, username, groupId: groupId),它按好友備註、群暱稱、暱稱、使用者名稱的順序取第一個非空的,見使用者、好友與線上狀態。
群的線上人數(需要應用開啟線上狀態且 presence_scope 為 all,否則在本地以 permission_denied 拒絕):
final count = await im.groups.onlineCount(groupId);
print('${count.onlineCount} 人在线');同一個群 30 秒內重複查詢直接返回上一次的結果。
邀請成員
一次最多邀請 100 人,可以帶附言。結果按請求的順序逐個給出,某個人失敗不影響其他人:
final results = await im.groups.invite(groupId, ['sunqi', 'zhouba'], message: '欢迎加入');
for (final r in results) {
if (!r.ok) showToast('${r.username}:${r.code}');
}成功的 status:
status | 說明 |
|---|---|
joined | 已入群 |
invited | 對方需要確認,已發出邀請,見被邀請時是否需要確認 |
pending_review | 本人是普通成員且群設定為邀請需要審批,等待群主或管理員審批 |
already_member | 原本就是成員 |
失敗的項 ok 為 false,帶 code,常見的有:
code | 原因 |
|---|---|
permission_denied | 對方在群黑名單中(details['reason'] 為 group_blacklisted),或被你的服務端透過加群前回撥拒絕 |
limit_exceeded | 群已滿(group_member_limit),或對方加入的群數已滿(user_group_limit) |
user_blocked | 對方把本人拉黑了 |
not_friend | 應用只允許邀請好友 |
rate_limited | declined_cooldown:開啟了邀請冷卻,對方 24 小時內拒絕過這個群的邀請或退出了這個群;request_rate、group_join_rate:邀請或入群過於頻繁 |
not_found | 使用者不存在 |
邀請冷卻(group_invite_cooldown_enabled)在控制檯的群組執行策略中設定:
- 預設關閉:對方退群或拒絕邀請後,可以立即再次邀請。
- 開啟後:對方退群或拒絕邀請後 24 小時內,這個群不能再邀請他。
- 冷卻只限制邀請。服務端直接新增、本人申請、入群連結不受影響;本人確認、管理員審批這些條件照常適用。
- 與此無關:入群申請被拒絕後,申請人 24 小時內不能再申請,這條始終生效。
呼叫沒有丟擲異常不代表所有人已入群,應逐項檢查 results,分別提示已入群、等待本人確認、等待管理員審批或失敗原因。
整個請求失敗的情況:普通成員在 member_invite 為 disabled 的群裡邀請(permission_denied),群被封禁(group_disabled)。
移出成員
群主和管理員可以移出成員(管理員只能移出普通成員),一次最多 100 人。結果中 removed 為已移出,not_member 為原本就不是成員。不能用它移出自己,請用退出群。
await im.groups.removeMembers(groupId, ['zhouba']);設定管理員
群主可以把成員設為管理員或取消管理員,每個群最多 20 個管理員(超出以 limit_exceeded 拒絕,details['reason'] 為 admin_limit)。
await im.groups.setRole(groupId, 'lisi', GroupRole.admin);
await im.groups.setRole(groupId, 'lisi', GroupRole.member); // 取消管理员群暱稱與成員屬性
每個成員可以修改自己的群暱稱;群主和管理員也可以修改級別比自己低的成員的群暱稱和成員屬性。成員屬性按項合併,值為 null 的鍵被刪除,clearAttributes: true 清空全部。
final me = im.auth.currentUser!.username;
await im.groups.updateMember(groupId, me, groupNickname: '李四-研发');
await im.groups.updateMember(groupId, 'wangwu', attributes: {'title': '后端'});群暱稱最長 64 個字元,傳空字串表示清除;要經過內容安全檢查。
禁言
禁言成員
群主和管理員可以禁言成員(管理員只能禁言普通成員),省略時長為永久禁言。被禁言的成員傳送群訊息時得到 group_muted(details['reason'] 為 member)。
await im.groups.mute(groupId, 'zhouba', durationSeconds: 3600); // 禁言 1 小时
await im.groups.unmute(groupId, 'zhouba');時長為 1 到 315360000 秒(10 年)。本人是否被禁言在 group.self 的 muted 和 mutedUntil 中,可以據此禁用輸入框。
全員禁言
開啟後只有群主和管理員可以發言,普通成員傳送群訊息時得到 group_muted(details['reason'] 為 all)。被單獨禁言的管理員仍然不能發言。
await im.groups.setMuteAll(groupId, true);
await im.groups.setMuteAll(groupId, false);群黑名單
被加入群黑名單的使用者被移出群(如果在群裡),之後不能再申請、被邀請或透過入群連結加入這個群。群主和管理員可以管理群黑名單;管理員只能移出由管理員加入的記錄。每個群最多 1000 人。
await im.groups.blacklist.add(groupId, 'spammer', reason: '发广告');
final page = await im.groups.blacklist.list(groupId, limit: 50);
for (final e in page.items) {
print('${e.username}:${e.reason ?? ''}');
}
await im.groups.blacklist.remove(groupId, 'spammer');列表的每項為 GroupBlacklistEntry。群黑名單隻影響本群,與使用者之間的黑名單無關。
公開群與入群申請
搜尋公開群
im.groups.publicGroups() 按建立時間從新到舊列出公開群,可以按名稱字首搜尋。每項只有公開的欄位(groupId、type、name、avatarUrl、description、memberCount、joinMode、status),self 為本人在群裡的資訊,不是成員時為 null。
final page = await im.groups.publicGroups(namePrefix: '摄影', limit: 20);
for (final g in page.items) {
print('${g.name}(${g.memberCount} 人)${g.self != null ? ' 已加入' : ''}');
}
// 下一页:im.groups.publicGroups(namePrefix: '摄影', cursor: page.nextCursor)申請加入
final status = await im.groups.applications.apply(groupId, message: '我也喜欢摄影');
if (status == 'joined') {
showToast('已加入');
} else if (status == 'pending') {
showToast('已提交申请,等待群主或管理员审批');
}群的申請方式為 free 時直接入群;為 approval 時產生一條待審批的申請,任意一位群主或管理員同意後入群。申請理由最長 256 個字元。申請被拒絕後 24 小時內不能再申請這個群(rate_limited,details['reason'] 為 declined_cooldown),同一個人對同一個群每天最多申請 5 次(pair_daily_limit)。私有群不能申請,得到 not_found;本人在群黑名單中得到 permission_denied(group_blacklisted)。
撤回待處理的申請,檢視本人發出的申請:
await im.groups.applications.withdraw(groupId);
final mine = await im.groups.applications.mine();申請已被處理時 withdraw 以 version_conflict 拒絕,details['status'] 為申請當前的狀態。
審批申請和成員的邀請
群主和管理員用 im.groups.requests 檢視和處理本群的請求。請求按“群 + 型別 + 使用者名稱”定位,沒有單獨的 ID。請求的型別 GroupRequestKind:
GroupRequestKind | 服務端的取值 | 說明 | 由誰處理 |
|---|---|---|---|
application | application | 使用者申請加入公開群 | 群主或管理員 |
inviteReview | invite_review | 普通成員在需要審批的群裡發出的邀請 | 群主或管理員 |
invitation | invitation | 等待被邀請人確認的邀請 | 被邀請人,見下一節 |
final page = await im.groups.requests.list(groupId, kind: GroupRequestKind.application, status: GroupRequestStatus.pending);
for (final r in page.items) {
print('${r.nickname.isNotEmpty ? r.nickname : r.username} 申请加入:${r.message ?? ''}');
}
final result = await im.groups.requests.approve(groupId, GroupRequestKind.application, 'sunqi');
await im.groups.requests.decline(groupId, GroupRequestKind.application, 'zhouba', reason: '仅限本校学生');approve的返回值:joined已入群;invited成員的邀請審批透過、被邀請人需要確認,已向他發出邀請;canceled被邀請人已不能接收這個群的邀請,請求失效。- 處理時會重新檢查入群條件(群正常、不在群黑名單中、人數和群數未滿),不滿足時以對應的錯誤拒絕,請求保持待處理,條件滿足後可以再次處理。
- 請求已被別人處理時以
version_conflict拒絕,details['status']為請求當前的狀態;已過期或不存在時以not_found拒絕。 - 拒絕的理由最長 256 個字元,展示給申請人或邀請人。拒絕申請後,申請人 24 小時內不能再申請。
- 普通成員呼叫
requests.list()只能看到自己發出的邀請。邀請人、群主和管理員可以用requests.withdrawInvite(groupId, kind, username)撤回待處理的邀請(kind為inviteReview或invitation)。
新的請求到達、請求被處理時發出 GroupRequestsChanged(list 為 pending,groupId 為這個群),可以據此重新整理審批頁面或顯示紅點:
im.on<GroupRequestsChanged>().listen((e) {
if (e.list == 'pending') print('群 ${e.groupId} 有新的待审批请求');
});待處理的請求在最近一次發起後 7 天未處理即過期。完整規則見服務端的入群申請與邀請。
被邀請時是否需要確認
每個使用者可以設定別人邀請自己入群時怎樣處理:InviteMode.allowAny(allow_any)直接入群,InviteMode.needConfirm(need_confirm)收到一條邀請、接受後才入群。沒有設定過時使用應用執行策略中的預設值(預設 allow_any)。
final settings = await im.groups.settings.get();
print(settings.inviteMode == null ? '跟随应用默认(${settings.effectiveInviteMode?.wire})' : settings.inviteMode!.wire);
await im.groups.settings.set(InviteMode.needConfirm);
await im.groups.settings.set(null); // 清除本人的设置,改用应用的默认值處理收到的邀請
final page = await im.groups.invitations.received(status: GroupRequestStatus.pending);
for (final inv in page.items) {
final inviter = inv.inviter?.nickname ?? '有人';
print('$inviter 邀请你加入 ${inv.group?.name ?? '群聊'}');
}
final group = await im.groups.invitations.accept('1840012345678901');
await im.groups.invitations.decline('1840099999999999', reason: '暂时不参加');invitations.received()和applications.mine()不帶cursor和status時返回 SDK 記憶體中的第一頁,不發請求;SDK 在登入、重連和收到相關通知時重新整理這一頁,重新整理後發出GroupRequestsChanged(list為invitations或applications)。- 接受後入群,返回群資訊,群隨即出現在“我的群”中。本人已經透過其他途徑入群的同樣返回群資訊。
- 拒絕後預設可立即再次收到邀請;僅在應用開啟邀請冷卻時,24 小時內這個群不能再邀請本人。
入群連結
群主和管理員可以生成入群連結,私有群也可以。使用者開啟連結後確認即可直接入群,不需要審批。每個群同時只有一個有效連結,重新生成或撤銷後舊連結立即失效;生成連結的人不再是群主或管理員時,連結也隨之失效。連結可以展示為二維碼。
final created = await im.groups.joinLink.create(groupId, expiresInSeconds: 86400);
print(created.link);
final current = await im.groups.joinLink.get(groupId); // 没有有效链接时三项都为 null
await im.groups.joinLink.revoke(groupId);有效期為 86400 到 604800 秒(1 到 7 天),預設 7 天。
開啟連結的一方(如掃碼後)先預覽,再確認加入:
final preview = await im.groups.joinLink.preview(link);
if (preview.isMember) {
showToast('你已在群中');
} else {
final group = await im.groups.joinLink.join(link);
print(group.name);
}連結無效、過期、已撤銷,或群已封禁、已解散時,preview 和 join 都以 not_found 拒絕。已是成員時 join 直接返回群資訊。預覽和加入合計按使用者每分鐘 20 次限流。
退出與解散
await im.groups.leave(groupId); // 退出群
await im.groups.dismiss(groupId); // 解散群,只有群主可以- 退出:退出後群從“我的群”中移除,本地的成員列表隨之刪除。群主退出以
owner_transfer_required拒絕,請先轉讓群主;群裡只剩群主一人時請解散。主動退出後預設可立即再次被邀請;僅在應用開啟邀請冷卻時,24 小時內這個群不能再邀請本人。 - 解散:不能恢復。群的全部成員收到通知,群從各自的“我的群”中移除;群檔案全部被刪除,本地這個群的會話免打擾設定也一併刪除。被平臺封禁的群不能解散(
group_disabled)。
被移出群或群被解散時,本人的群列表同樣自動更新,原因可以從會話中的群提示訊息得知(見訊息)。
轉讓群主
群主可以把群主轉讓給群裡的另一個成員。轉讓後原群主變為普通成員,原群主生成的入群連結失效。
final info = await im.groups.transferOwner(groupId, 'wangwu');
print(info.owner); // wangwu介面參考
各方法的 groupId 引數都是群 ID 字串。私有群對非成員不可見,對它的任何操作都以 not_found 拒絕;本人不是公開群的成員時,只有成員才能做的操作以 not_group_member 拒絕;角色不夠時以 permission_denied 拒絕;群被封禁時,被禁止的操作以 group_disabled 拒絕;未登入時以 not_signed_in 拒絕。下文不再逐個列出這幾個錯誤。
im.groups.list()
返回本人加入的群的可訂閱列表(LiveList<GroupView>),按群名排序;快照的 hasMore 總是 false。不再使用時呼叫 dispose()。
im.groups.get()
讀取一個群。
| 引數 | 型別 | 必填 | 說明 |
|---|---|---|---|
groupId | String | 是 | 群 ID |
refresh | bool | 否 | 命名引數。為 true 時不讀本地,向服務端查詢;預設 false |
返回值:Future<GroupView?>,看不到的群為 null。
im.groups.lookup()
批次查詢群資訊。
| 引數 | 型別 | 必填 | 說明 |
|---|---|---|---|
groupIds | List<String> | 是 | 1 到 100 個群 ID |
返回值:Future<List<GroupInfo>>。看不到的群不在結果中;本人不是成員的公開群只有公開的欄位。
可能的錯誤:local_validation(為空或超過 100 個)。
im.groups.publicGroups()
列出公開群,按建立時間從新到舊,不含已封禁和已解散的群。引數都是命名引數。
| 引數 | 型別 | 必填 | 說明 |
|---|---|---|---|
namePrefix | String? | 否 | 按群名稱的字首搜尋 |
cursor | String? | 否 | 下一頁的遊標 |
limit | int? | 否 | 每頁條數,預設 20,最大 100 |
返回值:Future<DRPage<GroupInfo>>。
im.groups.create()
建群,本人為群主。不自動重試,見建群。引數都是命名引數。
| 引數 | 型別 | 必填 | 說明 |
|---|---|---|---|
name | String | 是 | 群名稱,最長 64 個字元 |
type | GroupType? | 否 | 群型別,預設 private |
avatarUrl | String? | 否 | 群頭像地址 |
description | String? | 否 | 群簡介,最長 512 個字元 |
announcement | String? | 否 | 群公告,最長 2048 個字元 |
attributes | Map<String, String?>? | 否 | 自定義屬性,全體成員可見;最多 32 項,合計不超過 4 KB |
memberInvite | MemberInvite? | 否 | 普通成員能否邀請他人,預設 free |
joinMode | JoinMode? | 否 | 公開群的申請方式,預設 approval;私有群不能設定 |
members | List<String>? | 否 | 初始成員的使用者名稱,最多 100 個 |
message | String? | 否 | 給初始成員的邀請附言 |
返回值:Future<CreateGroupResult>。
可能的錯誤:invalid_argument、permission_denied(應用關閉了客戶端建群)、limit_exceeded(user_group_limit、app_group_limit)、content_rejected、rate_limited、app_unavailable(應用只讀)、timeout。
im.groups.update()
修改群資料和設定(群主和管理員,群型別只有群主能改),只提交傳入的引數。除 groupId 外都是命名引數。
| 引數 | 型別 | 必填 | 說明 |
|---|---|---|---|
groupId | String | 是 | 群 ID |
type、name、avatarUrl、description、announcement、memberInvite、joinMode | 同 create | 否 | 要修改的欄位,至少一項 |
attributes | Map<String, String?>? | 否 | 自定義屬性,按項合併,值為 null 的鍵被刪除 |
clearAttributes | bool | 否 | 為 true 時清空全部自定義屬性,預設 false |
version | int? | 否 | 讀取到的 infoVersion,不一致時不修改 |
返回值:Future<GroupInfo>,修改後的群資訊。
可能的錯誤:invalid_argument(為私有群設定 joinMode 等)、content_rejected、version_conflict。
im.groups.transferOwner()
轉讓群主(群主)。
| 引數 | 型別 | 必填 | 說明 |
|---|---|---|---|
groupId | String | 是 | 群 ID |
username | String | 是 | 新群主,必須是本群成員 |
返回值:Future<GroupInfo>。
可能的錯誤:not_group_member(對方不是成員)。
im.groups.setMuteAll()
開啟或關閉全員禁言(群主和管理員)。
| 引數 | 型別 | 必填 | 說明 |
|---|---|---|---|
groupId | String | 是 | 群 ID |
on | bool | 是 | true 開啟,false 關閉 |
返回值:Future<GroupInfo>。
im.groups.leave()
退出群。
| 引數 | 型別 | 必填 | 說明 |
|---|---|---|---|
groupId | String | 是 | 群 ID |
返回值:Future<void>。
可能的錯誤:owner_transfer_required(本人是群主)。
im.groups.dismiss()
解散群(群主),不能恢復。
| 引數 | 型別 | 必填 | 說明 |
|---|---|---|---|
groupId | String | 是 | 群 ID |
返回值:Future<void>。
im.groups.onlineCount()
查詢群的線上人數。同一個群 30 秒內重複呼叫返回上一次的結果。
| 引數 | 型別 | 必填 | 說明 |
|---|---|---|---|
groupId | String | 是 | 群 ID |
返回值:Future<GroupOnlineCount>。
可能的錯誤:permission_denied(details['reason'] 為 presence_disabled:應用沒有開啟線上狀態;presence_scope:線上狀態的可見範圍不是 all。這兩種在本地判斷)、rate_limited。
im.groups.members()
返回群成員的可訂閱列表(LiveList<GroupMember>)。只有成員可以檢視。不再使用時呼叫 dispose()。
| 引數 | 型別 | 必填 | 說明 |
|---|---|---|---|
groupId | String | 是 | 群 ID |
role | GroupRole? | 否 | 命名引數。只列出這種角色的成員 |
muted | bool? | 否 | 命名引數。true 只列出被禁言的成員,false 只列出沒有被禁言的 |
獲取失敗時,快照的 error 為對應的 DRException。未登入時丟擲 not_signed_in。
im.groups.lookupMembers()
按使用者名稱查詢成員資訊(成員才能呼叫)。
| 引數 | 型別 | 必填 | 說明 |
|---|---|---|---|
groupId | String | 是 | 群 ID |
usernames | List<String> | 是 | 1 到 100 個使用者名稱 |
返回值:Future<List<GroupMember>>,不是成員的使用者不在結果中。
可能的錯誤:local_validation(為空或超過 100 個)。
im.groups.invite()
邀請他人入群。
| 引數 | 型別 | 必填 | 說明 |
|---|---|---|---|
groupId | String | 是 | 群 ID |
usernames | List<String> | 是 | 1 到 100 個使用者名稱 |
message | String? | 否 | 命名引數。邀請附言 |
返回值:Future<List<GroupMemberResult>>,每人的結果見邀請成員。
可能的錯誤:local_validation、permission_denied(普通成員在不允許邀請的群裡邀請)、content_rejected(附言)。
im.groups.removeMembers()
移出成員(群主和管理員)。
| 引數 | 型別 | 必填 | 說明 |
|---|---|---|---|
groupId | String | 是 | 群 ID |
usernames | List<String> | 是 | 1 到 100 個使用者名稱 |
返回值:Future<List<GroupMemberResult>>,成功的 status 為 removed 或 not_member。
可能的錯誤:local_validation、invalid_argument(移出自己)。
im.groups.updateMember()
修改成員的群暱稱和成員屬性:本人,或級別更高的群主、管理員。
| 引數 | 型別 | 必填 | 說明 |
|---|---|---|---|
groupId | String | 是 | 群 ID |
username | String | 是 | 成員的使用者名稱 |
groupNickname | String? | 否 | 命名引數。群暱稱,最長 64 個字元;空字串表示清除 |
attributes | Map<String, String?>? | 否 | 命名引數。成員屬性,按項合併,值為 null 的鍵被刪除。最多 16 項,合計不超過 1 KB |
clearAttributes | bool | 否 | 命名引數。為 true 時清空全部成員屬性,預設 false |
返回值:Future<GroupMember>。
可能的錯誤:content_rejected(群暱稱)、not_group_member(對方不是成員)。
im.groups.setRole()
設定或取消管理員(群主)。
| 引數 | 型別 | 必填 | 說明 |
|---|---|---|---|
groupId | String | 是 | 群 ID |
username | String | 是 | 成員的使用者名稱 |
role | GroupRole | 是 | 新角色:admin 或 member |
返回值:Future<GroupMember>。
可能的錯誤:limit_exceeded(admin_limit)、invalid_argument(對群主設定)。
im.groups.mute()
禁言成員(群主和管理員)。
| 引數 | 型別 | 必填 | 說明 |
|---|---|---|---|
groupId | String | 是 | 群 ID |
username | String | 是 | 成員的使用者名稱 |
durationSeconds | int? | 否 | 命名引數。禁言時長,1 到 315360000 秒;省略時永久禁言 |
返回值:Future<GroupMember>。
im.groups.unmute()
解除成員的禁言(群主和管理員)。不能給自己解除。
| 引數 | 型別 | 必填 | 說明 |
|---|---|---|---|
groupId | String | 是 | 群 ID |
username | String | 是 | 成員的使用者名稱 |
返回值:Future<GroupMember>。
im.groups.blacklist.list()
查詢群黑名單(群主和管理員)。
| 引數 | 型別 | 必填 | 說明 |
|---|---|---|---|
groupId | String | 是 | 群 ID |
cursor | String? | 否 | 命名引數。下一頁的遊標 |
limit | int? | 否 | 命名引數。每頁條數,預設 20,最大 100 |
返回值:Future<DRPage<GroupBlacklistEntry>>。
im.groups.blacklist.add()
把使用者加入群黑名單(群主和管理員);他在群裡時同時被移出。已在群黑名單中時同樣成功。
| 引數 | 型別 | 必填 | 說明 |
|---|---|---|---|
groupId | String | 是 | 群 ID |
username | String | 是 | 使用者名稱 |
reason | String? | 否 | 命名引數。原因 |
返回值:Future<void>。
可能的錯誤:limit_exceeded(group_blacklist_limit)、invalid_argument(拉黑自己)。
im.groups.blacklist.remove()
把使用者移出群黑名單。管理員只能移出由管理員加入的記錄。
| 引數 | 型別 | 必填 | 說明 |
|---|---|---|---|
groupId | String | 是 | 群 ID |
username | String | 是 | 使用者名稱 |
返回值:Future<void>。
im.groups.joinLink.get()
查詢當前有效的入群連結(群主和管理員)。
| 引數 | 型別 | 必填 | 說明 |
|---|---|---|---|
groupId | String | 是 | 群 ID |
返回值:Future<JoinLink>;沒有有效連結時三個欄位都為 null。
im.groups.joinLink.create()
生成或重新生成入群連結(群主和管理員),舊連結立即失效。
| 引數 | 型別 | 必填 | 說明 |
|---|---|---|---|
groupId | String | 是 | 群 ID |
expiresInSeconds | int? | 否 | 命名引數。有效期,86400 到 604800 秒,預設 604800 |
返回值:Future<JoinLink>。
im.groups.joinLink.revoke()
撤銷入群連結(群主和管理員)。
| 引數 | 型別 | 必填 | 說明 |
|---|---|---|---|
groupId | String | 是 | 群 ID |
返回值:Future<void>。
im.groups.joinLink.preview()
預覽入群連結。
| 引數 | 型別 | 必填 | 說明 |
|---|---|---|---|
link | String | 是 | 入群連結 |
返回值:Future<JoinLinkPreview>。
可能的錯誤:not_found(連結無效、過期、已撤銷,或群已封禁、已解散)、rate_limited。
im.groups.joinLink.join()
透過入群連結加入。已是成員時直接返回群資訊。
| 引數 | 型別 | 必填 | 說明 |
|---|---|---|---|
link | String | 是 | 入群連結 |
返回值:Future<GroupInfo>。
可能的錯誤:not_found、permission_denied(在群黑名單中,或被加群前回撥拒絕)、limit_exceeded(群已滿或本人的群數已滿)、rate_limited。
im.groups.applications.apply()
申請加入公開群。
| 引數 | 型別 | 必填 | 說明 |
|---|---|---|---|
groupId | String | 是 | 群 ID |
message | String? | 否 | 命名引數。申請理由,最長 256 個字元 |
返回值:Future<String>:joined、pending 或 already_member。
可能的錯誤:not_found(私有群)、permission_denied(group_blacklisted,或被加群前回撥拒絕)、limit_exceeded(user_group_limit、group_member_limit)、rate_limited(declined_cooldown、pair_daily_limit、request_rate、group_join_rate)、content_rejected。
im.groups.applications.withdraw()
撤回本人待處理的申請。已撤回過同樣成功。
| 引數 | 型別 | 必填 | 說明 |
|---|---|---|---|
groupId | String | 是 | 群 ID |
返回值:Future<void>。
可能的錯誤:version_conflict(申請已被處理,details['status'] 為當前狀態)。
im.groups.applications.mine()
查詢本人發出的入群申請,按發起時間從新到舊。引數都是命名引數。
| 引數 | 型別 | 必填 | 說明 |
|---|---|---|---|
status | GroupRequestStatus? | 否 | 只列出這種狀態的申請 |
cursor | String? | 否 | 下一頁的遊標 |
limit | int? | 否 | 每頁條數 |
返回值:Future<DRPage<GroupRequest>>。不帶 cursor 和 status 時返回 SDK 記憶體中的第一頁。
im.groups.invitations.received()
查詢本人收到的入群邀請,按發起時間從新到舊。引數同 applications.mine()。
返回值:Future<DRPage<GroupRequest>>。不帶 cursor 和 status 時返回 SDK 記憶體中的第一頁。
im.groups.invitations.accept()
接受入群邀請。
| 引數 | 型別 | 必填 | 說明 |
|---|---|---|---|
groupId | String | 是 | 群 ID |
返回值:Future<GroupInfo>。
可能的錯誤:not_found(邀請不存在或已過期)、permission_denied(在群黑名單中)、limit_exceeded、rate_limited(group_join_rate)、version_conflict(邀請已被撤回等)。
im.groups.invitations.decline()
拒絕入群邀請。之後預設可立即再次收到邀請;僅在應用開啟 group_invite_cooldown_enabled 時,24 小時內這個群不能再邀請本人。
| 引數 | 型別 | 必填 | 說明 |
|---|---|---|---|
groupId | String | 是 | 群 ID |
reason | String? | 否 | 命名引數。拒絕理由,最長 256 個字元 |
返回值:Future<void>。
im.groups.requests.list()
查詢本群的請求,按發起時間從新到舊。群主和管理員可以看到全部型別,普通成員只能看到自己發出的邀請。每次都向服務端查詢。
| 引數 | 型別 | 必填 | 說明 |
|---|---|---|---|
groupId | String | 是 | 群 ID |
kind | GroupRequestKind? | 否 | 命名引數。application、inviteReview 或 invitation |
status | GroupRequestStatus? | 否 | 命名引數。pending、accepted、declined、canceled 或 expired |
cursor | String? | 否 | 命名引數。下一頁的遊標 |
limit | int? | 否 | 命名引數。每頁條數 |
返回值:Future<DRPage<GroupRequest>>。
im.groups.requests.approve()
透過申請或成員發起的邀請(群主和管理員)。
| 引數 | 型別 | 必填 | 說明 |
|---|---|---|---|
groupId | String | 是 | 群 ID |
kind | GroupRequestKind | 是 | application 或 inviteReview |
username | String | 是 | 申請人或被邀請人 |
返回值:Future<String>:joined、invited 或 canceled。
可能的錯誤:not_found(請求不存在或已過期)、version_conflict(已被別人處理)、permission_denied(group_blacklisted)、limit_exceeded、rate_limited(group_join_rate)。
im.groups.requests.decline()
拒絕申請或成員發起的邀請(群主和管理員)。
| 引數 | 型別 | 必填 | 說明 |
|---|---|---|---|
groupId | String | 是 | 群 ID |
kind | GroupRequestKind | 是 | application 或 inviteReview |
username | String | 是 | 申請人或被邀請人 |
reason | String? | 否 | 命名引數。拒絕理由,最長 256 個字元 |
返回值:Future<void>。
可能的錯誤:not_found、version_conflict、content_rejected(理由)。
im.groups.requests.withdrawInvite()
撤回待處理的邀請:邀請人本人,或群主、管理員。
| 引數 | 型別 | 必填 | 說明 |
|---|---|---|---|
groupId | String | 是 | 群 ID |
kind | GroupRequestKind | 是 | inviteReview 或 invitation |
username | String | 是 | 被邀請人 |
返回值:Future<void>。
可能的錯誤:not_found、version_conflict。
im.groups.settings.get()
查詢本人被邀請時的處理方式。
返回值:Future<GroupInviteSettings>。inviteMode 為本人的設定,沒有設定過時為 null;effectiveInviteMode 為實際生效的方式。
im.groups.settings.set()
設定本人被邀請時的處理方式。
| 引數 | 型別 | 必填 | 說明 |
|---|---|---|---|
mode | InviteMode? | 是 | allowAny 或 needConfirm;null 清除設定,改用應用的預設值 |
返回值:Future<void>。
相關事件
用 im.on<T>() 按型別訂閱,見事件與錯誤處理。
| 事件 | 欄位 | 說明 |
|---|---|---|
GroupsChanged | upserted、removed(群 ID) | 群資訊變化(upserted),或群離開了“我的群”(removed) |
GroupMembersChanged | groupId、usernames(List<String>?) | 本地儲存的成員列表變化;usernames 為 null 表示整體變化 |
GroupRequestsChanged | list、groupId(String?) | list 為 pending:這個群的待審批請求有變化;invitations、applications:本人收到的邀請、發出的申請的第一頁已重新整理 |
資料結構
服務端物件(繼承 DRObject)的常用欄位以 getter 提供;時間為 UTC 的 DateTime。服務端返回的全部欄位都在 raw(Map<String, Object?>)中,可以直接讀取沒有 getter 的欄位。
GroupView
| 欄位 | 型別 | 說明 |
|---|---|---|
groupId | String | 群 ID |
group | GroupInfo | 群資訊;已離開的群為離開前最後一次的資訊 |
inMyGroups | bool | 是否在“我的群”中 |
GroupInfo
本人是成員時有全部欄位;本人不是成員的公開群只有 groupId、type、name、avatarUrl、description、memberCount、joinMode、status 和 self,其餘為 null(或空值)。
| 欄位 | 型別 | 說明 |
|---|---|---|
groupId | String | 群 ID |
type | String | 群型別:private 或 public |
name | String | 群名稱,沒有時為空字串 |
avatarUrl | String | 群頭像地址,沒有時為空字串 |
description | String? | 群簡介 |
announcement | String? | 群公告 |
announcementUpdatedAt | DateTime? | 公告最近一次修改的時間 |
announcementUpdatedBy | String? | 最近一次在客戶端修改公告的使用者名稱 |
attributes | Map<String, String>? | 自定義屬性 |
owner | String? | 群主的使用者名稱 |
memberInvite | String? | 普通成員能否邀請他人:free、approval、disabled |
joinMode | String? | 公開群的申請方式:approval、free;私有群為 null |
muteAll | bool | 是否開啟了全員禁言 |
maxMembers | int? | 人數上限 |
memberCount | int | 當前人數,含群主 |
status | String | active 正常、disabled 已封禁、dismissed 已解散 |
infoVersion | int? | 群資料和設定的版本號,可用於 update 的 version |
memberVersion | int? | 成員列表的版本號 |
createdAt | DateTime? | 建立時間 |
self | GroupSelf? | 本人在群裡的資訊;不是成員時為 null |
raw['disabled_by'] 為封禁方:tenant 應用、platform 平臺;未封禁時為 null。
GroupSelf
| 欄位 | 型別 | 說明 |
|---|---|---|
role | GroupRole? | 本人的角色 |
groupNickname | String | 本人的群暱稱,沒有時為空字串 |
muted | bool | 本人是否被禁言 |
mutedUntil | DateTime? | 禁言的到期時間,永久禁言為 null |
joinedAt | DateTime? | 入群時間 |
CreateGroupResult
繼承 GroupInfo,另有:
| 欄位 | 型別 | 說明 |
|---|---|---|
results | List<GroupMemberResult> | 每個初始成員的結果,按請求的順序;超時後查詢確認已建成的群為空列表 |
GroupMember
| 欄位 | 型別 | 說明 |
|---|---|---|
username | String | 使用者名稱 |
nickname | String | 使用者資料中的暱稱 |
avatarUrl | String | 使用者資料中的頭像 |
role | GroupRole? | owner、admin 或 member |
groupNickname | String | 本群的群暱稱,沒有時為空字串 |
attributes | Map<String, String>? | 成員屬性 |
muted | bool | 是否被禁言 |
mutedUntil | DateTime? | 禁言的到期時間,永久禁言為 null |
joinedVia | String | 入群方式:create 建群時、server 服務端新增、invite 被邀請、apply 申請、link 入群連結 |
inviter | String? | 邀請人的使用者名稱 |
joinedAt | DateTime? | 入群時間 |
GroupMemberResult
批次操作中一個使用者的結果:成功的有 status,失敗的有 code。
| 欄位 | 型別 | 說明 |
|---|---|---|
username | String | 使用者名稱 |
ok | bool | 是否成功 |
status | String? | 成功時:joined、invited、pending_review、already_member(邀請、建群),或 removed、not_member(移出);失敗時為 null |
code | String? | 失敗時的錯誤碼 |
message | String? | 失敗時的說明 |
details | Map<String, Object?>? | 失敗的詳細原因,details['reason'] 說明原因 |
GroupOnlineCount
| 欄位 | 型別 | 說明 |
|---|---|---|
onlineCount | int | 線上人數 |
countedAt | DateTime? | 統計的時間 |
GroupRequest
入群申請或邀請,requests.list()、applications.mine()、invitations.received() 的每項。
| 欄位 | 型別 | 說明 |
|---|---|---|
groupId | String | 群 ID |
kind | String | application、invite_review 或 invitation |
username | String | 請求的目標使用者:申請人或被邀請人 |
nickname | String | 目標使用者的暱稱 |
avatarUrl | String | 目標使用者的頭像 |
inviter | GroupRequestUser? | 邀請人的 username、nickname、avatarUrl;申請為 null |
message | String? | 申請理由或邀請附言 |
reason | String? | 拒絕理由 |
status | String | pending、accepted、declined、canceled 或 expired |
cancelCause | String? | 失效的原因:withdrawn、joined、blacklisted、group_private、not_eligible、dismissed |
requestedAt | DateTime? | 最近一次發起的時間 |
expiresAt | DateTime? | 過期時間,只有待處理的有值 |
handledAt | DateTime? | 處理時間 |
handledBy | String? | 處理人的使用者名稱 |
group | GroupBrief? | 只在本人收到的邀請和發出的申請中:群的 groupId、name、avatarUrl、memberCount。群是私有群且請求已處理時為 null |
群被封禁期間,待處理的請求顯示為 canceled、cancelCause 為 null,解封后恢復。
GroupBlacklistEntry
| 欄位 | 型別 | 說明 |
|---|---|---|
username | String | 使用者名稱 |
nickname | String | 暱稱 |
avatarUrl | String | 頭像 |
reason | String? | 原因 |
createdBy | String? | 執行操作的群主或管理員;你的服務端和控制檯加入的為 null |
createdByRole | String? | 加入時操作人的身份:owner、admin 或 server |
createdAt | DateTime? | 加入的時間 |
JoinLink
| 欄位 | 型別 | 說明 |
|---|---|---|
link | String? | 入群連結 |
expiresAt | DateTime? | 過期時間 |
createdBy | String? | 生成連結的人 |
JoinLinkPreview
| 欄位 | 型別 | 說明 |
|---|---|---|
groupId | String | 群 ID |
name | String | 群名稱 |
avatarUrl | String | 群頭像 |
memberCount | int | 人數 |
isMember | bool | 本人是否已是成員 |
GroupInviteSettings
| 欄位 | 型別 | 說明 |
|---|---|---|
inviteMode | InviteMode? | 本人的設定,沒有設定過為 null |
effectiveInviteMode | InviteMode? | 實際生效的方式 |
列舉
| 列舉 | 取值 |
|---|---|
GroupRole | owner、admin、member |
GroupType | private、public |
MemberInvite | free、approval、disabled |
JoinMode | approval、free |
GroupRequestKind | application、inviteReview(invite_review)、invitation |
GroupRequestStatus | pending、accepted、declined、canceled、expired |
InviteMode | allowAny(allow_any)、needConfirm(need_confirm) |
每個列舉的 wire 為服務端的取值。
