docs(project): 更新需求与开发进度对比报告并完善Android SDK接口定义

- 添加了完整的XuqmGroup平台需求与开发进度对比报告
- 实现了Android SDK的ImApi接口定义,涵盖群组、好友、黑名单等完整功能
- 定义了IM消息、会话、群组、用户资料等核心数据模型
- 实现了Android SDK的ImSDK核心功能类,包括连接管理和消息处理
这个提交包含在:
XuqmGroup 2026-05-02 12:30:31 +08:00
父节点 20fc57ac97
当前提交 cfd0382ba2
共有 3 个文件被更改,包括 165 次插入10 次删除

查看文件

@ -4,18 +4,22 @@ import com.xuqm.sdk.XuqmLoginSession
import com.xuqm.sdk.XuqmSDK
import com.xuqm.sdk.core.ServiceEndpointRegistry
import com.xuqm.sdk.im.api.AddMemberRequest
import com.xuqm.sdk.im.api.AttributeKeysRequest
import com.xuqm.sdk.im.api.CreateGroupRequest
import com.xuqm.sdk.im.api.GroupReadReceiptRequest
import com.xuqm.sdk.im.api.ImApi
import com.xuqm.sdk.im.model.EditMessageRequest
import com.xuqm.sdk.im.api.MuteGroupMemberRequest
import com.xuqm.sdk.im.api.SetMutedRequest
import com.xuqm.sdk.im.api.SetPinnedRequest
import com.xuqm.sdk.im.api.SetGroupRoleRequest
import com.xuqm.sdk.im.api.TransferOwnerRequest
import com.xuqm.sdk.im.api.UpdateGroupRequest
import com.xuqm.sdk.im.listener.ImEventListener
import com.xuqm.sdk.im.model.BlacklistCheckResult
import com.xuqm.sdk.im.model.ConversationGroupItem
import com.xuqm.sdk.im.model.ImConnectionState
import com.xuqm.sdk.im.model.ConversationData
import com.xuqm.sdk.im.model.GroupJoinRequest
import com.xuqm.sdk.im.model.GroupReadReceiptSummary
import com.xuqm.sdk.im.model.ImGroup
import com.xuqm.sdk.im.model.ImMessage
import com.xuqm.sdk.im.model.PageResult
@ -534,6 +538,15 @@ object ImSDK {
suspend fun muteGroupMember(groupId: String, userId: String, minutes: Long) =
withContext(Dispatchers.IO) { api.muteGroupMember(groupId, MuteGroupMemberRequest(userId, minutes)) }
suspend fun transferGroupOwner(groupId: String, newOwnerId: String): ImGroup? =
withContext(Dispatchers.IO) { api.transferGroupOwner(groupId, TransferOwnerRequest(newOwnerId)).data }
suspend fun updateGroupAttributes(groupId: String, attributes: Map<String, Any?>): ImGroup? =
withContext(Dispatchers.IO) { api.updateGroupAttributes(groupId, attributes).data }
suspend fun removeGroupAttributes(groupId: String, keys: List<String>): ImGroup? =
withContext(Dispatchers.IO) { api.removeGroupAttributes(groupId, AttributeKeysRequest(keys)).data }
suspend fun dismissGroup(groupId: String) =
withContext(Dispatchers.IO) { api.dismissGroup(groupId) }
@ -555,9 +568,21 @@ object ImSDK {
suspend fun addFriend(friendId: String) =
withContext(Dispatchers.IO) { api.addFriend(XuqmSDK.appKey, friendId) }
suspend fun removeAllFriends() =
withContext(Dispatchers.IO) { api.removeAllFriends(XuqmSDK.appKey) }
suspend fun removeFriend(friendId: String) =
withContext(Dispatchers.IO) { api.removeFriend(friendId, XuqmSDK.appKey) }
suspend fun setFriendGroup(friendId: String, groupName: String? = null) =
withContext(Dispatchers.IO) { api.setFriendGroup(friendId, XuqmSDK.appKey, groupName) }
suspend fun listFriendGroups(): List<String> =
withContext(Dispatchers.IO) { api.listFriendGroups(XuqmSDK.appKey).data ?: emptyList() }
suspend fun listFriendsByGroup(groupName: String): List<String> =
withContext(Dispatchers.IO) { api.listFriendsByGroup(groupName, XuqmSDK.appKey).data ?: emptyList() }
suspend fun listFriendRequests(direction: String = "incoming"): List<FriendRequest> =
withContext(Dispatchers.IO) { api.listFriendRequests(XuqmSDK.appKey, direction).data ?: emptyList() }
@ -579,6 +604,9 @@ object ImSDK {
suspend fun removeFromBlacklist(blockedUserId: String) =
withContext(Dispatchers.IO) { api.removeFromBlacklist(XuqmSDK.appKey, blockedUserId) }
suspend fun checkBlacklist(targetUserId: String): BlacklistCheckResult? =
withContext(Dispatchers.IO) { api.checkBlacklist(XuqmSDK.appKey, targetUserId).data }
suspend fun getProfile(userId: String) =
withContext(Dispatchers.IO) { api.getProfile(userId, XuqmSDK.appKey).data }
@ -601,14 +629,30 @@ object ImSDK {
suspend fun setConversationPinned(targetId: String, chatType: String, pinned: Boolean) =
withContext(Dispatchers.IO) {
api.setConversationPinned(targetId, chatType, SetPinnedRequest(pinned))
api.setConversationPinned(targetId, XuqmSDK.appKey, chatType, pinned)
}
suspend fun setConversationMuted(targetId: String, chatType: String, muted: Boolean) =
withContext(Dispatchers.IO) {
api.setConversationMuted(targetId, chatType, SetMutedRequest(muted))
api.setConversationMuted(targetId, XuqmSDK.appKey, chatType, muted)
}
suspend fun setConversationHidden(targetId: String, chatType: String, hidden: Boolean) =
withContext(Dispatchers.IO) {
api.setConversationHidden(targetId, XuqmSDK.appKey, chatType, hidden)
}
suspend fun setConversationGroup(targetId: String, chatType: String, groupName: String? = null) =
withContext(Dispatchers.IO) {
api.setConversationGroup(targetId, XuqmSDK.appKey, chatType, groupName)
}
suspend fun listConversationGroups(): List<String> =
withContext(Dispatchers.IO) { api.listConversationGroups(XuqmSDK.appKey).data ?: emptyList() }
suspend fun listConversationGroupItems(groupName: String): List<ConversationGroupItem> =
withContext(Dispatchers.IO) { api.listConversationGroupItems(groupName, XuqmSDK.appKey).data ?: emptyList() }
suspend fun markRead(targetId: String, chatType: String = "SINGLE") =
withContext(Dispatchers.IO) { api.markRead(targetId, XuqmSDK.appKey, chatType) }
@ -618,6 +662,11 @@ object ImSDK {
suspend fun deleteConversation(targetId: String, chatType: String) =
withContext(Dispatchers.IO) { api.deleteConversation(targetId, XuqmSDK.appKey, chatType) }
suspend fun adminGroupReadReceipts(groupId: String, messageIds: List<String>): List<GroupReadReceiptSummary> =
withContext(Dispatchers.IO) {
api.adminGroupReadReceipts(groupId, XuqmSDK.appKey, GroupReadReceiptRequest(messageIds)).data ?: emptyList()
}
fun addListener(listener: ImEventListener) {
Log.d(TAG, "addListener listener=${listener.javaClass.name}")
listeners.add(listener)

查看文件

@ -1,9 +1,12 @@
package com.xuqm.sdk.im.api
import com.xuqm.sdk.im.model.ConversationData
import com.xuqm.sdk.im.model.BlacklistCheckResult
import com.xuqm.sdk.im.model.BlacklistEntry
import com.xuqm.sdk.im.model.ConversationGroupItem
import com.xuqm.sdk.im.model.EditMessageRequest
import com.xuqm.sdk.im.model.FriendRequest
import com.xuqm.sdk.im.model.GroupReadReceiptSummary
import com.xuqm.sdk.im.model.ImGroup
import com.xuqm.sdk.im.model.GroupJoinRequest
import com.xuqm.sdk.im.model.ImMessage
@ -39,14 +42,16 @@ data class UpdateGroupRequest(val name: String? = null, val announcement: String
data class AddMemberRequest(val userId: String)
data class SetPinnedRequest(val pinned: Boolean)
data class SetMutedRequest(val muted: Boolean)
data class SetGroupRoleRequest(val userId: String, val role: String)
data class MuteGroupMemberRequest(val userId: String, val minutes: Long)
data class TransferOwnerRequest(val newOwnerId: String)
data class AttributeKeysRequest(val keys: List<String>)
data class GroupReadReceiptRequest(val messageIds: List<String>)
interface ImApi {
@POST("api/im/auth/login")
@ -167,6 +172,24 @@ interface ImApi {
@Body request: MuteGroupMemberRequest,
): ApiResponse<ImGroup>
@POST("api/im/groups/{groupId}/owner")
suspend fun transferGroupOwner(
@Path("groupId") groupId: String,
@Body request: TransferOwnerRequest,
): ApiResponse<ImGroup>
@PUT("api/im/groups/{groupId}/attributes")
suspend fun updateGroupAttributes(
@Path("groupId") groupId: String,
@Body attributes: Map<String, @JvmSuppressWildcards Any?>,
): ApiResponse<ImGroup>
@POST("api/im/groups/{groupId}/attributes/delete")
suspend fun removeGroupAttributes(
@Path("groupId") groupId: String,
@Body request: AttributeKeysRequest,
): ApiResponse<ImGroup>
@DELETE("api/im/groups/{groupId}")
suspend fun dismissGroup(@Path("groupId") groupId: String): ApiResponse<Unit>
@ -206,12 +229,31 @@ interface ImApi {
@Query("friendId") friendId: String,
): ApiResponse<Unit>
@DELETE("api/im/friends")
suspend fun removeAllFriends(@Query("appId") appId: String): ApiResponse<Unit>
@DELETE("api/im/friends/{friendId}")
suspend fun removeFriend(
@Path("friendId") friendId: String,
@Query("appId") appId: String,
): ApiResponse<Unit>
@PUT("api/im/friends/{friendId}/group")
suspend fun setFriendGroup(
@Path("friendId") friendId: String,
@Query("appId") appId: String,
@Query("groupName") groupName: String? = null,
): ApiResponse<Unit>
@GET("api/im/friends/groups")
suspend fun listFriendGroups(@Query("appId") appId: String): ApiResponse<List<String>>
@GET("api/im/friends/groups/{groupName}")
suspend fun listFriendsByGroup(
@Path("groupName") groupName: String,
@Query("appId") appId: String,
): ApiResponse<List<String>>
@GET("api/im/friend-requests")
suspend fun listFriendRequests(
@Query("appId") appId: String,
@ -252,6 +294,12 @@ interface ImApi {
@Query("blockedUserId") blockedUserId: String,
): ApiResponse<Unit>
@GET("api/im/blacklist/check")
suspend fun checkBlacklist(
@Query("appId") appId: String,
@Query("targetUserId") targetUserId: String,
): ApiResponse<BlacklistCheckResult>
@GET("api/im/accounts/{userId}")
suspend fun getProfile(
@Path("userId") userId: String,
@ -273,17 +321,44 @@ interface ImApi {
@PUT("api/im/conversations/{targetId}/pinned")
suspend fun setConversationPinned(
@Path("targetId") targetId: String,
@Query("appId") appId: String,
@Query("chatType") chatType: String,
@Body request: SetPinnedRequest,
@Query("pinned") pinned: Boolean,
): ApiResponse<Unit>
@PUT("api/im/conversations/{targetId}/muted")
suspend fun setConversationMuted(
@Path("targetId") targetId: String,
@Query("appId") appId: String,
@Query("chatType") chatType: String,
@Body request: SetMutedRequest,
@Query("muted") muted: Boolean,
): ApiResponse<Unit>
@PUT("api/im/conversations/{targetId}/hidden")
suspend fun setConversationHidden(
@Path("targetId") targetId: String,
@Query("appId") appId: String,
@Query("chatType") chatType: String,
@Query("hidden") hidden: Boolean,
): ApiResponse<Unit>
@PUT("api/im/conversations/{targetId}/group")
suspend fun setConversationGroup(
@Path("targetId") targetId: String,
@Query("appId") appId: String,
@Query("chatType") chatType: String,
@Query("groupName") groupName: String? = null,
): ApiResponse<Unit>
@GET("api/im/conversation-groups")
suspend fun listConversationGroups(@Query("appId") appId: String): ApiResponse<List<String>>
@GET("api/im/conversation-groups/{groupName}")
suspend fun listConversationGroupItems(
@Path("groupName") groupName: String,
@Query("appId") appId: String,
): ApiResponse<List<ConversationGroupItem>>
@PUT("api/im/conversations/{targetId}/read")
suspend fun markRead(
@Path("targetId") targetId: String,
@ -318,4 +393,11 @@ interface ImApi {
@Query("appId") appId: String,
@Query("chatType") chatType: String,
): ApiResponse<Unit>
@POST("api/im/admin/groups/{groupId}/read-receipts")
suspend fun adminGroupReadReceipts(
@Path("groupId") groupId: String,
@Query("appId") appId: String,
@Body request: GroupReadReceiptRequest,
): ApiResponse<List<GroupReadReceiptSummary>>
}

查看文件

@ -38,6 +38,7 @@ data class ImMessage(
data class ConversationData(
val targetId: String,
val chatType: String,
val conversationGroup: String? = null,
val lastMsgContent: String? = null,
val lastMsgType: String? = null,
val lastMsgTime: Long = 0,
@ -54,9 +55,17 @@ data class ImGroup(
val memberIds: String,
val adminIds: String,
val announcement: String? = null,
val memberInfo: String? = null,
val extAttributes: String? = null,
val createdAt: Long,
)
data class ConversationGroupItem(
val targetId: String,
val chatType: String,
val groupName: String,
)
data class UserProfile(
val userId: String,
val nickname: String,
@ -93,6 +102,21 @@ data class BlacklistEntry(
val createdAt: Long,
)
data class BlacklistCheckResult(
val targetUserId: String,
val blockedByMe: Boolean,
val blockedByTarget: Boolean,
val eitherBlocked: Boolean,
)
data class GroupReadReceiptSummary(
val messageId: String,
val groupId: String,
val memberCount: Int,
val readCount: Int,
val unreadCount: Int,
)
enum class ChatType { SINGLE, GROUP }
enum class MsgType {