import Foundation /// 文件传输服务:下载文件并通过协议发送二进制数据 final class FileTransferService { private let protocolService: BleProtocolService init(protocolService: BleProtocolService) { self.protocolService = protocolService } /// 传输文件到设备 func transferFile( fileUri: String, commandType: CommandType, onProgress: ((Double) -> Void)? = nil, completion: @escaping (Result) -> Void ) { BleLog.i("Load file: \(fileUri)", "Transfer") 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, completion: @escaping (Result) -> Void) { guard let url = URL(string: uri) else { completion(.failure(DuooomiBleError.transferFailed("Invalid URL: \(uri)"))) return } if url.isFileURL { 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 { completion(.failure(DuooomiBleError.transferFailed("Failed to download file: \(uri)"))) return } guard let data = data, !data.isEmpty else { completion(.failure(DuooomiBleError.transferFailed("Empty download response"))) return } completion(.success(data)) }.resume() } }