Files
youle_app_ios_v2/ylgamehall/Source/Network/QiniuUploader.swift
T
joywayerandClaude Opus 4.7 a3679aba7d 修复 SDK 真实接入后的 Swift 编译错误 + Xcode 链接配置
实测三个 SDK(微信 / 高德 / 七牛)链接进 Target 后,暴露出 9 个 Swift 编译错误,逐一修正:

代码侧(5 个 Swift 文件):
- AMapWrapper:updatePrivacyShow / updatePrivacyAgree 是 AMapLocationManager
  类方法(since 2.8.0),不在 AMapServices 上;改为 AMapLocationManager.*
  并补 import AMapLocationKit
- BackGameDataHandler:删 `WXApi.delegate = nil`。新版 SDK 2.x 无 static
  delegate API,delegate 由调用方逐次传给 handleOpenURL/sendAuthReq 并被
  SDK 弱引用;WeChatManager singleton 长生命周期不析构,无需 cleanup
- QiniuConfig / QiniuTokenSigner:所有 static 成员标 nonisolated,让 actor
  QiniuUploader 可直接调,无需 await MainActor.run
- QiniuUploader:QNUploadManager() 在七牛 SDK 8.x 已 kQNDeprecated,改用
  initWithConfiguration: + defaultConfigurationV2

工程侧(pbxproj,Xcode UI 自动写入):
- 新 Frameworks group 容纳 Vendor/WechatSDK / Vendor/AMap 引用
- WechatOpenSDK-NoPay.xcframework:Embed & Sign(动态库)
- AMapFoundationKit / AMapLocationKit:Do Not Embed(静态 fat .framework)

BuildProject 验证:Swift 全部编译通过;剩余 AMap fat framework arch 冲突
(M Mac iOS-simulator)是工程配置选择,下个 commit 处理。

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-23 01:03:29 +08:00

106 lines
4.3 KiB
Swift
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.
//
// QiniuUploader.swift
// ylgamehall
//
// 七牛上传 actor wrapper。包 `QNUploadManager` 为 async/await。
//
// ⚠️ canImport(QiniuSDK) 守卫:在 Xcode 把 https://github.com/qiniu/objc-sdk
// 添加到 Swift Package Dependencies 之前,本文件编译为 no-opupload 永远抛
// QiniuUploadError.sdkNotLinked。后续 handler 可降级到 stub 路径。
//
// 上传完成后返回 UploadedFile,字段映射给 H5 `getaudiourl` / `recordSuccess`。
//
import Foundation
#if canImport(QiniuSDK)
import QiniuSDK
#endif
public struct UploadedFile: Sendable {
public let fileUrl: String // 公网访问 URLhttp://{domain}/{key}
public let fileName: String // 原始本地文件名
public let fileKey: String // 七牛 keypath-on-cdn
public let timeSec: Int // 录音时长(秒)
}
public enum QiniuUploadError: Error, Sendable {
case sdkNotLinked
case fileNotFound(String)
case uploadFailed(any Error)
case responseInvalid
}
public actor QiniuUploader {
public static let shared = QiniuUploader()
public init() {}
/// 上传文件。
/// - Parameters:
/// - localFile: 本地文件 URLamr 录音文件)
/// - timeSec: 录音时长,回传给 H5 `getaudiourl` 用
/// - Returns: UploadedFile(含公网 URL
public func upload(_ localFile: URL, timeSec: Int) async throws -> UploadedFile {
#if canImport(QiniuSDK)
let fm = FileManager.default
guard fm.fileExists(atPath: localFile.path) else {
throw QiniuUploadError.fileNotFound(localFile.path)
}
// 生成 key`{recordingDirectory}{uuid}.{ext}`(与 msext QiniuManager.m:55-60 等价)
let uuid = UUID().uuidString.lowercased().replacingOccurrences(of: "-", with: "")
let ext = localFile.pathExtension
let key = QiniuConfig.recordingDirectory + uuid + (ext.isEmpty ? "" : ".\(ext)")
// 客户端自签 token(参 QiniuTokenSigner / msext QiniuManager 同款算法)
let token = QiniuTokenSigner.uploadToken(key: key)
// 七牛 SDK 8.x`QNUploadManager.init()` 被标 `kQNDeprecated`,必须走
// `initWithConfiguration:`。用 defaultConfigurationV2v2 已替代旧 defaultConfiguration)。
// initWithConfiguration: ObjC 端 instancetype 桥到 Swift 仍为可选;
// 实际几乎不会失败(内部仅初始化无 IO),失败按 responseInvalid 抛出。
let cfg = QNConfiguration.defaultConfigurationV2()
guard let mgr = QNUploadManager(configuration: cfg) else {
throw QiniuUploadError.responseInvalid
}
let fileName = localFile.lastPathComponent
return try await withCheckedThrowingContinuation { (cont: CheckedContinuation<UploadedFile, Error>) in
mgr.putFile(
localFile.path,
key: key,
token: token,
complete: { info, savedKey, _ in
if let info, info.isOK, let savedKey {
let url = QiniuConfig.publicURL(forKey: savedKey)
cont.resume(returning: UploadedFile(
fileUrl: url,
fileName: fileName,
fileKey: savedKey,
timeSec: timeSec
))
} else if let error = info?.error {
cont.resume(throwing: QiniuUploadError.uploadFailed(error))
} else {
cont.resume(throwing: QiniuUploadError.responseInvalid)
}
},
option: nil
)
}
#else
throw QiniuUploadError.sdkNotLinked
#endif
}
/// 取消所有进行中任务(接 BackGameDataHandler 清理钩子用)。
/// QNUploadManager 没有「取消全部」API,单任务用 QNUploadOption.cancellationSignal 实现;
/// 当前实现以 task 粒度由 Swift Task.cancel 传递(withCheckedThrowingContinuation
/// 已在 cancellation 时 throw CancellationError),无需额外状态。
public func cancelInFlight() {
// no-op(依赖 Task.cancel 传播);如未来需要硬 cancel,改为持有 QNUploadOption 并触发 cancellationSignal
}
}