feat: 重写 SDK 支持 iOS 12.2,移除 async/await 和 Combine

- 所有公开 API 改为 completion handler (Result<T, Error>)
- 状态通知改为 DuooomiBleSDKDelegate 协议
- 移除 Sendable、@MainActor、AsyncStream、CheckedContinuation
- 网络请求改为 URLSession.dataTask 回调
- BLE 通信改为 delegate + 闭包模式
- deployment target 降至 iOS 12.2

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
km2023
2026-04-16 16:59:39 +08:00
parent 79af43cdef
commit 1a7bbdc625
26 changed files with 3211 additions and 944 deletions

View File

@@ -9,40 +9,60 @@ final class FileTransferService {
}
///
/// - Parameters:
/// - fileUri: file:// URL https:// URL
/// - commandType:
/// - onProgress: 0.0 ~ 1.0
func transferFile(
fileUri: String,
commandType: CommandType,
onProgress: ((Double) -> Void)? = nil
) async throws {
onProgress: ((Double) -> Void)? = nil,
completion: @escaping (Result<Void, Error>) -> Void
) {
BleLog.i("Load file: \(fileUri)", "Transfer")
let data = try await loadFileData(from: fileUri)
BleLog.d("File loaded: size=\(data.count) bytes", "Transfer")
try await protocolService.send(
type: commandType.rawValue,
data: data,
onProgress: onProgress
)
loadFileData(from: fileUri) { [weak self] result in
switch result {
case .failure(let error):
completion(.failure(error))
case .success(let data):
BleLog.d("File loaded: size=\(data.count) bytes", "Transfer")
self?.protocolService.send(
type: commandType.rawValue,
data: data,
onProgress: onProgress,
completion: completion
)
}
}
}
private func loadFileData(from uri: String) async throws -> Data {
private func loadFileData(from uri: String, completion: @escaping (Result<Data, Error>) -> Void) {
guard let url = URL(string: uri) else {
throw DuooomiBleError.transferFailed("Invalid URL: \(uri)")
completion(.failure(DuooomiBleError.transferFailed("Invalid URL: \(uri)")))
return
}
if url.isFileURL {
return try Data(contentsOf: url)
} else {
let (data, response) = try await URLSession.shared.data(from: url)
do {
let data = try Data(contentsOf: url)
completion(.success(data))
} catch {
completion(.failure(DuooomiBleError.transferFailed("Failed to read local file: \(error.localizedDescription)")))
}
return
}
URLSession.shared.dataTask(with: url) { data, response, error in
if let error = error {
completion(.failure(DuooomiBleError.transferFailed("Download failed: \(error.localizedDescription)")))
return
}
guard let httpResponse = response as? HTTPURLResponse,
(200...299).contains(httpResponse.statusCode) else {
throw DuooomiBleError.transferFailed("Failed to download file: \(uri)")
completion(.failure(DuooomiBleError.transferFailed("Failed to download file: \(uri)")))
return
}
return data
}
guard let data = data, !data.isEmpty else {
completion(.failure(DuooomiBleError.transferFailed("Empty download response")))
return
}
completion(.success(data))
}.resume()
}
}