2026-04-21 22:25:33 +08:00
|
|
|
|
# XuqmGroup Android SDK 文档
|
|
|
|
|
|
|
|
|
|
|
|
> Kotlin 2.3.10 · AGP 9.1.0 · minSdk 24 · compileSdk 36
|
|
|
|
|
|
|
|
|
|
|
|
## 模块结构
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
XuqmGroup-AndroidSDK/
|
2026-04-27 19:00:54 +08:00
|
|
|
|
├── sdk-core/ # 核心:初始化、HTTP、Token 存储、通用工具/组件
|
2026-04-21 22:25:33 +08:00
|
|
|
|
├── sdk-im/ # IM:WebSocket 实时通信
|
|
|
|
|
|
├── sdk-push/ # 推送:设备 Token 注册
|
|
|
|
|
|
├── sdk-update/ # 版本管理:检查更新、下载安装、RN 热更新
|
|
|
|
|
|
└── sample-app/ # 示例 App(Jetpack Compose)
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## 集成
|
|
|
|
|
|
|
|
|
|
|
|
### Gradle(Maven 私有仓库)
|
|
|
|
|
|
|
|
|
|
|
|
在项目根 `settings.gradle.kts` 添加仓库:
|
|
|
|
|
|
```kotlin
|
|
|
|
|
|
dependencyResolutionManagement {
|
|
|
|
|
|
repositories {
|
|
|
|
|
|
maven {
|
|
|
|
|
|
url = uri("https://nexus.xuqinmin.com/repository/android-hosted/")
|
|
|
|
|
|
credentials {
|
|
|
|
|
|
username = providers.gradleProperty("NEXUS_USER").orNull ?: ""
|
|
|
|
|
|
password = providers.gradleProperty("NEXUS_PASSWORD").orNull ?: ""
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
在 `gradle.properties` 或环境变量中配置:
|
|
|
|
|
|
```properties
|
|
|
|
|
|
NEXUS_USER=your_username
|
|
|
|
|
|
NEXUS_PASSWORD=your_password
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
引入依赖:
|
|
|
|
|
|
```kotlin
|
|
|
|
|
|
dependencies {
|
|
|
|
|
|
implementation("com.xuqm:sdk-core:0.1.0")
|
|
|
|
|
|
implementation("com.xuqm:sdk-im:0.1.0") // 可选
|
|
|
|
|
|
implementation("com.xuqm:sdk-push:0.1.0") // 可选
|
|
|
|
|
|
implementation("com.xuqm:sdk-update:0.1.0") // 可选
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## 快速开始
|
|
|
|
|
|
|
|
|
|
|
|
### 1. 初始化(Application.onCreate)
|
|
|
|
|
|
|
|
|
|
|
|
```kotlin
|
2026-04-27 19:00:54 +08:00
|
|
|
|
XuqmSDK.initialize(
|
2026-04-21 22:25:33 +08:00
|
|
|
|
context = this,
|
2026-04-27 19:00:54 +08:00
|
|
|
|
appId = "ak_your_app_id",
|
2026-04-21 22:25:33 +08:00
|
|
|
|
debug = BuildConfig.DEBUG
|
|
|
|
|
|
)
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2026-04-27 19:00:54 +08:00
|
|
|
|
### 2. 用户登录后初始化 IM
|
2026-04-21 22:25:33 +08:00
|
|
|
|
|
|
|
|
|
|
```kotlin
|
2026-04-27 19:00:54 +08:00
|
|
|
|
// 调用业务登录接口,拿到 userSig 后再登录 IM
|
|
|
|
|
|
val userSig = api.getUserSig(userId)
|
|
|
|
|
|
ImSDK.login(userId = userId, userSig = userSig)
|
|
|
|
|
|
|
|
|
|
|
|
// Push 设备注册在 PushSDK.initialize() 内部自动完成
|
2026-04-21 22:25:33 +08:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## sdk-core
|
|
|
|
|
|
|
|
|
|
|
|
### SDKConfig
|
|
|
|
|
|
|
|
|
|
|
|
| 参数 | 类型 | 说明 |
|
|
|
|
|
|
|------|------|------|
|
2026-04-27 19:00:54 +08:00
|
|
|
|
| `appId` | String | 应用标识(租户平台获取) |
|
2026-04-21 22:25:33 +08:00
|
|
|
|
| `debug` | Boolean | 开启日志 |
|
|
|
|
|
|
|
|
|
|
|
|
### TokenStore
|
|
|
|
|
|
|
|
|
|
|
|
基于 `DataStore<Preferences>` 持久化存储。
|
|
|
|
|
|
|
|
|
|
|
|
```kotlin
|
|
|
|
|
|
// 存储
|
|
|
|
|
|
XuqmSDK.tokenStore.save("eyJ...")
|
|
|
|
|
|
|
|
|
|
|
|
// 读取(协程)
|
|
|
|
|
|
val token = XuqmSDK.tokenStore.get()
|
|
|
|
|
|
|
|
|
|
|
|
// 清除(登出)
|
|
|
|
|
|
XuqmSDK.tokenStore.clear()
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### ApiClient
|
|
|
|
|
|
|
|
|
|
|
|
基于 OkHttp 5 + Retrofit 3,自动附加 Bearer Token,统一解析 `ApiResponse<T>`。
|
|
|
|
|
|
|
|
|
|
|
|
```kotlin
|
|
|
|
|
|
// 通过 RetrofitFactory 获取接口实例
|
|
|
|
|
|
val service = RetrofitFactory.create(MyApiService::class.java)
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## sdk-im
|
|
|
|
|
|
|
|
|
|
|
|
### ImClient
|
|
|
|
|
|
|
|
|
|
|
|
```kotlin
|
|
|
|
|
|
val imClient = ImClient()
|
|
|
|
|
|
|
|
|
|
|
|
// 注册事件监听
|
|
|
|
|
|
imClient.listener = object : ImEventListener {
|
|
|
|
|
|
override fun onConnected() { /* WebSocket 连接成功 */ }
|
|
|
|
|
|
override fun onDisconnected(code: Int, reason: String) { /* 断开 */ }
|
|
|
|
|
|
override fun onMessage(msg: ImMessage) { /* 收到新消息 */ }
|
|
|
|
|
|
override fun onRevoke(msgId: String, operatorId: String) { /* 消息被撤回 */ }
|
|
|
|
|
|
override fun onError(t: Throwable) { /* 连接错误 */ }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 连接
|
|
|
|
|
|
imClient.connect()
|
|
|
|
|
|
|
|
|
|
|
|
// 发送消息
|
|
|
|
|
|
imClient.send(SendMessageParams(
|
|
|
|
|
|
toId = "user_002",
|
|
|
|
|
|
chatType = ChatType.SINGLE,
|
|
|
|
|
|
msgType = MsgType.TEXT,
|
|
|
|
|
|
content = "Hello!"
|
|
|
|
|
|
))
|
|
|
|
|
|
|
|
|
|
|
|
// 撤回消息
|
|
|
|
|
|
imClient.revoke(msgId = "uuid")
|
|
|
|
|
|
|
|
|
|
|
|
// 断开连接(Activity/Fragment 销毁时调用)
|
|
|
|
|
|
imClient.disconnect()
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 消息类型(MsgType)
|
|
|
|
|
|
|
|
|
|
|
|
`TEXT` / `IMAGE` / `VIDEO` / `AUDIO` / `FILE` / `CUSTOM` / `LOCATION` / `NOTIFY` / `RICH_TEXT` / `CALL_AUDIO` / `CALL_VIDEO` / `FORWARD`
|
|
|
|
|
|
|
|
|
|
|
|
### ImMessage 结构
|
|
|
|
|
|
|
|
|
|
|
|
```kotlin
|
|
|
|
|
|
data class ImMessage(
|
|
|
|
|
|
val id: String,
|
|
|
|
|
|
val fromId: String,
|
|
|
|
|
|
val toId: String,
|
|
|
|
|
|
val chatType: ChatType, // SINGLE / GROUP
|
|
|
|
|
|
val msgType: MsgType,
|
|
|
|
|
|
val content: String,
|
|
|
|
|
|
val extra: String?,
|
|
|
|
|
|
val revoked: Boolean,
|
|
|
|
|
|
val createdAt: String
|
|
|
|
|
|
)
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 自动重连
|
|
|
|
|
|
|
|
|
|
|
|
断线后指数退避重连,初始间隔 3 秒,最大间隔 30 秒。调用 `disconnect()` 后停止重连。
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## sdk-push
|
|
|
|
|
|
|
2026-04-27 19:00:54 +08:00
|
|
|
|
### 推送接入
|
2026-04-21 22:25:33 +08:00
|
|
|
|
|
2026-04-27 19:00:54 +08:00
|
|
|
|
在 `PushSDK.initialize()` 后由 SDK 自动完成厂商初始化、设备注册与 token 上传,不再要求业务侧单独调用注册接口。
|
2026-04-21 22:25:33 +08:00
|
|
|
|
|
|
|
|
|
|
### 与 IM 联动
|
|
|
|
|
|
|
|
|
|
|
|
当 IM 和推送服务均已开启时,IM 服务在目标用户离线时会自动调用推送服务发送离线推送通知。
|
|
|
|
|
|
业务方只需分别注册推送 Token 和 IM 登录,无需额外配置。
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## sdk-update
|
|
|
|
|
|
|
|
|
|
|
|
### 检查原生 App 更新
|
|
|
|
|
|
|
|
|
|
|
|
```kotlin
|
|
|
|
|
|
val result: UpdateResult = UpdateSDK.checkUpdate(
|
|
|
|
|
|
appId = "ak_xxx",
|
|
|
|
|
|
platform = Platform.ANDROID
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
if (result.needsUpdate) {
|
|
|
|
|
|
// result.versionName, result.downloadUrl, result.forceUpdate
|
|
|
|
|
|
UpdateSDK.downloadAndInstall(context, result.downloadUrl)
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
`downloadAndInstall` 会将 APK 下载到 `getExternalFilesDir(null)`,通过 `FileProvider` 触发系统安装。
|
|
|
|
|
|
AndroidManifest 中已配置 `@xml/file_paths`(`external-files-path`)。
|
|
|
|
|
|
|
|
|
|
|
|
### 检查 RN Bundle 更新
|
|
|
|
|
|
|
|
|
|
|
|
```kotlin
|
|
|
|
|
|
val rnResult = UpdateSDK.checkRnUpdate(
|
|
|
|
|
|
appId = "ak_xxx",
|
|
|
|
|
|
moduleId = "main",
|
|
|
|
|
|
platform = "android",
|
|
|
|
|
|
currentVersion = "1.0.0"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
if (rnResult.needsUpdate) {
|
|
|
|
|
|
val filePath = UpdateSDK.downloadBundle(context, rnResult.downloadUrl, "main.android.bundle")
|
|
|
|
|
|
// 校验 MD5
|
|
|
|
|
|
// 通知 RN 引擎加载新 bundle
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 发版
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# 在 gradle.properties 中配置 NEXUS_USER / NEXUS_PASSWORD
|
|
|
|
|
|
./gradlew :sdk-core:publish
|
|
|
|
|
|
./gradlew :sdk-im:publish
|
|
|
|
|
|
./gradlew :sdk-push:publish
|
|
|
|
|
|
./gradlew :sdk-update:publish
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
发布至 `https://nexus.xuqinmin.com/repository/android-hosted/`,groupId `com.xuqm`,版本号在各模块 `build.gradle.kts` 中维护。
|