feat(im): 添加即时通讯SDK核心功能
- 实现IM API接口定义,包括消息、群组、好友、黑名单等功能 - 定义IM消息相关数据模型,包含聊天类型、消息类型、用户资料等 - 实现ImSDK单例类,提供登录、消息发送、群组管理、好友管理等核心功能 - 添加WebSocket连接管理,支持自动重连机制 - 实现历史消息查询、群组操作、用户资料管理等API调用 - 添加会话状态管理,支持置顶、静音、草稿等功能 - 集成文件上传结果,支持多媒体消息发送 - 实现连接状态监听和事件回调机制
这个提交包含在:
父节点
0425c988ae
当前提交
17168dcf4e
@ -17,6 +17,8 @@ import com.xuqm.sdk.im.model.ConversationData
|
|||||||
import com.xuqm.sdk.im.model.GroupJoinRequest
|
import com.xuqm.sdk.im.model.GroupJoinRequest
|
||||||
import com.xuqm.sdk.im.model.ImGroup
|
import com.xuqm.sdk.im.model.ImGroup
|
||||||
import com.xuqm.sdk.im.model.ImMessage
|
import com.xuqm.sdk.im.model.ImMessage
|
||||||
|
import com.xuqm.sdk.im.model.PageResult
|
||||||
|
import com.xuqm.sdk.im.model.UserProfile
|
||||||
import com.xuqm.sdk.im.model.BlacklistEntry
|
import com.xuqm.sdk.im.model.BlacklistEntry
|
||||||
import com.xuqm.sdk.im.model.FriendRequest
|
import com.xuqm.sdk.im.model.FriendRequest
|
||||||
import com.xuqm.sdk.file.FileUploadResult
|
import com.xuqm.sdk.file.FileUploadResult
|
||||||
@ -447,6 +449,34 @@ object ImSDK {
|
|||||||
suspend fun listPublicGroups(keyword: String? = null): List<ImGroup> =
|
suspend fun listPublicGroups(keyword: String? = null): List<ImGroup> =
|
||||||
withContext(Dispatchers.IO) { api.listPublicGroups(XuqmSDK.appId, keyword).data ?: emptyList() }
|
withContext(Dispatchers.IO) { api.listPublicGroups(XuqmSDK.appId, keyword).data ?: emptyList() }
|
||||||
|
|
||||||
|
suspend fun searchUsers(keyword: String, size: Int = 20): List<UserProfile> =
|
||||||
|
withContext(Dispatchers.IO) { api.searchUsers(XuqmSDK.appId, keyword, size).data ?: emptyList() }
|
||||||
|
|
||||||
|
suspend fun searchGroups(keyword: String, size: Int = 20): List<ImGroup> =
|
||||||
|
withContext(Dispatchers.IO) { api.searchGroups(XuqmSDK.appId, keyword, size).data ?: emptyList() }
|
||||||
|
|
||||||
|
suspend fun searchMessages(
|
||||||
|
keyword: String? = null,
|
||||||
|
chatType: String? = null,
|
||||||
|
msgType: String? = null,
|
||||||
|
startTime: LocalDateTime? = null,
|
||||||
|
endTime: LocalDateTime? = null,
|
||||||
|
page: Int = 0,
|
||||||
|
size: Int = 20,
|
||||||
|
): PageResult<ImMessage> =
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
|
api.searchMessages(
|
||||||
|
XuqmSDK.appId,
|
||||||
|
keyword,
|
||||||
|
chatType,
|
||||||
|
msgType,
|
||||||
|
startTime?.toString(),
|
||||||
|
endTime?.toString(),
|
||||||
|
page,
|
||||||
|
size,
|
||||||
|
).data ?: PageResult()
|
||||||
|
}
|
||||||
|
|
||||||
suspend fun updateGroupInfo(groupId: String, name: String? = null, announcement: String? = null) =
|
suspend fun updateGroupInfo(groupId: String, name: String? = null, announcement: String? = null) =
|
||||||
withContext(Dispatchers.IO) { api.updateGroupInfo(groupId, UpdateGroupRequest(name, announcement)) }
|
withContext(Dispatchers.IO) { api.updateGroupInfo(groupId, UpdateGroupRequest(name, announcement)) }
|
||||||
|
|
||||||
|
|||||||
@ -83,6 +83,32 @@ interface ImApi {
|
|||||||
@Query("keyword") keyword: String? = null,
|
@Query("keyword") keyword: String? = null,
|
||||||
): ApiResponse<List<ImGroup>>
|
): ApiResponse<List<ImGroup>>
|
||||||
|
|
||||||
|
@GET("api/im/admin/users/search")
|
||||||
|
suspend fun searchUsers(
|
||||||
|
@Query("appId") appId: String,
|
||||||
|
@Query("keyword") keyword: String,
|
||||||
|
@Query("size") size: Int = 20,
|
||||||
|
): ApiResponse<List<UserProfile>>
|
||||||
|
|
||||||
|
@GET("api/im/admin/groups/search")
|
||||||
|
suspend fun searchGroups(
|
||||||
|
@Query("appId") appId: String,
|
||||||
|
@Query("keyword") keyword: String,
|
||||||
|
@Query("size") size: Int = 20,
|
||||||
|
): ApiResponse<List<ImGroup>>
|
||||||
|
|
||||||
|
@GET("api/im/admin/messages/search")
|
||||||
|
suspend fun searchMessages(
|
||||||
|
@Query("appId") appId: String,
|
||||||
|
@Query("keyword") keyword: String? = null,
|
||||||
|
@Query("chatType") chatType: String? = null,
|
||||||
|
@Query("msgType") msgType: String? = null,
|
||||||
|
@Query("startTime") startTime: String? = null,
|
||||||
|
@Query("endTime") endTime: String? = null,
|
||||||
|
@Query("page") page: Int = 0,
|
||||||
|
@Query("size") size: Int = 20,
|
||||||
|
): ApiResponse<PageResult<ImMessage>>
|
||||||
|
|
||||||
@POST("api/im/groups")
|
@POST("api/im/groups")
|
||||||
suspend fun createGroup(
|
suspend fun createGroup(
|
||||||
@Query("appId") appId: String,
|
@Query("appId") appId: String,
|
||||||
|
|||||||
@ -2,6 +2,18 @@ package com.xuqm.sdk.im.model
|
|||||||
|
|
||||||
import com.google.gson.annotations.SerializedName
|
import com.google.gson.annotations.SerializedName
|
||||||
|
|
||||||
|
data class PageResult<T>(
|
||||||
|
val content: List<T> = emptyList(),
|
||||||
|
val totalElements: Long = 0,
|
||||||
|
val totalPages: Int = 0,
|
||||||
|
val size: Int = 0,
|
||||||
|
val number: Int = 0,
|
||||||
|
val numberOfElements: Int = 0,
|
||||||
|
val first: Boolean = false,
|
||||||
|
val last: Boolean = false,
|
||||||
|
val empty: Boolean = true,
|
||||||
|
)
|
||||||
|
|
||||||
data class ImMessage(
|
data class ImMessage(
|
||||||
val id: String,
|
val id: String,
|
||||||
val appId: String,
|
val appId: String,
|
||||||
|
|||||||
@ -9,7 +9,6 @@ import com.xuqm.sdk.file.FileSDK
|
|||||||
import com.xuqm.sdk.core.ServiceEndpointRegistry
|
import com.xuqm.sdk.core.ServiceEndpointRegistry
|
||||||
import com.xuqm.sdk.network.ApiClient
|
import com.xuqm.sdk.network.ApiClient
|
||||||
import com.xuqm.sdk.update.api.UpdateApi
|
import com.xuqm.sdk.update.api.UpdateApi
|
||||||
import com.xuqm.sdk.update.model.RnUpdateInfo
|
|
||||||
import com.xuqm.sdk.update.model.UpdateInfo
|
import com.xuqm.sdk.update.model.UpdateInfo
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
@ -22,10 +21,6 @@ object UpdateSDK {
|
|||||||
private fun normalizeDownloadUrl(rawUrl: String?): String? {
|
private fun normalizeDownloadUrl(rawUrl: String?): String? {
|
||||||
if (rawUrl.isNullOrBlank()) return rawUrl
|
if (rawUrl.isNullOrBlank()) return rawUrl
|
||||||
|
|
||||||
if (rawUrl.contains("/api/v1/updates/api/v1/rn/files/")) {
|
|
||||||
return rawUrl.replace("/api/v1/updates/api/v1/rn/files/", "/api/v1/rn/files/")
|
|
||||||
}
|
|
||||||
|
|
||||||
return runCatching {
|
return runCatching {
|
||||||
val uri = Uri.parse(rawUrl)
|
val uri = Uri.parse(rawUrl)
|
||||||
if (uri.path?.startsWith("/files/apk/") == true) {
|
if (uri.path?.startsWith("/files/apk/") == true) {
|
||||||
@ -65,14 +60,4 @@ object UpdateSDK {
|
|||||||
}
|
}
|
||||||
context.startActivity(intent)
|
context.startActivity(intent)
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun checkRnUpdate(moduleId: String, currentVersion: String): RnUpdateInfo? =
|
|
||||||
withContext(Dispatchers.IO) {
|
|
||||||
XuqmSDK.requireInit()
|
|
||||||
runCatching {
|
|
||||||
api.checkRnUpdate(XuqmSDK.appId, moduleId, "ANDROID", currentVersion).data?.let {
|
|
||||||
it.copy(downloadUrl = normalizeDownloadUrl(it.downloadUrl) ?: it.downloadUrl)
|
|
||||||
}
|
|
||||||
}.getOrNull()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
package com.xuqm.sdk.update.api
|
package com.xuqm.sdk.update.api
|
||||||
|
|
||||||
import com.xuqm.sdk.update.model.UpdateInfo
|
import com.xuqm.sdk.update.model.UpdateInfo
|
||||||
import com.xuqm.sdk.update.model.RnUpdateInfo
|
|
||||||
import retrofit2.http.GET
|
import retrofit2.http.GET
|
||||||
import retrofit2.http.Query
|
import retrofit2.http.Query
|
||||||
|
|
||||||
@ -14,12 +13,4 @@ interface UpdateApi {
|
|||||||
@Query("platform") platform: String,
|
@Query("platform") platform: String,
|
||||||
@Query("currentVersionCode") currentVersionCode: Int,
|
@Query("currentVersionCode") currentVersionCode: Int,
|
||||||
): ApiResponse<UpdateInfo>
|
): ApiResponse<UpdateInfo>
|
||||||
|
|
||||||
@GET("api/v1/rn/update/check")
|
|
||||||
suspend fun checkRnUpdate(
|
|
||||||
@Query("appId") appId: String,
|
|
||||||
@Query("moduleId") moduleId: String,
|
|
||||||
@Query("platform") platform: String,
|
|
||||||
@Query("currentVersion") currentVersion: String,
|
|
||||||
): ApiResponse<RnUpdateInfo>
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,12 +10,3 @@ data class UpdateInfo(
|
|||||||
val appStoreUrl: String = "",
|
val appStoreUrl: String = "",
|
||||||
val marketUrl: String = "",
|
val marketUrl: String = "",
|
||||||
)
|
)
|
||||||
|
|
||||||
data class RnUpdateInfo(
|
|
||||||
val needsUpdate: Boolean,
|
|
||||||
val latestVersion: String = "",
|
|
||||||
val downloadUrl: String = "",
|
|
||||||
val md5: String = "",
|
|
||||||
val minCommonVersion: String = "0.0.0",
|
|
||||||
val note: String = "",
|
|
||||||
)
|
|
||||||
|
|||||||
正在加载...
在新工单中引用
屏蔽一个用户