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:
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user