
主要变更: 1. 新增 EPImageUploader.swift 和 EPProgressHUD.swift,提供图片批量上传和进度显示功能。 2. 新建 EPMomentAPISwiftHelper.swift,封装动态 API 的 Swift 版本。 3. 更新 EPMomentPublishViewController,集成新上传功能并实现发布成功通知。 4. 创建多个文档,包括实施报告、检查清单和快速使用指南,详细记录功能实现和使用方法。 5. 更新 Bridging Header,确保 Swift 和 Objective-C 代码的互操作性。 此功能旨在提升用户体验,简化动态发布流程,并提供清晰的文档支持。
521 lines
11 KiB
Markdown
521 lines
11 KiB
Markdown
# SDK 管理器实施总结
|
||
|
||
## 实施时间
|
||
2025-10-11
|
||
|
||
## 问题背景
|
||
|
||
### 崩溃原因
|
||
```
|
||
Terminating app due to uncaught exception 'com.tencent.qcloud.error',
|
||
reason: '您没有配置默认的OCR服务配置,请配置之后再调用该方法'
|
||
```
|
||
|
||
### 根本原因
|
||
|
||
- `EPImageUploader` 直接调用 `UploadFile.qCloudUploadImage()`
|
||
- `UploadFile` 的 `fileModel` 属性为 nil(未初始化)
|
||
- QCloud SDK 需要先调用 `initQCloud` 获取配置才能使用
|
||
|
||
## 解决方案
|
||
|
||
### 架构设计
|
||
|
||
创建独立的 SDK 管理器,职责分离:
|
||
|
||
```
|
||
EPSDKManager (SDK 管理)
|
||
↓ 提供配置
|
||
EPImageUploader (业务逻辑)
|
||
↓ 调用底层
|
||
UploadFile (基础设施)
|
||
```
|
||
|
||
### 设计决策
|
||
|
||
1. **初始化时机**: 懒加载(首次上传时自动初始化)
|
||
2. **Token 刷新**: 过期后重新获取
|
||
3. **错误处理**: 直接返回失败,不重试
|
||
4. **旧代码兼容**: 保持 UploadFile.m 不变
|
||
|
||
## 实施内容
|
||
|
||
### 1. EPQCloudConfig.swift (60 行)
|
||
|
||
**路径**: `YuMi/E-P/Common/EPQCloudConfig.swift`
|
||
|
||
**功能**:
|
||
|
||
- QCloud 配置数据模型
|
||
- 从 API 返回数据初始化
|
||
- 提供过期检查
|
||
|
||
**核心字段**:
|
||
```swift
|
||
struct EPQCloudConfig {
|
||
let secretId: String
|
||
let secretKey: String
|
||
let sessionToken: String
|
||
let bucket: String
|
||
let region: String
|
||
let customDomain: String
|
||
let startTime: Int64
|
||
let expireTime: Int64
|
||
let appId: String
|
||
let accelerate: Int
|
||
|
||
var isExpired: Bool // 检查是否过期
|
||
}
|
||
```
|
||
|
||
### 2. EPSDKManager.swift (116 行)
|
||
|
||
**路径**: `YuMi/E-P/Common/EPSDKManager.swift`
|
||
|
||
**功能**:
|
||
|
||
- 单例模式管理所有第三方 SDK
|
||
- QCloud 初始化和配置缓存
|
||
- 并发安全的初始化控制
|
||
|
||
**核心方法**:
|
||
```swift
|
||
@objc class EPSDKManager: NSObject {
|
||
@objc static let shared: EPSDKManager
|
||
|
||
// 检查 QCloud 是否就绪
|
||
@objc func isQCloudReady() -> Bool
|
||
|
||
// 确保 QCloud 就绪(自动初始化)
|
||
@objc func ensureQCloudReady(completion: (Bool, String?) -> Void)
|
||
|
||
// 主动初始化 QCloud
|
||
@objc func initializeQCloud(completion: (Bool, String?) -> Void)
|
||
}
|
||
```
|
||
|
||
**关键特性**:
|
||
|
||
- **回调队列**: 处理并发初始化请求
|
||
- **NSLock 保护**: 线程安全
|
||
- **配置缓存**: 避免重复获取 Token
|
||
- **过期检查**: 自动重新初始化
|
||
|
||
**初始化流程**:
|
||
```
|
||
1. 检查是否正在初始化 → 是:加入回调队列
|
||
2. 检查是否已初始化且未过期 → 是:直接返回成功
|
||
3. 调用 Api.getQCloudInfo 获取 Token
|
||
4. 保存 EPQCloudConfig
|
||
5. 调用 UploadFile.initQCloud()(兼容性)
|
||
6. 延迟 0.3s 确保初始化完成
|
||
7. 触发所有回调
|
||
```
|
||
|
||
### 3. EPImageUploader.swift(修改)
|
||
|
||
**路径**: `YuMi/E-P/Common/EPImageUploader.swift`
|
||
|
||
**修改内容**:
|
||
|
||
- 提取 `performBatchUpload` 私有方法(原上传逻辑)
|
||
- `uploadImages` 中添加初始化检查
|
||
|
||
**修改前**:
|
||
```swift
|
||
@objc func uploadImages(...) {
|
||
// 直接上传
|
||
UploadFile.share().qCloudUploadImage(...)
|
||
}
|
||
```
|
||
|
||
**修改后**:
|
||
```swift
|
||
@objc func uploadImages(...) {
|
||
// 1. 确保 QCloud 已初始化
|
||
EPSDKManager.shared.ensureQCloudReady { isReady, errorMsg in
|
||
if !isReady {
|
||
failure(errorMsg ?? "QCloud 初始化失败")
|
||
return
|
||
}
|
||
|
||
// 2. 执行上传
|
||
self.performBatchUpload(...)
|
||
}
|
||
}
|
||
|
||
private func performBatchUpload(...) {
|
||
// 原有的并发上传逻辑
|
||
}
|
||
```
|
||
|
||
### 4. Bridging Header(修改)
|
||
|
||
**文件**: `YuMi/YuMi-Bridging-Header.h`
|
||
|
||
**新增**:
|
||
```objc
|
||
#import "Api+Mine.h" // 用于调用 getQCloudInfo
|
||
```
|
||
|
||
## 执行流程
|
||
|
||
### 首次上传流程
|
||
|
||
```
|
||
用户点击发布
|
||
↓
|
||
EPMomentPublishViewController.onPublish()
|
||
↓
|
||
EPImageUploader.uploadImages()
|
||
↓
|
||
EPSDKManager.ensureQCloudReady()
|
||
↓
|
||
检查 isQCloudReady() → false (未初始化)
|
||
↓
|
||
initializeQCloud()
|
||
↓
|
||
调用 Api.getQCloudInfo
|
||
↓ (GET: tencent/cos/getToken)
|
||
返回 Token 数据
|
||
↓
|
||
保存到 EPQCloudConfig
|
||
↓
|
||
调用 UploadFile.share().initQCloud() (兼容)
|
||
↓
|
||
延迟 0.3s 等待初始化完成
|
||
↓
|
||
回调成功 → performBatchUpload()
|
||
↓
|
||
并发上传图片(最多 3 张同时)
|
||
↓
|
||
显示进度 "上传中 X/Y"
|
||
↓
|
||
全部完成 → 调用发布 API
|
||
↓
|
||
发布成功 → Dismiss 页面
|
||
```
|
||
|
||
### 后续上传流程
|
||
|
||
```
|
||
EPSDKManager.ensureQCloudReady()
|
||
↓
|
||
检查 isQCloudReady() → true (已初始化且未过期)
|
||
↓
|
||
直接回调成功 → 立即执行 performBatchUpload()
|
||
```
|
||
|
||
### Token 过期流程
|
||
|
||
```
|
||
EPSDKManager.ensureQCloudReady()
|
||
↓
|
||
检查 config.isExpired → true (已过期)
|
||
↓
|
||
自动调用 initializeQCloud() 重新获取
|
||
↓
|
||
继续上传流程
|
||
```
|
||
|
||
## 技术亮点
|
||
|
||
### 1. 懒加载策略
|
||
|
||
- 首次使用时才初始化
|
||
- 节省 App 启动时间
|
||
- 按需加载,资源利用最优
|
||
|
||
### 2. 并发安全设计
|
||
```swift
|
||
private var isQCloudInitializing = false
|
||
private var qcloudInitCallbacks: [(Bool, String?) -> Void] = []
|
||
private let lock = NSLock()
|
||
```
|
||
|
||
- NSLock 保护共享状态
|
||
- 回调队列处理并发请求
|
||
- 避免重复初始化
|
||
|
||
### 3. 自动过期重新初始化
|
||
```swift
|
||
var isExpired: Bool {
|
||
return Date().timeIntervalSince1970 > Double(expireTime)
|
||
}
|
||
```
|
||
|
||
- 检查 Token 是否过期
|
||
- 过期自动重新获取
|
||
- 无需手动管理
|
||
|
||
### 4. 向后兼容
|
||
```swift
|
||
// 继续调用旧的初始化方法
|
||
UploadFile.share().initQCloud()
|
||
```
|
||
|
||
- 新旧代码可以并存
|
||
- 旧代码依然可以正常工作
|
||
- 平滑过渡,降低风险
|
||
|
||
## 代码统计
|
||
|
||
### 新建文件
|
||
| 文件 | 行数 | 说明 |
|
||
|------|------|------|
|
||
| EPQCloudConfig.swift | 60 | QCloud 配置 Model |
|
||
| EPSDKManager.swift | 116 | SDK 管理器 |
|
||
| **合计** | **176** | **纯 Swift** |
|
||
|
||
### 修改文件
|
||
| 文件 | 修改行数 | 说明 |
|
||
|------|---------|------|
|
||
| EPImageUploader.swift | +30 | 添加初始化检查 |
|
||
| YuMi-Bridging-Header.h | +1 | 新增 Api+Mine.h |
|
||
| **合计** | **+31** | **配置更新** |
|
||
|
||
### 总计
|
||
|
||
- **新增**: 176 行 Swift 代码
|
||
- **修改**: 31 行代码
|
||
- **不改**: UploadFile.m (410 行保持不变)
|
||
|
||
## 文件清单
|
||
|
||
### 新建
|
||
|
||
- ✅ `YuMi/E-P/Common/EPQCloudConfig.swift`
|
||
- ✅ `YuMi/E-P/Common/EPSDKManager.swift`
|
||
|
||
### 修改
|
||
|
||
- ✅ `YuMi/E-P/Common/EPImageUploader.swift`
|
||
- ✅ `YuMi/YuMi-Bridging-Header.h`
|
||
|
||
### 不改
|
||
|
||
- ✅ `YuMi/Tools/File/UploadFile.m`
|
||
- ✅ `YuMi/Tools/File/UploadFile.h`
|
||
|
||
## 测试计划
|
||
|
||
### 功能测试
|
||
|
||
| ID | 测试用例 | 预期结果 |
|
||
|----|---------|---------|
|
||
| T01 | 冷启动后首次上传单图 | 自动初始化 QCloud → 上传成功 |
|
||
| T02 | 连续上传多次 | 复用配置,无重复初始化 |
|
||
| T03 | 并发初始化(快速点击两次发布) | 第二次请求加入回调队列,共享初始化结果 |
|
||
| T04 | 网络异常初始化失败 | 显示错误提示,不崩溃 |
|
||
| T05 | Token 模拟过期 | 自动重新获取配置 |
|
||
|
||
### 测试步骤
|
||
|
||
#### T01: 冷启动首次上传
|
||
```
|
||
1. 杀掉 App
|
||
2. 重新启动
|
||
3. 进入发布页面
|
||
4. 选择 1 张图片
|
||
5. 点击发布
|
||
6. 观察:
|
||
- 短暂等待(初始化)
|
||
- 显示 "上传中 1/1"
|
||
- 发布成功
|
||
```
|
||
|
||
#### T02: 连续上传
|
||
```
|
||
1. 上传成功后
|
||
2. 再次进入发布页面
|
||
3. 选择图片并发布
|
||
4. 观察:
|
||
- 无等待(配置已缓存)
|
||
- 立即开始上传
|
||
```
|
||
|
||
#### T03: 并发初始化
|
||
```
|
||
1. 冷启动
|
||
2. 准备两个发布操作
|
||
3. 快速连续点击发布
|
||
4. 观察:
|
||
- 两个请求都成功
|
||
- 只初始化一次
|
||
```
|
||
|
||
#### T04: 网络异常
|
||
```
|
||
1. 断开网络
|
||
2. 冷启动
|
||
3. 尝试上传
|
||
4. 观察:
|
||
- 显示错误提示
|
||
- App 不崩溃
|
||
```
|
||
|
||
#### T05: Token 过期测试
|
||
```
|
||
1. 在 EPSDKManager 中临时修改过期判断:
|
||
return true // 强制过期
|
||
2. 尝试上传
|
||
3. 观察:
|
||
- 自动重新初始化
|
||
- 上传成功
|
||
```
|
||
|
||
## 监控要点
|
||
|
||
### 日志输出
|
||
|
||
建议在关键节点添加日志:
|
||
|
||
```swift
|
||
// EPSDKManager.swift
|
||
print("[EPSDKManager] QCloud 初始化开始")
|
||
print("[EPSDKManager] QCloud 配置获取成功,过期时间: \(config.expireTime)")
|
||
print("[EPSDKManager] QCloud 初始化完成")
|
||
|
||
// EPImageUploader.swift
|
||
print("[EPImageUploader] 等待 QCloud 初始化...")
|
||
print("[EPImageUploader] QCloud 就绪,开始上传 \(images.count) 张图片")
|
||
print("[EPImageUploader] 上传进度: \(uploaded)/\(total)")
|
||
```
|
||
|
||
### 性能指标
|
||
|
||
| 指标 | 目标值 | 说明 |
|
||
|------|--------|------|
|
||
| 初始化时间 | < 1s | 首次获取 QCloud Token |
|
||
| 单图上传 | < 3s | 1MB 图片 |
|
||
| 9 图上传 | < 15s | 并发 3 张 |
|
||
| 配置复用 | 0s | 已初始化时无等待 |
|
||
|
||
## 架构优势
|
||
|
||
### 1. 职责分离
|
||
|
||
| 组件 | 职责 | 依赖 |
|
||
|------|------|------|
|
||
| EPSDKManager | SDK 初始化管理、配置缓存 | Api+Mine |
|
||
| EPImageUploader | 图片上传业务逻辑 | EPSDKManager |
|
||
| UploadFile | QCloud 底层上传 | QCloudCOSXML |
|
||
|
||
### 2. 技术特点
|
||
|
||
- **自动初始化**: 用户无感知,首次使用时自动触发
|
||
- **并发控制**: 回调队列 + NSLock 确保线程安全
|
||
- **Token 管理**: 自动检查过期,按需刷新
|
||
- **扩展性强**: 未来其他 SDK 可接入同一管理器
|
||
|
||
### 3. 向后兼容
|
||
|
||
```swift
|
||
// 新代码调用 EPSDKManager
|
||
EPSDKManager.shared.ensureQCloudReady { ... }
|
||
|
||
// 旧代码依然可以直接调用
|
||
UploadFile.share().initQCloud()
|
||
```
|
||
|
||
## API 接口
|
||
|
||
### 调用的 API
|
||
|
||
**接口**: `GET tencent/cos/getToken`
|
||
|
||
**返回数据**:
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"data": {
|
||
"secretId": "xxx",
|
||
"secretKey": "xxx",
|
||
"sessionToken": "xxx",
|
||
"bucket": "xxx",
|
||
"region": "xxx",
|
||
"customDomain": "https://xxx",
|
||
"startTime": 1728123456,
|
||
"expireTime": 1728209856,
|
||
"appId": "xxx",
|
||
"accelerate": 1
|
||
}
|
||
}
|
||
```
|
||
|
||
## 已知问题
|
||
|
||
### 当前
|
||
|
||
- 无
|
||
|
||
### 潜在风险
|
||
|
||
1. **初始化延迟 0.3s**:
|
||
- 当前使用固定延迟等待 UploadFile 初始化
|
||
- 可能在慢速设备上不够
|
||
- 可优化为轮询检查或使用通知
|
||
|
||
2. **Token 提前过期**:
|
||
- 当前在过期时才重新获取
|
||
- 可优化为提前 5 分钟主动刷新
|
||
|
||
## 未来优化
|
||
|
||
### 短期(本周)
|
||
|
||
- [ ] 添加初始化日志,便于调试
|
||
- [ ] 测试所有场景
|
||
- [ ] 验证 Token 过期处理
|
||
|
||
### 中期(本月)
|
||
|
||
- [ ] 优化初始化完成检测机制(替代固定延迟)
|
||
- [ ] 添加 Token 提前刷新策略
|
||
- [ ] 接入其他 SDK(IM、推送等)
|
||
|
||
### 长期(季度)
|
||
|
||
- [ ] 统一 SDK 初始化入口
|
||
- [ ] 添加 SDK 状态监控
|
||
- [ ] 实现配置本地持久化
|
||
|
||
## 相关文档
|
||
|
||
- [实施计划](moment-publish-implementation.plan.md)
|
||
- [Bridging Header 修复](BRIDGING_HEADER_FIX.md)
|
||
- [动态发布实施](MOMENT_PUBLISH_IMPLEMENTATION.md)
|
||
- [实施检查清单](IMPLEMENTATION_CHECKLIST.md)
|
||
|
||
## Git 状态
|
||
|
||
```
|
||
新建文件:
|
||
YuMi/E-P/Common/EPQCloudConfig.swift
|
||
YuMi/E-P/Common/EPSDKManager.swift
|
||
|
||
修改文件:
|
||
YuMi/E-P/Common/EPImageUploader.swift
|
||
YuMi/YuMi-Bridging-Header.h
|
||
```
|
||
|
||
## 编译状态
|
||
|
||
- ✅ **Swift 语法检查**: 无错误
|
||
- ✅ **Bridging Header**: 依赖链问题已解决
|
||
- ✅ **OC/Swift 互操作**: 正确配置
|
||
|
||
## 下一步
|
||
|
||
1. **在 Xcode 中添加新文件到项目**
|
||
2. **Clean Build** (Shift+Cmd+K)
|
||
3. **Build** (Cmd+B)
|
||
4. **运行并测试上传功能**
|
||
|
||
---
|
||
|
||
**实施状态**: ✅ 代码完成,待测试验证
|
||
**实施者**: AI Assistant (Linus Mode)
|
||
**审查状态**: 待审查
|
||
|