Files
real-e-party-iOS/YuMi/E-P/Common/EPSDKManager.swift.backup
2025-10-17 14:52:29 +08:00

254 lines
8.5 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// EPSDKManager.swift
// YuMi
//
// Created by AI on 2025-10-11.
//
import Foundation
/// 第三方 SDK 统一管理器(单例)
/// 统一入口:对外提供所有 SDK 能力
/// 内部管理QCloud 初始化、配置、上传等
@objc class EPSDKManager: NSObject, QCloudSignatureProvider, QCloudCredentailFenceQueueDelegate {
// MARK: - Singleton
@objc static let shared = EPSDKManager()
// MARK: - Properties
// QCloud 配置缓存
private var qcloudConfig: EPQCloudConfig?
// QCloud 初始化状态
private var isQCloudInitializing = false
// QCloud 初始化回调队列
private var qcloudInitCallbacks: [(Bool, String?) -> Void] = []
// QCloud 凭证队列
private var credentialFenceQueue: QCloudCredentailFenceQueue?
// 线程安全锁
private let lock = NSLock()
// 内部图片上传器
private let uploader = EPImageUploader()
// MARK: - Initialization
private override init() {
super.init()
}
// MARK: - Public API (对外统一入口)
/// 批量上传图片(统一入口)
/// - Parameters:
/// - images: 要上传的图片数组
/// - progress: 进度回调 (已上传数, 总数)
/// - success: 成功回调,返回图片信息数组
/// - failure: 失败回调
@objc func uploadImages(
_ images: [UIImage],
progress: @escaping (Int, Int) -> Void,
success: @escaping ([[String: Any]]) -> Void,
failure: @escaping (String) -> Void
) {
guard !images.isEmpty else {
success([])
return
}
// 确保 QCloud 已就绪
ensureQCloudReady { [weak self] isReady, errorMsg in
guard let self = self, isReady else {
DispatchQueue.main.async {
failure(errorMsg ?? YMLocalizedString("error.qcloud_init_failed"))
}
return
}
// 委托给内部 uploader 执行
self.uploader.performBatchUpload(
images,
bucket: self.qcloudConfig?.bucket ?? "",
customDomain: self.qcloudConfig?.customDomain ?? "",
progress: progress,
success: success,
failure: failure
)
}
}
/// 检查 QCloud 是否已就绪
/// - Returns: true 表示已初始化且未过期
@objc func isQCloudReady() -> Bool {
lock.lock()
defer { lock.unlock() }
guard let config = qcloudConfig else {
return false
}
return !config.isExpired
}
// MARK: - Internal Methods
/// 确保 QCloud 已就绪(自动初始化)
private func ensureQCloudReady(completion: @escaping (Bool, String?) -> Void) {
if isQCloudReady() {
completion(true, nil)
return
}
// 未初始化或已过期,重新初始化
initializeQCloud(completion: completion)
}
/// 初始化 QCloud获取 Token 并配置 SDK
private func initializeQCloud(completion: @escaping (Bool, String?) -> Void) {
lock.lock()
// 如果正在初始化,加入回调队列
if isQCloudInitializing {
qcloudInitCallbacks.append(completion)
lock.unlock()
return
}
// 如果已初始化且未过期,直接返回
if let config = qcloudConfig, !config.isExpired {
lock.unlock()
completion(true, nil)
return
}
// 开始初始化
isQCloudInitializing = true
qcloudInitCallbacks.append(completion)
lock.unlock()
// 调用 API 获取 QCloud Token
// API: GET tencent/cos/getToken
Api.getQCloudInfo { [weak self] (data, code, msg) in
guard let self = self else { return }
self.lock.lock()
if code == 200,
let dict = data?.data as? [String: Any],
let config = EPQCloudConfig(dictionary: dict) {
// 保存配置
self.qcloudConfig = config
// 配置 QCloud SDK
self.configureQCloudSDK(with: config)
// 初始化完成
self.isQCloudInitializing = false
let callbacks = self.qcloudInitCallbacks
self.qcloudInitCallbacks.removeAll()
self.lock.unlock()
// 短暂延迟确保 SDK 配置完成
DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
callbacks.forEach { $0(true, nil) }
}
} else {
// 初始化失败
self.isQCloudInitializing = false
let callbacks = self.qcloudInitCallbacks
self.qcloudInitCallbacks.removeAll()
self.lock.unlock()
let errorMsg = msg ?? YMLocalizedString("error.qcloud_config_failed")
DispatchQueue.main.async {
callbacks.forEach { $0(false, errorMsg) }
}
}
}
}
/// 配置 QCloud SDK参考 UploadFile.m line 42-64
private func configureQCloudSDK(with config: EPQCloudConfig) {
let configuration = QCloudServiceConfiguration()
configuration.appID = config.appId
let endpoint = QCloudCOSXMLEndPoint()
endpoint.regionName = config.region
endpoint.useHTTPS = true
// 全球加速(参考 UploadFile.m line 56-59
if config.accelerate == 1 {
endpoint.suffix = "cos.accelerate.myqcloud.com"
}
configuration.endpoint = endpoint
configuration.signatureProvider = self
// 注册 COS 服务
QCloudCOSXMLService.registerDefaultCOSXML(with: configuration)
QCloudCOSTransferMangerService.registerDefaultCOSTransferManger(with: configuration)
// 初始化凭证队列
credentialFenceQueue = QCloudCredentailFenceQueue()
credentialFenceQueue?.delegate = self
}
// MARK: - QCloudSignatureProvider Protocol
/// 提供签名(参考 UploadFile.m line 67-104
func signature(
with fields: QCloudSignatureFields,
request: QCloudBizHTTPRequest,
urlRequest: NSMutableURLRequest,
compelete: @escaping QCloudHTTPAuthentationContinueBlock
) {
guard let config = qcloudConfig else {
let error = NSError(domain: "com.yumi.qcloud", code: -1,
userInfo: [NSLocalizedDescriptionKey: YMLocalizedString("error.qcloud_config_not_initialized")])
compelete(nil, error)
return
}
let credential = QCloudCredential()
credential.secretID = config.secretId
credential.secretKey = config.secretKey
credential.token = config.sessionToken
credential.startDate = Date(timeIntervalSince1970: TimeInterval(config.startTime))
credential.expirationDate = Date(timeIntervalSince1970: TimeInterval(config.expireTime))
let creator = QCloudAuthentationV5Creator(credential: credential)
let signature = creator?.signature(forData: urlRequest)
compelete(signature, nil)
}
// MARK: - QCloudCredentailFenceQueueDelegate Protocol
/// 管理凭证(参考 UploadFile.m line 107-133
func fenceQueue(
_ queue: QCloudCredentailFenceQueue,
requestCreatorWithContinue continueBlock: @escaping QCloudCredentailFenceQueueContinue
) {
guard let config = qcloudConfig else {
let error = NSError(domain: "com.yumi.qcloud", code: -1,
userInfo: [NSLocalizedDescriptionKey: YMLocalizedString("error.qcloud_config_not_initialized")])
continueBlock(nil, error)
return
}
let credential = QCloudCredential()
credential.secretID = config.secretId
credential.secretKey = config.secretKey
credential.token = config.sessionToken
credential.startDate = Date(timeIntervalSince1970: TimeInterval(config.startTime))
credential.expirationDate = Date(timeIntervalSince1970: TimeInterval(config.expireTime))
let creator = QCloudAuthentationV5Creator(credential: credential)
continueBlock(creator, nil)
}
}