docs(deploy): 移除 Jenkins 配置和 Android Demo 计划文档

- 删除 jenkins-setup.md 完整的 Jenkins 服务配置指南
- 更新 README.md 部署文档标题为公有化部署文档
- 添加私有化部署说明章节和相关设计文档链接
- 从 REST API 设计文档中移除 demo-service 相关描述
- 更新推送架构图中业务服务端描述为客户端服务器
- 删除 android-demo-plan.md Android Demo 开发计划文档
- 删除 multi-platform-im-roadmap.md 多平台 IM 路线图文档
- 删除 java-im-server-sdk-plan.md Java IM 服务端 SDK 计划文档
这个提交包含在:
XuqmGroup 2026-05-18 17:57:04 +08:00
父节点 7217b6bcfc
当前提交 b1e5c52edf
共有 4 个文件被更改,包括 0 次插入563 次删除

查看文件

@ -1,130 +0,0 @@
# iOS SDK 测试报告
> **生成时间**: 2026-05-01
> **版本**: 0.1.0
> **测试状态**: 部分功能待测试
---
## 测试环境
| 项目 | 版本/配置 |
|------|-----------|
| Xcode | 16.0 |
| iOS 模拟器 | iPhone 16 ProiOS 18.0 |
| Swift | 5.9+ |
| Swift Tools Version | 5.9 |
| 最低 iOS 版本 | iOS 14 |
---
## 测试用例清单
### TC-01 SDK 初始化测试
| 字段 | 内容 |
|------|------|
| **测试目的** | 验证 SDK 初始化及模块配置 |
| **测试步骤** | 1. 在 `AppDelegate` 中调用 `XuqmSDK.shared.initialize(config: SDKConfig(appKey:appSecret:))` <br> 2. 确认 `XuqmSDK.shared.requireConfig()` 返回有效配置 <br> 3. 确认 `ApiClient.shared` 已配置 baseURL 与拦截器 |
| **预期结果** | 1. 初始化成功,无 fatalError <br> 2. `config.appKey` 与传入值一致 <br> 3. `TokenStore` 已实例化 |
| **实际结果** | 待测试 |
| **通过状态** | ⬜ |
---
### TC-02 IM 登录/登出测试UserSig 模式)
| 字段 | 内容 |
|------|------|
| **测试目的** | 验证 UserSig 鉴权登录与登出流程 |
| **测试步骤** | 1. 调用 `XuqmSDK.shared.login(userId: "user_001", userSig: "xxx")` <br> 2. 观察 `ImSDK.shared.login` 内部触发 WebSocket 连接 <br> 3. 监听 `ImEventDelegate.imClientDidConnect()` <br> 4. 调用 `XuqmSDK.shared.logout()` <br> 5. 确认 `ImSDK.shared.disconnect()` 执行,Push Token 解注册 |
| **预期结果** | 1. `currentUserId` 被赋值 <br> 2. WebSocket 连接成功,状态变为 `.connecting``.connected` <br> 3. delegate `imClientDidConnect()` 触发 <br> 4. 登出后 `currentUserId` 置 nil <br> 5. `PushSDK.shared.unregisterToken` 被调用 |
| **实际结果** | 待测试 |
| **通过状态** | ⬜ |
---
### TC-03 单聊消息收发测试
| 字段 | 内容 |
|------|------|
| **测试目的** | 验证单聊消息发送、接收、历史与已读 |
| **测试步骤** | 1. 调用 `ImSDK.shared.sendTextMessage(toId:chatType:content:)` <br> 2. 接收方通过 `ImEventDelegate.imClientDidReceiveMessage(_:)` 接收 <br> 3. 调用 `fetchHistory(toId:page:size:)` <br> 4. 调用 `markRead(targetId:chatType:)` <br> 5. 发送方重新拉取历史,确认 `status == .read` |
| **预期结果** | 1. 返回 `ImMessage`,`status` 为 `.sending``.sent` <br> 2. 接收方实时收到消息,未读角标 +1 <br> 3. 历史消息返回 `[ImMessage]` <br> 4. `markRead` HTTP 200,未读清零 <br> 5. 发送方消息状态更新为 `.read` |
| **实际结果** | 待测试 |
| **通过状态** | ⬜ |
---
### TC-04 群聊消息收发测试
| 字段 | 内容 |
|------|------|
| **测试目的** | 验证群创建、订阅、群消息收发与历史 |
| **测试步骤** | 1. 调用 `createGroup(name:memberIds:groupType:)` <br> 2. 双端调用 `subscribeGroup(_:)` <br> 3. 发送方调用 `sendTextMessage(toId:chatType:content:)`chatType=.group <br> 4. 接收方通过 `imClientDidReceiveGroupMessage(_:)` 接收 <br> 5. 双端调用 `fetchGroupHistory(groupId:page:size:)` |
| **预期结果** | 1. 返回 `ImGroup`,`memberIds` 包含指定用户 <br> 2. WebSocket 订阅 `/topic/group/{groupId}` 成功 <br> 3. 群消息发送成功 <br> 4. 群成员实时收到消息 <br> 5. 群历史正确分页 |
| **实际结果** | 待测试 |
| **通过状态** | ⬜ |
---
### TC-05 连接状态监听测试(新增)
| 字段 | 内容 |
|------|------|
| **测试目的** | 验证 `connectionState` 属性与 `addConnectionStateListener` 回调 |
| **测试步骤** | 1. 添加 `addConnectionStateListener { state in print(state) }` <br> 2. 触发登录,观察状态流转 <br> 3. 手动断开网络,观察重连状态 <br> 4. 恢复网络,观察恢复为 `.connected` <br> 5. 调用 `disconnect()`,观察 `.disconnected` |
| **预期结果** | 1. 监听器被加入数组 <br> 2. 登录时状态变化:`.disconnected` → `.connecting``.connected` <br> 3. 断网后状态变为 `.disconnected` 并触发重连 <br> 4. 恢复网络后回到 `.connected` <br> 5. `disconnect()` 后状态为 `.disconnected`,监听器仍保留(不移除) |
| **实际结果** | 待测试 |
| **通过状态** | ⬜ |
---
### TC-06 Push 设备注册测试APNs + FCM
| 字段 | 内容 |
|------|------|
| **测试目的** | 验证 APNs 设备 Token 获取、注册与 FCM 备选方案 |
| **测试步骤** | 1. 在 `AppDelegate` 中调用 `PushSDK.shared.requestAuthorization()` <br> 2. 系统授权后 `UIApplication.shared.registerForRemoteNotifications()` <br> 3. 在 `didRegisterForRemoteNotificationsWithDeviceToken` 中调用 `XuqmSDK.shared.registerDeviceToken(_:)` <br> 4. 确认 `PushSDK.shared.registerToken(token:userId:vendor:)` 调用vendor=.apns <br> 5. 若集成 Firebase,验证 `registerFcmToken` 路径 |
| **预期结果** | 1. `requestAuthorization` 返回 `true` <br> 2. 系统弹窗申请通知权限 <br> 3. `cachedDeviceToken` 被保存 <br> 4. `/api/push/register` 返回 200 <br> 5. FCM 路径返回 vendor=FCM,注册成功 |
| **实际结果** | 待测试 |
| **通过状态** | ⬜ |
---
### TC-07 版本更新检查测试
| 字段 | 内容 |
|------|------|
| **测试目的** | 验证 UpdateSDK 检查 App Store 更新 |
| **测试步骤** | 1. 调用 `UpdateSDK.shared.checkAppUpdate(currentVersionCode: 1)` <br> 2. 若 `needsUpdate=true``forceUpdate=true`,调用 `openAppStore(url:)` <br> 3. 观察是否能正确跳转到 App Store 或下载页 |
| **预期结果** | 1. 返回 `AppUpdateInfo`,`platform=IOS` <br> 2. `forceUpdate` 为布尔值,下载链接有效 <br> 3. `UIApplication.shared.open` 成功跳转 |
| **实际结果** | 待测试 |
| **通过状态** | ⬜ |
---
### TC-08 UserSig 匹配登录测试(新增)
| 字段 | 内容 |
|------|------|
| **测试目的** | 验证 `XuqmSDK` 仅按 `userId + userSig` 建立 IM 登录态,不解析生命周期字段 |
| **测试步骤** | 1. 使用业务服务端签发的 UserSig 调用 `XuqmSDK.shared.login(userId:userSig:)` <br> 2. 观察 `ImSDK.shared.login` 建立 WebSocket 连接 <br> 3. 保持连接并确认 SDK 侧不启动生命周期 Timer <br> 4. 再次传入同一 `userId` 与匹配的新 UserSig 调用 `login` |
| **预期结果** | 1. SDK 只保存当前 `userId``userSig` <br> 2. 不解析 JWT `exp`,不触发生命周期回调 <br> 3. 重新登录会覆盖当前会话并重连 IM |
| **实际结果** | 待测试 |
| **通过状态** | ⬜ |
---
## 测试汇总
| 用例编号 | 用例名称 | 状态 |
|---------|---------|------|
| TC-01 | SDK 初始化测试 | ⬜ 待测试 |
| TC-02 | IM 登录/登出测试UserSig 模式) | ⬜ 待测试 |
| TC-03 | 单聊消息收发测试 | ⬜ 待测试 |
| TC-04 | 群聊消息收发测试 | ⬜ 待测试 |
| TC-05 | 连接状态监听测试 | ⬜ 待测试 |
| TC-06 | Push 设备注册测试APNs + FCM | ⬜ 待测试 |
| TC-07 | 版本更新检查测试 | ⬜ 待测试 |
| TC-08 | UserSig 匹配登录测试 | ⬜ 待测试 |

查看文件

@ -1,65 +0,0 @@
# XuqmDemo
XuqmGroup iOS SDK 的 SwiftUI 演示应用。
## 功能
- **登录**:使用 demo-service 登录(`user_a` / `123456`
- **会话列表**:展示最近会话,支持搜索、置顶、静音、删除
- **单聊**:与某个用户收发文本消息
- **更新检查**:检查 App 更新
- **个人资料**:展示并修改当前用户信息
## 环境
- 演示服务器:`https://dev.xuqinmin.com`
- App ID`ak_demo_chat`
## 运行方式
### 方式一:嵌入 Xcode 项目
1. 将 `XuqmDemo/Sources` 下的所有 Swift 文件拖入你的 Xcode iOS App 项目
2. 确保项目已依赖 `XuqmSDK`(本地 SPM 或源码引用)
3. 构建并运行
### 方式二Swift Package Manager验证编译
```bash
cd XuqmDemo
swift build
```
> 注:由于 Demo 是 iOS SwiftUI 应用,建议使用 Xcode 打开 `XuqmGroup-iOSSDK` 仓库,然后新建一个 iOS App Target 并将 `XuqmDemo/Sources` 中的文件加入该 Target 进行真机/模拟器运行。
## 项目结构
```
XuqmDemo/
Package.swift
Sources/
XuqmDemoApp.swift # @main 入口,初始化 SDK 与路由
Views/
LoginView.swift # 登录页
ConversationListView.swift # 会话列表页
ChatView.swift # 单聊页
UpdateCheckView.swift # 更新检查页
ProfileView.swift # 个人资料页
ViewModels/
AuthViewModel.swift # 登录/登出逻辑
ConversationViewModel.swift# 会话列表逻辑
ChatViewModel.swift # 聊天逻辑(含 ImEventDelegate 桥接)
Models/
DemoModels.swift # 路由、状态、辅助函数
README.md
```
## 关键 SDK API 使用
- `XuqmSDK.shared.initialize(config:)` — 初始化 SDK
- `ImSDK.shared.loginWithDemo(userId:password:)` — Demo 登录
- `ImSDK.shared.listConversations()` — 获取会话列表
- `ImSDK.shared.fetchHistory(toId:page:size:)` — 获取历史消息
- `ImSDK.shared.sendTextMessage(toId:chatType:content:)` — 发送文本消息
- `ImSDK.shared.getProfile(userId:)` / `updateProfile(...)` — 用户资料
- `UpdateSDK.shared.checkAppUpdate(currentVersionCode:)` — 检查更新

查看文件

@ -1,279 +0,0 @@
# 部署文档
## 一、基础设施要求
| 组件 | 版本 | 说明 |
|------|------|------|
| JDK | 21 | GraalVM 或 Eclipse Temurin |
| MySQL | 8.0+ | 4 个独立数据库 |
| Redis | 7.x | 验证码、会话标记 |
| Nginx | 1.24+ | 前端静态 + API 反代 |
| Maven | 3.9+ | 后端构建 |
| Node.js | 22+ | 前端构建 |
---
## 二、数据库初始化
服务启动时通过 `ddl-auto: update` 自动建表,只需提前创建数据库:
```sql
CREATE DATABASE xuqm_tenant CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE DATABASE xuqm_im CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE DATABASE xuqm_push CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE DATABASE xuqm_update CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
```
---
## 三、后端构建与启动
### 构建
```bash
cd XuqmGroup-Server
mvn clean package -DskipTests
```
各模块 jar 生成于 `{module}/target/{module}-0.1.0-SNAPSHOT.jar`
### 环境变量
**tenant-service**:8081
```bash
export SPRING_DATASOURCE_URL=jdbc:mysql://db:3306/xuqm_tenant?...
export SPRING_DATASOURCE_USERNAME=xuqm
export SPRING_DATASOURCE_PASSWORD=your_db_password
export SPRING_DATA_REDIS_HOST=redis
export SPRING_MAIL_USERNAME=noreply@xuqm.com
export SPRING_MAIL_PASSWORD=your_smtp_password
export JWT_SECRET=your_256bit_secret
export OPS_ADMIN_USERNAME=admin
export OPS_ADMIN_PASSWORD=your_ops_password
```
**im-service**:8082
```bash
export SPRING_DATASOURCE_URL=jdbc:mysql://db:3306/xuqm_im?...
export SPRING_DATASOURCE_USERNAME=xuqm
export SPRING_DATASOURCE_PASSWORD=your_db_password
export SPRING_DATA_REDIS_HOST=redis
export JWT_SECRET=your_256bit_secret_im
```
**push-service**:8083
```bash
export SPRING_DATASOURCE_URL=jdbc:mysql://db:3306/xuqm_push?...
export SPRING_DATASOURCE_USERNAME=xuqm
export SPRING_DATASOURCE_PASSWORD=your_db_password
export JWT_SECRET=your_256bit_secret_push
# 华为推送
export HUAWEI_APP_ID=your_huawei_app_id
export HUAWEI_APP_SECRET=your_huawei_secret
# 小米推送
export XIAOMI_APP_SECRET=your_xiaomi_secret
# iOS APNs
export APNS_KEY_ID=your_key_id
export APNS_TEAM_ID=your_team_id
export APNS_KEY_PATH=/opt/xuqm/apns_key.p8
export APNS_BUNDLE_ID=com.yourcompany.app
```
**update-service**:8084
```bash
export SPRING_DATASOURCE_URL=jdbc:mysql://db:3306/xuqm_update?...
export SPRING_DATASOURCE_USERNAME=xuqm
export SPRING_DATASOURCE_PASSWORD=your_db_password
export JWT_SECRET=your_256bit_secret_update
export UPDATE_UPLOAD_DIR=/data/xuqm/update
export UPDATE_BASE_URL=https://update.xuqm.com
```
### 启动
```bash
java -jar tenant-service/target/tenant-service-*.jar &
java -jar im-service/target/im-service-*.jar &
java -jar push-service/target/push-service-*.jar &
java -jar update-service/target/update-service-*.jar &
```
---
## 四、前端构建与部署
```bash
cd XuqmGroup-Web
yarn install
yarn workspace tenant-platform build # dist/ → /var/www/tenant
yarn workspace ops-platform build # dist/ → /var/www/ops
```
### Nginx 配置
```nginx
# 租户开放平台
server {
listen 80;
server_name tenant.xuqm.com;
root /var/www/tenant;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
location /api/ {
proxy_pass http://127.0.0.1:8081/api/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
# 运营管理平台
server {
listen 80;
server_name ops.xuqm.com;
root /var/www/ops;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
location /api/ {
proxy_pass http://127.0.0.1:8081/api/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
# IM WebSocket 反代
server {
listen 80;
server_name im.xuqm.com;
location /ws/im {
proxy_pass http://127.0.0.1:8082;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 86400;
}
location /api/im/ {
proxy_pass http://127.0.0.1:8082/api/im/;
}
}
# 版本管理文件服务
server {
listen 80;
server_name update.xuqm.com;
location / {
proxy_pass http://127.0.0.1:8084/;
}
}
```
---
## 五、Docker Compose可选
```yaml
version: '3.9'
services:
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_USER: xuqm
MYSQL_PASSWORD: xuqm_password
volumes:
- mysql_data:/var/lib/mysql
ports:
- "3306:3306"
redis:
image: redis:7-alpine
ports:
- "6379:6379"
tenant-service:
image: eclipse-temurin:21-jre
volumes:
- ./XuqmGroup-Server/tenant-service/target:/app
command: java -jar /app/tenant-service-0.1.0-SNAPSHOT.jar
environment:
SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/xuqm_tenant?...
SPRING_DATA_REDIS_HOST: redis
ports:
- "8081:8081"
depends_on: [mysql, redis]
im-service:
image: eclipse-temurin:21-jre
volumes:
- ./XuqmGroup-Server/im-service/target:/app
command: java -jar /app/im-service-0.1.0-SNAPSHOT.jar
ports:
- "8082:8082"
depends_on: [mysql, redis]
push-service:
image: eclipse-temurin:21-jre
volumes:
- ./XuqmGroup-Server/push-service/target:/app
command: java -jar /app/push-service-0.1.0-SNAPSHOT.jar
ports:
- "8083:8083"
depends_on: [mysql]
update-service:
image: eclipse-temurin:21-jre
volumes:
- ./XuqmGroup-Server/update-service/target:/app
- update_files:/data/xuqm/update
command: java -jar /app/update-service-0.1.0-SNAPSHOT.jar
environment:
UPDATE_UPLOAD_DIR: /data/xuqm/update
ports:
- "8084:8084"
depends_on: [mysql]
volumes:
mysql_data:
update_files:
```
---
## 六、发版流程汇总
| 平台 | 步骤 |
|------|------|
| **后端** | `mvn clean package` → 替换 jar → 重启服务 |
| **前端** | `yarn build` → 替换 `dist/` → Nginx 无需重启 |
| **Android SDK** | 修改版本号 → `./gradlew publish` → Nexus |
| **iOS SDK (SPM)** | 修改版本号 → `git tag x.y.z && git push origin x.y.z` |
| **iOS SDK (CocoaPods)** | `pod repo push xuqm-specs XuqmSDK.podspec` |
| **RN SDK** | 修改 `package.json` version → `npm publish` |
| **Vue3 SDK** | 修改 `package.json` version → `npm run build && npm publish` |
| **HarmonyOS SDK** | 修改 `oh-package.json5` version → `ohpm publish` |
---
## 七、健康检查
各服务均暴露 Spring Actuator 端点:
```bash
curl http://localhost:8081/actuator/health
curl http://localhost:8082/actuator/health
curl http://localhost:8083/actuator/health
curl http://localhost:8084/actuator/health
```
正常返回:`{"status":"UP"}`

查看文件

@ -1,89 +0,0 @@
# XuqmGroup 平台文档总览
> 版本0.1.0 | 最后更新2026-04-21
## 仓库索引
| 仓库 | 语言/框架 | Gogs 地址 | 说明 |
|------|-----------|-----------|------|
| [XuqmGroup-Server](./server/README.md) | Java 21 / Spring Boot 3.4 | https://xuqinmin.com/xuqinmin12/XuqmGroup-Server | 后端多模块服务 |
| [XuqmGroup-Web](./web/README.md) | Vue 3.5 / TypeScript | https://xuqinmin.com/xuqinmin12/XuqmGroup-Web | 租户平台 + 运营平台前端 |
| [XuqmGroup-AndroidSDK](./android-sdk/README.md) | Kotlin 2.3 / AGP 9.1 | https://xuqinmin.com/xuqinmin12/XuqmGroup-AndroidSDK | Android SDK |
| [XuqmGroup-iOSSDK](./ios-sdk/README.md) | Swift 5.9 / iOS 16+ | https://xuqinmin.com/xuqinmin12/XuqmGroup-iOSSDK | iOS SDK |
| [XuqmGroup-RNSDK](./rn-sdk/README.md) | TypeScript / RN 0.76+ | https://xuqinmin.com/xuqinmin12/XuqmGroup-RNSDK | React Native SDK |
| [XuqmGroup-Vue3SDK](./vue3-sdk/README.md) | TypeScript / Vue 3.5 | https://xuqinmin.com/xuqinmin12/XuqmGroup-Vue3SDK | Vue3 Web SDK |
| [XuqmGroup-HarmonySDK](./harmony-sdk/README.md) | ArkTS / HarmonyOS 5 | https://xuqinmin.com/xuqinmin12/XuqmGroup-HarmonySDK | 鸿蒙 SDK |
## 整体架构
```
┌─────────────────────────────────────────────────────────────┐
│ 客户端层 │
│ Android SDK iOS SDK RN SDK Vue3 SDK HarmonyOS SDK │
└───────────────────────────┬─────────────────────────────────┘
│ HTTPS / WSS
┌───────────────────────────▼─────────────────────────────────┐
│ 服务端层 │
│ ┌────────────┐ ┌──────────┐ ┌───────────┐ ┌────────────┐ │
│ │tenant-svc │ │im-service│ │push-svc │ │update-svc │ │
│ │ :8081 │ │ :8082 │ │ :8083 │ │ :8084 │ │
│ └─────┬──────┘ └────┬─────┘ └─────┬─────┘ └──────┬─────┘ │
│ └─────────────┴─────────────┴───────────────┘ │
│ ↓ JPA / JDBC │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ MySQL 8 (xuqm_tenant / xuqm_im / xuqm_push / │ │
│ │ xuqm_update) + Redis 7 │ │
│ └──────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ 前端层 │
│ 租户开放平台 :5173 运营管理平台 :5174 │
└─────────────────────────────────────────────────────────────┘
```
## 核心概念
| 概念 | 说明 |
|------|------|
| **租户 (Tenant)** | 在开放平台注册的主账号,可创建子账号 |
| **应用 (App)** | 租户创建的业务应用,具有唯一 appKey/appSecret |
| **功能服务 (FeatureService)** | 挂载在 App 下的服务实例IM / 推送 / 版本管理,按平台Android / iOS / HarmonyOS独立开启 |
| **IM 账号** | 业务方通过 appKey 在 IM 服务创建的用户,仅存 userId,不存昵称/头像 |
| **运营平台** | 内部管理后台,独立账号体系,不与租户共用 |
## 统一响应格式
所有 HTTP 接口均返回:
```json
{
"code": 200,
"status": "0",
"data": { ... },
"message": "success"
}
```
| 字段 | 含义 |
|------|------|
| `code` | HTTP 语义码,200 成功,4xx/5xx 失败 |
| `status` | `"0"` 成功,`"1"` 业务失败 |
| `data` | 业务数据,失败时为 null |
| `message` | 错误描述 |
## 认证方式
- **租户平台**`Authorization: Bearer <tenant_jwt>`,由 `POST /api/auth/login` 颁发
- **IM 服务**`Authorization: Bearer <im_jwt>`,由 `POST /api/im/auth/login` 颁发;WebSocket 连接时通过 URL 参数 `?token=<im_jwt>` 传递
- **运营平台**`Authorization: Bearer <ops_jwt>`,由 `POST /api/auth/ops/login` 颁发
## 发版信息
| 平台 | Registry | 命令 |
|------|----------|------|
| npm (RN SDK / Vue3 SDK) | https://nexus.xuqinmin.com/repository/npm-hosted/ | `npm publish` |
| Android Maven | https://nexus.xuqinmin.com/repository/android-hosted/ | `./gradlew publish` |
| iOS SPM | Git Tag | `git tag x.y.z && git push origin x.y.z` |
| iOS CocoaPods | https://xuqinmin.com/xuqinmin12/xuqm-specs | `pod repo push xuqm-specs XuqmSDK.podspec` |
| HarmonyOS | ohpm (OpenHarmony Package Manager) | `ohpm publish` |