- 新增 SDK API 重设计规范文档,统一各端 SDK 初始化、登录、消息接口 - 新增安全设计规范文档,涵盖密码安全、AppSecret 验证、令牌存储等安全要点 - 新增 Bug 跟踪记录文档,记录已修复问题和开放问题 - 新增测试进度跟踪文档,记录各模块测试覆盖情况和验证结果
239 行
7.0 KiB
Markdown
239 行
7.0 KiB
Markdown
# iOS SDK 概览
|
||
|
||
**版本**:0.1.0 · **最低 iOS 版本**:iOS 14 · **语言**:Swift 5.9+
|
||
|
||
## 功能模块
|
||
|
||
| 模块 | 功能 |
|
||
|------|------|
|
||
| XuqmCore | 初始化、网络、鉴权 |
|
||
| XuqmIM | 单聊、群聊、消息收发(15 种类型)、连接状态监听 |
|
||
| XuqmPush | APNs 设备 Token 注册、FCM 备选、通知处理 |
|
||
| XuqmUpdate | App 版本检查、App Store 跳转 |
|
||
|
||
## 安装
|
||
|
||
### Swift Package Manager(推荐)
|
||
|
||
在 Xcode → File → Add Package Dependencies 中输入:
|
||
|
||
```
|
||
https://github.com/xuqm/XuqmGroup-iOSSDK
|
||
```
|
||
|
||
或在 `Package.swift` 中添加:
|
||
|
||
```swift
|
||
dependencies: [
|
||
.package(url: "https://github.com/xuqm/XuqmGroup-iOSSDK", from: "0.1.0")
|
||
]
|
||
```
|
||
|
||
按需引入所需模块:
|
||
|
||
```swift
|
||
.target(
|
||
name: "MyApp",
|
||
dependencies: [
|
||
.product(name: "XuqmCore", package: "XuqmGroup-iOSSDK"),
|
||
.product(name: "XuqmIM", package: "XuqmGroup-iOSSDK"),
|
||
.product(name: "XuqmPush", package: "XuqmGroup-iOSSDK"),
|
||
.product(name: "XuqmUpdate", package: "XuqmGroup-iOSSDK"),
|
||
]
|
||
)
|
||
```
|
||
|
||
## 快速接入
|
||
|
||
### 1. 初始化
|
||
|
||
在 `AppDelegate.application(_:didFinishLaunchingWithOptions:)` 中:
|
||
|
||
```swift
|
||
import XuqmCore
|
||
|
||
let config = SDKConfig(appId: "your_app_id", appSecret: "your_app_secret")
|
||
XuqmSDK.shared.initialize(config: config)
|
||
```
|
||
|
||
### 2. IM 登录与监听消息(UserSig 模式)
|
||
|
||
```swift
|
||
import XuqmIM
|
||
|
||
// 使用 UserSig 登录(推荐生产环境)
|
||
// 只需要 userId + userSig,不需要 nickname / avatar / 生命周期字段
|
||
try await XuqmSDK.shared.login(userId: "user_001", userSig: "your_user_sig_jwt")
|
||
|
||
// 设置事件代理
|
||
ImSDK.shared.setDelegate(self)
|
||
|
||
extension ViewController: ImEventDelegate {
|
||
func imClientDidConnect() { print("WS connected") }
|
||
func imClientDidReceiveMessage(_ msg: ImMessage) { /* 处理单聊消息 */ }
|
||
func imClientDidReceiveGroupMessage(_ msg: ImMessage) { /* 处理群消息 */ }
|
||
func imClientDidReadMessage(_ msg: ImMessage) { /* 对方已读回执 */ }
|
||
func imClientDidReceiveRevokedMessage(_ msg: ImMessage) { /* 消息被撤回 */ }
|
||
func imClientDidDisconnect(reason: String?) { /* 断线 */ }
|
||
func imClientDidError(_ error: String) { /* 错误 */ }
|
||
}
|
||
```
|
||
|
||
### 3. 连接状态监听
|
||
|
||
SDK 暴露 `connectionState` 属性与 `addConnectionStateListener`,方便业务层实时感知 WebSocket 连接状态:
|
||
|
||
```swift
|
||
// 查询当前状态
|
||
let state = ImSDK.shared.connectionState
|
||
// 返回:.disconnected / .connecting / .connected
|
||
|
||
// 注册状态变更监听器
|
||
ImSDK.shared.addConnectionStateListener { state in
|
||
switch state {
|
||
case .connected:
|
||
print("IM 已连接")
|
||
case .connecting:
|
||
print("IM 连接中...")
|
||
case .disconnected:
|
||
print("IM 已断开")
|
||
}
|
||
}
|
||
```
|
||
|
||
> 状态变更触发时机:
|
||
> - 登录后 → `.connecting` → `.connected`
|
||
> - 网络异常/断线 → `.disconnected`,内部自动重连 → `.connecting` → `.connected`
|
||
> - 调用 `disconnect()` 或 `logout()` → `.disconnected`
|
||
|
||
### 4. 发送消息
|
||
|
||
```swift
|
||
// 发文本
|
||
let msg = ImSDK.shared.sendTextMessage(
|
||
toId: "user_002",
|
||
chatType: .single,
|
||
content: "Hello!"
|
||
)
|
||
|
||
// 发图片
|
||
let imgContent = try JSONSerialization.data(withJSONObject: [
|
||
"url": "https://cdn.example.com/img.jpg",
|
||
"width": 800, "height": 600
|
||
])
|
||
let msg2 = try await ImSDK.shared.sendMessage(
|
||
toId: "user_002", chatType: .single,
|
||
msgType: .image, content: String(data: imgContent, encoding: .utf8)!
|
||
)
|
||
```
|
||
|
||
### 5. 撤回与编辑
|
||
|
||
```swift
|
||
// 撤回消息
|
||
let revoked = try await ImSDK.shared.revokeMessage(messageId: msg.id)
|
||
|
||
// 编辑消息
|
||
let edited = try await ImSDK.shared.editMessage(messageId: msg.id, content: "新内容")
|
||
```
|
||
|
||
### 6. 群聊
|
||
|
||
```swift
|
||
// 创建群组
|
||
let group = try await ImSDK.shared.createGroup(name: "我的群", memberIds: ["user_001", "user_002"])
|
||
|
||
// 订阅群消息
|
||
ImSDK.shared.subscribeGroup(group.id)
|
||
|
||
// 发送群消息
|
||
ImSDK.shared.sendTextMessage(toId: group.id, chatType: .group, content: "大家好")
|
||
|
||
// 群管理
|
||
try await ImSDK.shared.addGroupMember(groupId: group.id, userId: "user_003")
|
||
try await ImSDK.shared.leaveGroup(groupId: group.id)
|
||
```
|
||
|
||
### 7. 会话管理
|
||
|
||
```swift
|
||
// 会话列表
|
||
let conversations = try await ImSDK.shared.listConversations()
|
||
|
||
// 置顶 / 静音 / 已读 / 草稿 / 删除
|
||
try await ImSDK.shared.setConversationPinned(targetId: "user_002", chatType: .single, pinned: true)
|
||
try await ImSDK.shared.setConversationMuted(targetId: "user_002", chatType: .single, muted: true)
|
||
try await ImSDK.shared.markRead(targetId: "user_002", chatType: .single)
|
||
try await ImSDK.shared.setDraft(targetId: "user_002", chatType: .single, draft: "未完成")
|
||
try await ImSDK.shared.deleteConversation(targetId: "user_002", chatType: .single)
|
||
```
|
||
|
||
### 8. Push 设备注册(APNs + FCM)
|
||
|
||
```swift
|
||
import XuqmPush
|
||
|
||
// 请求通知授权并自动注册 APNs
|
||
let granted = try await PushSDK.shared.requestAuthorization(options: [.alert, .badge, .sound])
|
||
|
||
// 在 AppDelegate 中转发 deviceToken
|
||
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
|
||
XuqmSDK.shared.registerDeviceToken(deviceToken)
|
||
}
|
||
|
||
// 如需手动注册 FCM Token(若集成 FirebaseMessaging)
|
||
try await PushSDK.shared.registerFcmToken(fcmToken, userId: "user_001")
|
||
```
|
||
|
||
### 9. 多模块统一登录
|
||
|
||
无论集成了哪些模块(IM、Push、Update),**初始化和登录永远只做一次**:
|
||
|
||
```swift
|
||
// 初始化
|
||
XuqmSDK.shared.initialize(config: config)
|
||
|
||
// 登录(业务登录成功后调用一次)
|
||
try await XuqmSDK.shared.login(userId: "user_001", userSig: userSig)
|
||
// ↓ 自动触发
|
||
// · ImSDK 连接 WebSocket
|
||
// · PushSDK 注册 APNs Token 并上报
|
||
|
||
// 登出(业务退出时调用一次)
|
||
XuqmSDK.shared.logout()
|
||
```
|
||
|
||
> **注意**:`userSig` 由业务服务端签发。若需更新登录态,请直接重新登录。
|
||
|
||
### 10. 检查更新
|
||
|
||
```swift
|
||
import XuqmUpdate
|
||
|
||
// App 整包更新
|
||
let appInfo = try await UpdateSDK.shared.checkAppUpdate(currentVersionCode: 1)
|
||
if let info = appInfo, info.forceUpdate == true {
|
||
UpdateSDK.shared.openAppStore(url: info.appStoreUrl ?? info.downloadUrl!)
|
||
}
|
||
```
|
||
|
||
## 消息类型
|
||
|
||
| MsgType | 说明 | content 结构 |
|
||
|---------|------|-------------|
|
||
| `.text` | 纯文本 | `String` |
|
||
| `.image` | 图片 | `{url, width, height, thumbnailUrl?}` |
|
||
| `.video` | 视频 | `{url, duration, thumbnailUrl, size}` |
|
||
| `.audio` | 语音 | `{url, duration, size}` |
|
||
| `.file` | 文件 | `{url, name, size, mimeType}` |
|
||
| `.location` | 位置 | `{lat, lng, address, title}` |
|
||
| `.custom` | 自定义 | 任意 JSON |
|
||
| `.notify` | 系统通知 | `{title, content}` |
|
||
| `.richText` | 富文本 | `{html}` |
|
||
| `.callAudio` | 语音通话信令 | `{callId, action, callerName}` |
|
||
| `.callVideo` | 视频通话信令 | `{callId, action, callerName}` |
|
||
| `.forward` | 转发 | `{originalMsgId, originalContent, originalSender}` |
|
||
| `.quote` | 引用 | `{quotedMsgId, quotedContent, text}` |
|
||
| `.merge` | 合并转发 | `{title, msgList}` |
|
||
| `.revoked` | 撤回 | 系统内部填充 |
|