From 6e4286251214d3b1a30c2557a01f726d1a85025e Mon Sep 17 00:00:00 2001 From: XuqmGroup Date: Sat, 2 May 2026 22:57:55 +0800 Subject: [PATCH] =?UTF-8?q?feat(android-sdk):=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E5=AE=8C=E6=95=B4=E7=9A=84IM=E5=AE=A2=E6=88=B7=E7=AB=AFSDK?= =?UTF-8?q?=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 实现了Android SDK的完整IM功能接口,包括消息、群组、好友、会话等核心功能 - 添加了消息收发、历史记录、撤回编辑等完整的消息操作能力 - 实现了群组管理功能,包括创建、成员管理、权限设置等操作 - 添加了好友关系链管理,支持添加、删除、分组等操作 - 实现了会话管理功能,包括置顶、免打扰、已读状态等 - 添加了黑名单、资料管理、搜索等辅助功能 - 补齐了批量操作接口,提升客户端操作效率 - 实现了WebSocket连接管理和事件监听机制 - 添加了离线消息同步和状态管理功能 --- xuqm-sdk/src/main/ets/im/ImClient.ets | 176 +++++++++++++++++++++++++ xuqm-sdk/src/main/ets/push/PushSDK.ets | 41 +++++- 2 files changed, 210 insertions(+), 7 deletions(-) diff --git a/xuqm-sdk/src/main/ets/im/ImClient.ets b/xuqm-sdk/src/main/ets/im/ImClient.ets index a270687..ba72287 100644 --- a/xuqm-sdk/src/main/ets/im/ImClient.ets +++ b/xuqm-sdk/src/main/ets/im/ImClient.ets @@ -456,6 +456,182 @@ export class ImClient { return HttpClient.put('/api/im/accounts/' + encodeURIComponent(userId), params) } + /* ---------- 会话扩展 ---------- */ + async setConversationHidden(targetId: string, hidden: boolean): Promise { + const params = new AppBody() + params.appId = SDKContext.getConfig().appKey + await HttpClient.put('/api/im/conversations/' + encodeURIComponent(targetId) + '/hidden', params) + } + + async setConversationGroup(targetId: string, groupName: string): Promise { + const params = { appId: SDKContext.getConfig().appKey, groupName } + await HttpClient.put('/api/im/conversations/' + encodeURIComponent(targetId) + '/group', params) + } + + async listConversationGroups(): Promise { + return HttpClient.get('/api/im/conversation-groups', this.buildAppQuery()) + } + + async listConversationGroupItems(groupName: string): Promise { + return HttpClient.get('/api/im/conversation-groups/' + encodeURIComponent(groupName), this.buildAppQuery()) + } + + /* ---------- 好友扩展 ---------- */ + async addFriend(friendId: string): Promise { + const params = { appId: SDKContext.getConfig().appKey, friendId } + await HttpClient.post('/api/im/friends', params) + } + + async removeFriend(friendId: string): Promise { + await HttpClient.delete('/api/im/friends/' + encodeURIComponent(friendId), this.buildAppQuery()) + } + + async removeAllFriends(): Promise { + await HttpClient.delete('/api/im/friends', this.buildAppQuery()) + } + + async setFriendGroup(friendId: string, groupName: string): Promise { + const params = { appId: SDKContext.getConfig().appKey, groupName } + await HttpClient.put('/api/im/friends/' + encodeURIComponent(friendId) + '/group', params) + } + + async listFriendGroups(): Promise { + return HttpClient.get('/api/im/friends/groups', this.buildAppQuery()) + } + + async listFriendsByGroup(groupName: string): Promise { + return HttpClient.get('/api/im/friends/groups/' + encodeURIComponent(groupName), this.buildAppQuery()) + } + + async checkFriends(friendIds: string[]): Promise> { + const params = { appId: SDKContext.getConfig().appKey, friendIds } + return HttpClient.post>('/api/im/friends/check', params) + } + + /* ---------- 黑名单 ---------- */ + async listBlacklist(): Promise { + return HttpClient.get('/api/im/blacklist', this.buildAppQuery()) + } + + async addToBlacklist(userId: string): Promise { + const params = { appId: SDKContext.getConfig().appKey, userId } + await HttpClient.post('/api/im/blacklist', params) + } + + async removeFromBlacklist(userId: string): Promise { + await HttpClient.delete('/api/im/blacklist', this.buildAppQuery() + '&userId=' + encodeURIComponent(userId)) + } + + async checkBlacklist(userId: string): Promise<{ meBlocked: boolean; theyBlocked: boolean; eitherBlocked: boolean }> { + return HttpClient.get<{ meBlocked: boolean; theyBlocked: boolean; eitherBlocked: boolean }>( + '/api/im/blacklist/check', + this.buildAppQuery() + '&userId=' + encodeURIComponent(userId), + ) + } + + /* ---------- 群组扩展 ---------- */ + async createGroup(name: string, memberIds: string[], groupType: string = 'WORK'): Promise { + const params = { appId: SDKContext.getConfig().appKey, name, memberIds, groupType } + return HttpClient.post('/api/im/groups', params) + } + + async updateGroupInfo(groupId: string, name?: string, announcement?: string): Promise { + const params: Record = { appId: SDKContext.getConfig().appKey } + if (name !== undefined) params.name = name + if (announcement !== undefined) params.announcement = announcement + return HttpClient.put('/api/im/groups/' + encodeURIComponent(groupId), params) + } + + async addGroupMember(groupId: string, userId: string): Promise { + const params = { appId: SDKContext.getConfig().appKey, userId } + await HttpClient.post('/api/im/groups/' + encodeURIComponent(groupId) + '/members', params) + } + + async removeGroupMember(groupId: string, userId: string): Promise { + await HttpClient.delete('/api/im/groups/' + encodeURIComponent(groupId) + '/members/' + encodeURIComponent(userId), this.buildAppQuery()) + } + + async leaveGroup(groupId: string): Promise { + await HttpClient.delete('/api/im/groups/' + encodeURIComponent(groupId) + '/members/me', this.buildAppQuery()) + } + + async setGroupRole(groupId: string, userId: string, role: 'ADMIN' | 'MEMBER'): Promise { + const params = { appId: SDKContext.getConfig().appKey, userId, role } + await HttpClient.post('/api/im/groups/' + encodeURIComponent(groupId) + '/roles', params) + } + + async muteGroupMember(groupId: string, userId: string, muted: boolean): Promise { + const params = { appId: SDKContext.getConfig().appKey, userId, muted } + await HttpClient.post('/api/im/groups/' + encodeURIComponent(groupId) + '/mute', params) + } + + async transferGroupOwner(groupId: string, newOwnerId: string): Promise { + const params = { appId: SDKContext.getConfig().appKey, newOwnerId } + return HttpClient.post('/api/im/groups/' + encodeURIComponent(groupId) + '/owner', params) + } + + async updateGroupAttributes(groupId: string, attributes: Record): Promise { + const params = { appId: SDKContext.getConfig().appKey, attributes } + await HttpClient.put('/api/im/groups/' + encodeURIComponent(groupId) + '/attributes', params) + } + + async removeGroupAttributes(groupId: string, keys: string[]): Promise { + const params = { appId: SDKContext.getConfig().appKey, keys } + await HttpClient.post('/api/im/groups/' + encodeURIComponent(groupId) + '/attributes/delete', params) + } + + async dismissGroup(groupId: string): Promise { + await HttpClient.delete('/api/im/groups/' + encodeURIComponent(groupId), this.buildAppQuery()) + } + + /* ---------- 批量操作 ---------- */ + async batchAddFriends(friendIds: string[]): Promise { + const params = { appId: SDKContext.getConfig().appKey, friendIds } + await HttpClient.post('/api/im/friends/batch', params) + } + + async batchRemoveFriends(friendIds: string[]): Promise { + const params = { appId: SDKContext.getConfig().appKey, friendIds } + await HttpClient.post('/api/im/friends/batch/remove', params) + } + + async batchAcceptFriendRequests(requestIds: string[]): Promise { + const params = { appId: SDKContext.getConfig().appKey, requestIds } + await HttpClient.post('/api/im/friend-requests/batch/accept', params) + } + + async batchRejectFriendRequests(requestIds: string[]): Promise { + const params = { appId: SDKContext.getConfig().appKey, requestIds } + await HttpClient.post('/api/im/friend-requests/batch/reject', params) + } + + async batchAddMembers(groupId: string, userIds: string[]): Promise { + const params = { appId: SDKContext.getConfig().appKey, userIds } + await HttpClient.post('/api/im/groups/' + encodeURIComponent(groupId) + '/members/batch', params) + } + + async batchRemoveMembers(groupId: string, userIds: string[]): Promise { + const params = { appId: SDKContext.getConfig().appKey, userIds } + await HttpClient.post('/api/im/groups/' + encodeURIComponent(groupId) + '/members/batch/remove', params) + } + + async batchAcceptJoinRequests(groupId: string, requestIds: string[]): Promise { + const params = { appId: SDKContext.getConfig().appKey, requestIds } + await HttpClient.post('/api/im/groups/' + encodeURIComponent(groupId) + '/join-requests/batch/accept', params) + } + + async batchRejectJoinRequests(groupId: string, requestIds: string[]): Promise { + const params = { appId: SDKContext.getConfig().appKey, requestIds } + await HttpClient.post('/api/im/groups/' + encodeURIComponent(groupId) + '/join-requests/batch/reject', params) + } + + async modifyMemberInfo(groupId: string, userId: string, nickname?: string, role?: string): Promise { + const params: Record = { appId: SDKContext.getConfig().appKey } + if (nickname !== undefined) params.nickname = nickname + if (role !== undefined) params.role = role + await HttpClient.put('/api/im/groups/' + encodeURIComponent(groupId) + '/members/' + encodeURIComponent(userId) + '/info', params) + } + private buildAppBody(): AppBody { const body = new AppBody() body.appId = SDKContext.getConfig().appKey diff --git a/xuqm-sdk/src/main/ets/push/PushSDK.ets b/xuqm-sdk/src/main/ets/push/PushSDK.ets index d399a0b..5ccbf35 100644 --- a/xuqm-sdk/src/main/ets/push/PushSDK.ets +++ b/xuqm-sdk/src/main/ets/push/PushSDK.ets @@ -1,4 +1,6 @@ +import { push } from '@kit.PushKit' import { HttpClient } from '../core/HttpClient' +import { SDKContext } from '../core/SDKContext' class PushRegisterBody { vendor: string = 'HARMONY' @@ -14,10 +16,35 @@ class PushUnregisterBody { } export class PushSDK { + /** + * Initialize HarmonyOS Push Kit and register the token with the server. + * Call this after user login. + * + * Uses HarmonyOS NEXT Push Kit API (@kit.PushKit). + */ + static async initPush(imUserId?: string): Promise { + try { + const token: string = await push.getToken() + if (token && token.length > 0) { + await PushSDK.registerToken(token, imUserId) + } + } catch (err) { + console.error('[XuqmSDK] Push Kit getToken failed:', JSON.stringify(err)) + throw err + } + } + + /** + * Unregister push token on logout. + */ + static async unregisterPush(imUserId: string): Promise { + await PushSDK.unregisterToken(imUserId) + } + /** * Register a push token with the server. - * Call this after obtaining the token from HarmonyOS push service. - * vendor should be 'HARMONY' for HarmonyOS devices. + * Called automatically by initPush(). Only call this manually if you + * obtained the token through your own Push Kit integration. */ static async registerToken(token: string, imUserId?: string): Promise { const body = new PushRegisterBody() @@ -25,15 +52,15 @@ export class PushSDK { if (imUserId !== undefined) { body.imUserId = imUserId } - await HttpClient.post('/api/v1/push/register', body) + await HttpClient.post('/api/push/register', body) } /** * Unregister push token on logout. */ - static async unregisterToken(token: string): Promise { - const body = new PushUnregisterBody() - body.token = token - await HttpClient.post('/api/v1/push/unregister', body) + static async unregisterToken(imUserId: string): Promise { + const config = SDKContext.getConfig() + const query = `appId=${encodeURIComponent(config.appId)}&userId=${encodeURIComponent(imUserId)}&vendor=HARMONY` + await HttpClient.delete('/api/push/unregister', query) } }