转到文件
2026-06-08 11:22:13 +08:00
docs refactor(sdk-update): 重构版本更新检测功能 2026-06-04 13:35:59 +08:00
gradle build: 各 SDK 模块独立版本,publish.gradle 改用 project.version 2026-05-21 16:48:10 +08:00
sample-app refactor(webview): 重构WebView组件实现 2026-05-11 18:58:51 +08:00
scripts docs(test): 更新测试报告和文档 2026-05-05 16:06:32 +08:00
sdk-core feat(file): 添加文件下载完成后打开文件的功能 2026-06-05 16:28:34 +08:00
sdk-im build: 各 SDK 模块独立版本,publish.gradle 改用 project.version 2026-05-21 16:48:10 +08:00
sdk-license feat(sdk): 将许可证文件替换为初始化配置文件 2026-06-02 17:15:49 +08:00
sdk-push build: 各 SDK 模块独立版本,publish.gradle 改用 project.version 2026-05-21 16:48:10 +08:00
sdk-update refactor(sdk-update): 重构版本更新检测功能 2026-06-04 13:35:59 +08:00
sdk-webview refactor(webview): 将 WebView 活动重构为 Compose 组件 2026-06-08 11:20:17 +08:00
.gitignore build: add consumer-rules.pro and untrack local.properties 2026-04-29 16:02:57 +08:00
.java-version feat(im): 添加平台事件通知功能支持应用审核状态实时更新 2026-05-08 18:32:46 +08:00
build.gradle.kts build: 各 SDK 模块独立版本,publish.gradle 改用 project.version 2026-05-21 16:48:10 +08:00
gradle.properties ci: bump module versions [sdk-webview] 2026-06-08 11:22:13 +08:00
gradlew feat(sample): 集成 Sentry 异常监控功能 2026-04-24 16:46:38 +08:00
gradlew.bat feat(sample): 集成 Sentry 异常监控功能 2026-04-24 16:46:38 +08:00
Jenkinsfile ci: support independent versioning per SDK module 2026-05-23 04:23:07 +08:00
README.md feat(sdk): 新增文件上传下载功能并完善WebView组件 2026-06-05 15:48:08 +08:00
settings.gradle.kts Add Android license SDK 2026-05-15 21:00:24 +08:00

XuqmGroup Android SDK 文档

Kotlin 2.3.10 · AGP 9.1.0 · minSdk 24 · compileSdk 36

模块结构

XuqmGroup-AndroidSDK/
├── sdk-core/        # 核心初始化、HTTP、Token 存储、文件上传、通用工具/组件
├── sdk-im/          # IMWebSocket 实时通信
├── sdk-push/        # 推送:设备 Token 注册
├── sdk-update/      # 版本管理:检查更新、下载安装
├── sdk-webview/     # WebView嵌入式组件 / 独立页面
└── sample-app/      # 示例 AppJetpack Compose

集成

GradleMaven 私有仓库)

在项目根 settings.gradle.kts 添加仓库:

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 或环境变量中配置:

NEXUS_USER=your_username
NEXUS_PASSWORD=your_password

引入依赖:

dependencies {
    implementation("com.xuqm:sdk-core:0.4.2")
    implementation("com.xuqm:sdk-im:0.4.2")       // 可选
    implementation("com.xuqm:sdk-push:0.4.2")     // 可选
    implementation("com.xuqm:sdk-update:0.4.2")   // 可选
    implementation("com.xuqm:sdk-webview:0.4.2")   // 可选
}

快速开始

1. 初始化Application.onCreate

XuqmSDK.initialize(
    context = this,
    appKey = "ak_your_app_key",
    logLevel = if (BuildConfig.DEBUG) LogLevel.DEBUG else LogLevel.WARN
)

2. 用户登录后初始化 IM

// 调用业务登录接口,拿到 userSig 后只需要登录一次 SDK
val userSig = api.getUserSig(userId)
XuqmSDK.login(
    userId = userId,
    userSig = userSig,
)

// 如果工程里集成了 sdk-im / sdk-push / sdk-update,
// SDK 会自动完成对应模块的登录与初始化

3. WebView 独立模块

sdk-webview 不需要额外初始化,直接依赖 sdk-core 即可使用。

import com.xuqm.sdk.webview.XWebViewConfig
import com.xuqm.sdk.webview.XWebViewView
import com.xuqm.sdk.webview.XWebViewScreen
import com.xuqm.sdk.webview.openXWebView

// 嵌入式组件:直接放到页面中,不包含导航栏 / 状态栏
XWebViewView(
    config = XWebViewConfig(
        url = "https://example.com",
        title = "嵌入式网页",
    ),
)

// 独立页面:先设置配置,再跳转到页面
openXWebView(
    XWebViewConfig(
        url = "https://example.com",
        title = "独立页面",
    )
)
// navigate("xwebview") 后使用 XWebViewScreen()

3. 切换联调环境

默认使用外网域名。若要本地联调,可在 Application.onCreate() 里切换:

XuqmSDK.useLocalServiceEndpoints("192.168.113.37")
// 物理设备可改成你的电脑局域网 IP

如果是 sample-app,也可以直接调用

SampleEnvironmentConfig.useLocalhost("192.168.113.37")

切换后,HTTP API 会立即走新端点;如果 IM 已登录,SDK 会自动重新连接。

sample-app 里也提供了一个“环境设置”页面,可以直接在外网和本地联调之间切换。


sdk-core

SDKConfig

参数 类型 说明
appKey String 应用标识(租户平台获取)
logLevel LogLevel 日志等级

TokenStore

基于 EncryptedSharedPreferences 持久化存储。

// 存储
XuqmSDK.tokenStore.saveToken("eyJ...")

// 读取(协程)
val token = XuqmSDK.tokenStore.getToken()

// 清除(登出)
XuqmSDK.tokenStore.clear()

ApiClient

基于 OkHttp 5 + Retrofit 3,自动附加 Bearer Token,统一解析 ApiResponse<T>

// 通过 RetrofitFactory 获取接口实例
val service = RetrofitFactory.create(MyApiService::class.java)

FileSDK

文件上传、下载、打开的统一入口,位于 com.xuqm.sdk.file

上传

// 从 Uri文件选择器返回值上传,自动解析文件名和 MIME 类型
val result: FileUploadResult = FileSDK.upload(
    context = context,
    uri = uri,
    onProgress = { progress -> /* 0–100 */ },
)

// 直接上传字节数组(如相机拍照后的 ByteArray
val result = FileSDK.uploadBytes(
    fileName = "photo.jpg",
    mimeType = "image/jpeg",
    bytes = byteArray,
    onProgress = { progress -> },
)

// 上传 File 对象
val result = FileSDK.upload(file = file)

FileUploadResult 字段:urlthumbnailUrlhashsizeoriginalNamemimeTypeext

下载

// 下载存储目标
sealed class FileDownloadDestination {
    data object Sandbox : FileDownloadDestination()        // 应用私有目录(无需权限)
    data object PublicDownloads : FileDownloadDestination() // 系统 Downloads 文件夹
}

// 下载到指定目标,支持通知栏进度
val file: File = FileSDK.download(
    context = context,
    downloadUrl = "https://example.com/report.pdf",
    fileName = "report.pdf",                         // 可选,默认从 URL 推断
    destination = FileDownloadDestination.PublicDownloads,
    notificationTitle = "正在下载",                   // 非 null 时显示通知栏进度条
    onProgress = { progress -> /* 0–100,同步进度到 H5 或 UI */ },
)

通知栏进度:设置 notificationTitle 后,下载过程中通知栏会显示带进度条的持续通知,完成后自动切换为完成图标。需在 AndroidManifest.xml 中声明 POST_NOTIFICATIONS 权限Android 13+)。

打开文件

// 用系统应用打开本地文件(通过 FileProvider + ACTION_VIEW
FileSDK.openFile(context, file)

需在 AndroidManifest.xml 中配置 FileProvider

<provider
    android:name="androidx.core.content.FileProvider"
    android:authorities="${applicationId}.fileprovider"
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/file_paths" />
</provider>

sdk-im

Android sample 已具备

  • 会话列表先读本地缓存,再刷新网络
  • 联系人列表先读本地缓存,再刷新网络
  • 聊天历史分页加载
  • 当前会话本地搜索
  • 输入草稿自动保存
  • 群设置支持编辑群名和群公告
  • 群组扩展 API 已补齐:管理员设置、禁言、解散群
  • 公开群支持搜索、创建和加群审批
  • 会话支持本地删除
  • 显示总未读数
  • 消息状态直接展示
  • 会话置顶/免打扰/已读/草稿/删除同步服务端
  • IM 连接状态提示
  • SDK 登录态恢复后自动重连
  • 重复调用登录会覆盖当前 IM 会话并自动重连,SDK 侧不做生命周期检测或维护
  • 群聊支持 @userId 提及,并写入 mentionedUserIds
  • 关系链支持好友申请、接受/拒绝、黑名单
  • 支持图片 / 视频 / 音频 / 文件消息,文件通过独立文件服务上传后再发 IM
  • 图片支持拍照、摄像、图库选择,文件支持文件管理器选择
  • 语音支持长按录音、抬手发送
  • 支持引用回复、群聊已读人数展示
  • 支持 LOCATION / CUSTOM / RICH_TEXT / FORWARD / QUOTE / MERGE / CALL_AUDIO / CALL_VIDEO 等通用消息类型发送
  • 单聊支持已读回执,服务端会把 READ 状态推回发送者
  • sdk-webview 作为独立模块提供嵌入式组件和独立页面两种形态,可与 IM / Push / Update 任意组合

ImClient

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.send(SendMessageParams(
    toId = "group_001",
    chatType = ChatType.GROUP,
    msgType = MsgType.TEXT,
    content = "@user_002 你好",
    mentionedUserIds = "user_002",
))

// 撤回消息
imClient.revoke(msgId = "uuid")

// 断开连接Activity/Fragment 销毁时调用)
imClient.disconnect()

消息类型MsgType

TEXT / IMAGE / VIDEO / AUDIO / FILE / CUSTOM / LOCATION / NOTIFY / RICH_TEXT / CALL_AUDIO / CALL_VIDEO / FORWARD / QUOTE / MERGE

ImMessage 结构

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

推送接入

XuqmSDK.login() 成功后,SDK 会自动完成当前系统推送 token 的注册与上传,不再要求业务侧手工传入 token。logout() 时会自动注销当前设备绑定。

还可以按用户设置接收开关:

PushSDK.setReceivePush(context, enabled = false)
PushSDK.setReceivePush(context, enabled = true)

如果项目接入了 Firebase Messaging,sdk-push 会通过 FirebaseMessagingService.onNewToken() 自动接收并上报 FCM token。对应服务已经随库注册,只要应用工程提供 Firebase 配置即可生效。

与 IM 联动

当 IM 和推送服务均已开启时,IM 服务在目标用户离线时会自动调用推送服务发送离线推送通知。
业务方只需分别注册推送 Token 和 IM 登录,无需额外配置。


sdk-update

检查原生 App 更新

val result: UpdateResult = UpdateSDK.checkUpdate(
    appKey = "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_pathsexternal-files-path)。


sdk-webview

XWebViewView 是基于 android.webkit.WebView 封装的 Jetpack Compose 组件,内置文件选择、拍照、下载拦截和 JS 通信能力。

XWebViewConfig 完整参数

参数 类型 默认值 说明
url String "" 初始加载地址
title String "" 页面标题(独立页面模式使用)
hideToolbar Boolean false 隐藏独立页面顶栏
hideStatusBar Boolean false 隐藏状态栏
userAgent String? null 自定义 User-Agent
injectedJavaScript String? null 页面加载后注入的额外 JS
jsBridgeName String "XWebViewBridge" JS 桥接对象名
debugEnabled Boolean false 开启 WebView 远程调试
downloadDestination FileDownloadDestination Sandbox 下载文件存储目标
downloadNotificationTitle String? null 非 null 时通知栏显示下载进度
onMessage (String) -> Unit? null H5 发送消息的回调

文件选择与拍照

WebView 内 <input type="file"><input type="file" capture> 均已内置处理:

  • accept="image/*" + capture → 调起系统相机,自动申请 CAMERA 权限
  • accept=".docx,.xlsx" 等扩展名格式 → 自动映射为正确的 MIME 类型后调起文件选择器
  • getUserMedia() WebRTC 摄像头 → 自动请求 CAMERA 权限后授权

下载拦截

注入的 JS 自动拦截以下两种场景,下载完成后调用 FileSDK.openFile() 打开文件:

  • download 属性的 <a> 标签,或链接以可下载扩展名(.pdf.zip.docx 等)结尾
  • Blob URL自动转 base64 后传给 native 处理)
XWebViewView(
    config = XWebViewConfig(
        url = "https://example.com",
        downloadDestination = FileDownloadDestination.PublicDownloads, // 存入系统 Downloads
        downloadNotificationTitle = "正在下载",                         // 通知栏进度
    )
)

H5 监听下载进度

H5 页面可通过 window.addEventListener 接收下载进度和完成事件:

// 下载进度0–100
window.addEventListener('__xwvDownloadProgress', (e) => {
    console.log(e.detail.url, e.detail.progress)
})

// 下载完成
window.addEventListener('__xwvDownloadDone', (e) => {
    if (e.detail.success) {
        console.log('下载成功', e.detail.url)
    } else {
        console.error('下载失败', e.detail.error)
    }
})

H5 ↔ Native 消息通信

// H5 发消息给 Native触发 onMessage 回调)
window.XWebViewBridge.postMessage(JSON.stringify({ type: 'login', token: '...' }))
XWebViewConfig(
    onMessage = { raw ->
        val json = JSONObject(raw)
        when (json.optString("type")) {
            "login" -> { /* 处理登录 */ }
        }
    }
)
// Native 发消息给 H5
val controller = getXWebViewController()
controller?.postMessageToWeb("window.dispatchEvent(new CustomEvent('nativeMsg', { detail: { key: 'value' } }))")

发版

# 在 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 中维护。