import Foundation import os.log /// iOS端的文件日志助手类,提供与Android端FileLogger类似的功能 class FileLogger { private static let logQueue = DispatchQueue(label: "com.yunqiinnovation.classic_bluetooth.logger", qos: .background) private static let dateFormatter: DateFormatter = { let formatter = DateFormatter() formatter.dateFormat = "yyyy-MM-dd HH:mm:ss.SSS" return formatter }() /// 日志类型 enum LogLevel: String { case debug = "DEBUG" case info = "INFO" case warning = "WARNING" case error = "ERROR" } /// 输出调试日志 /// - Parameters: /// - tag: 标签 /// - message: 日志消息 static func d(_ tag: String, _ message: String) { log(level: .debug, tag: tag, message: message) } /// 输出信息日志 /// - Parameters: /// - tag: 标签 /// - message: 日志消息 static func i(_ tag: String, _ message: String) { log(level: .info, tag: tag, message: message) } /// 输出警告日志 /// - Parameters: /// - tag: 标签 /// - message: 日志消息 static func w(_ tag: String, _ message: String) { log(level: .warning, tag: tag, message: message) } /// 输出错误日志 /// - Parameters: /// - tag: 标签 /// - message: 日志消息 /// - error: 可选的错误对象 static func e(_ tag: String, _ message: String, _ error: Error? = nil) { var fullMessage = message if let error = error { fullMessage += " - Error: \(error.localizedDescription)" } log(level: .error, tag: tag, message: fullMessage) } /// 输出日志 /// - Parameters: /// - level: 日志级别 /// - tag: 标签 /// - message: 日志消息 private static func log(level: LogLevel, tag: String, message: String) { let timestamp = dateFormatter.string(from: Date()) let logMessage = "[\(timestamp)] [\(level.rawValue)] [\(tag)]: \(message)" // 输出到控制台 print(logMessage) // 异步写入日志文件 logQueue.async { writeToLogFile(logMessage) } // 使用系统日志 if #available(iOS 10.0, *) { let osLog = OSLog(subsystem: "com.yunqiinnovation.classic_bluetooth", category: tag) let osLogType: OSLogType switch level { case .debug: osLogType = .debug case .info: osLogType = .info case .warning: osLogType = .default case .error: osLogType = .error } os_log("%{public}@", log: osLog, type: osLogType, message) } } /// 将日志写入文件 /// - Parameter message: 日志消息 private static func writeToLogFile(_ message: String) { guard let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { return } let logDirectoryURL = documentsDirectory.appendingPathComponent("Logs") let dateString = DateFormatter().with { $0.dateFormat = "yyyy-MM-dd" }.string(from: Date()) let logFileURL = logDirectoryURL.appendingPathComponent("bluetooth_\(dateString).log") do { // 创建日志文件夹 try FileManager.default.createDirectory(at: logDirectoryURL, withIntermediateDirectories: true) // 如果文件不存在,创建文件 if !FileManager.default.fileExists(atPath: logFileURL.path) { FileManager.default.createFile(atPath: logFileURL.path, contents: nil) } // 追加日志内容 if let fileHandle = FileHandle(forWritingAtPath: logFileURL.path) { fileHandle.seekToEndOfFile() if let data = "\(message)\n".data(using: .utf8) { fileHandle.write(data) } fileHandle.closeFile() } } catch { print("写入日志文件失败: \(error.localizedDescription)") } } } // MARK: - DateFormatter 扩展 extension DateFormatter { func with(_ block: (DateFormatter) -> Void) -> DateFormatter { block(self) return self } }