
主要变更: 1. 新增 EPImageUploader.swift 和 EPProgressHUD.swift,提供图片批量上传和进度显示功能。 2. 新建 EPMomentAPISwiftHelper.swift,封装动态 API 的 Swift 版本。 3. 更新 EPMomentPublishViewController,集成新上传功能并实现发布成功通知。 4. 创建多个文档,包括实施报告、检查清单和快速使用指南,详细记录功能实现和使用方法。 5. 更新 Bridging Header,确保 Swift 和 Objective-C 代码的互操作性。 此功能旨在提升用户体验,简化动态发布流程,并提供清晰的文档支持。
11 KiB
11 KiB
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 (基础设施)
设计决策
- 初始化时机: 懒加载(首次上传时自动初始化)
- Token 刷新: 过期后重新获取
- 错误处理: 直接返回失败,不重试
- 旧代码兼容: 保持 UploadFile.m 不变
实施内容
1. EPQCloudConfig.swift (60 行)
路径: YuMi/E-P/Common/EPQCloudConfig.swift
功能:
- QCloud 配置数据模型
- 从 API 返回数据初始化
- 提供过期检查
核心字段:
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 初始化和配置缓存
- 并发安全的初始化控制
核心方法:
@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
中添加初始化检查
修改前:
@objc func uploadImages(...) {
// 直接上传
UploadFile.share().qCloudUploadImage(...)
}
修改后:
@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
新增:
#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. 并发安全设计
private var isQCloudInitializing = false
private var qcloudInitCallbacks: [(Bool, String?) -> Void] = []
private let lock = NSLock()
- NSLock 保护共享状态
- 回调队列处理并发请求
- 避免重复初始化
3. 自动过期重新初始化
var isExpired: Bool {
return Date().timeIntervalSince1970 > Double(expireTime)
}
- 检查 Token 是否过期
- 过期自动重新获取
- 无需手动管理
4. 向后兼容
// 继续调用旧的初始化方法
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. 观察:
- 自动重新初始化
- 上传成功
监控要点
日志输出
建议在关键节点添加日志:
// 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. 向后兼容
// 新代码调用 EPSDKManager
EPSDKManager.shared.ensureQCloudReady { ... }
// 旧代码依然可以直接调用
UploadFile.share().initQCloud()
API 接口
调用的 API
接口: GET tencent/cos/getToken
返回数据:
{
"code": 200,
"data": {
"secretId": "xxx",
"secretKey": "xxx",
"sessionToken": "xxx",
"bucket": "xxx",
"region": "xxx",
"customDomain": "https://xxx",
"startTime": 1728123456,
"expireTime": 1728209856,
"appId": "xxx",
"accelerate": 1
}
}
已知问题
当前
- 无
潜在风险
-
初始化延迟 0.3s:
- 当前使用固定延迟等待 UploadFile 初始化
- 可能在慢速设备上不够
- 可优化为轮询检查或使用通知
-
Token 提前过期:
- 当前在过期时才重新获取
- 可优化为提前 5 分钟主动刷新
未来优化
短期(本周)
- 添加初始化日志,便于调试
- 测试所有场景
- 验证 Token 过期处理
中期(本月)
- 优化初始化完成检测机制(替代固定延迟)
- 添加 Token 提前刷新策略
- 接入其他 SDK(IM、推送等)
长期(季度)
- 统一 SDK 初始化入口
- 添加 SDK 状态监控
- 实现配置本地持久化
相关文档
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 互操作: 正确配置
下一步
- 在 Xcode 中添加新文件到项目
- Clean Build (Shift+Cmd+K)
- Build (Cmd+B)
- 运行并测试上传功能
实施状态: ✅ 代码完成,待测试验证
实施者: AI Assistant (Linus Mode)
审查状态: 待审查