import Foundation import UIKit // MARK: - 二维码解析器 class QRCodeParser { // MARK: - 解析二维码内容 static func parseQRCode(_ content: String) -> ParsedQRData { let trimmedContent = content.trimmingCharacters(in: .whitespacesAndNewlines) // Wi-Fi if trimmedContent.hasPrefix("WIFI:") { return parseWiFi(trimmedContent) } // Email if trimmedContent.hasPrefix("mailto:") { return parseEmail(trimmedContent) } // Phone if trimmedContent.hasPrefix("tel:") { return parsePhone(trimmedContent) } // SMS if trimmedContent.hasPrefix("sms:") { return parseSMS(trimmedContent) } // vCard if trimmedContent.hasPrefix("BEGIN:VCARD") { return parseVCard(trimmedContent) } // MeCard if trimmedContent.hasPrefix("MECARD:") { return parseMeCard(trimmedContent) } // Calendar if trimmedContent.hasPrefix("BEGIN:VEVENT") { return parseCalendar(trimmedContent) } // Instagram if trimmedContent.contains("instagram.com") { return parseInstagram(trimmedContent) } // Facebook if trimmedContent.contains("facebook.com") { return parseFacebook(trimmedContent) } // Spotify if trimmedContent.hasPrefix("spotify:") { return parseSpotify(trimmedContent) } // Twitter if trimmedContent.contains("twitter.com") { return parseTwitter(trimmedContent) } // WhatsApp if trimmedContent.contains("wa.me") { return parseWhatsApp(trimmedContent) } // Viber if trimmedContent.hasPrefix("viber://") { return parseViber(trimmedContent) } // Snapchat if trimmedContent.hasPrefix("snapchat://") { return parseSnapchat(trimmedContent) } // TikTok if trimmedContent.contains("tiktok.com") { return parseTikTok(trimmedContent) } // URL (检查是否为有效的URL) if isValidURL(trimmedContent) { return parseURL(trimmedContent) } // Location if trimmedContent.hasPrefix("geo:") { return parseLocation(trimmedContent) } // 默认为文本类型 return ParsedQRData( type: .text, title: "文本信息", subtitle: trimmedContent.count > 50 ? String(trimmedContent.prefix(50)) + "..." : trimmedContent, icon: "text.quote" ) } // MARK: - 解析Wi-Fi private static func parseWiFi(_ content: String) -> ParsedQRData { let wifiInfo = content.replacingOccurrences(of: "WIFI:", with: "") let components = wifiInfo.components(separatedBy: ";") var ssid = "" var password = "" var encryption = "WPA" for component in components { if component.hasPrefix("S:") { ssid = String(component.dropFirst(2)) } else if component.hasPrefix("P:") { password = String(component.dropFirst(2)) } else if component.hasPrefix("T:") { encryption = String(component.dropFirst(2)) } } let title = "Wi-Fi网络" let subtitle = "网络名称: \(ssid)\n加密类型: \(encryption)\n密码: \(password.isEmpty ? "无" : "已设置")" return ParsedQRData( type: .wifi, title: title, subtitle: subtitle, icon: "wifi" ) } // MARK: - 解析Email private static func parseEmail(_ content: String) -> ParsedQRData { let email = content.replacingOccurrences(of: "mailto:", with: "") return ParsedQRData( type: .mail, title: "邮箱地址", subtitle: email, icon: "envelope" ) } // MARK: - 解析Phone private static func parsePhone(_ content: String) -> ParsedQRData { let phone = content.replacingOccurrences(of: "tel:", with: "") return ParsedQRData( type: .phone, title: "电话号码", subtitle: phone, icon: "phone" ) } // MARK: - 解析SMS private static func parseSMS(_ content: String) -> ParsedQRData { let smsInfo = content.replacingOccurrences(of: "sms:", with: "") let components = smsInfo.components(separatedBy: "?body=") let phone = components.first ?? "" let message = components.count > 1 ? components[1] : "" let title = "短信" let subtitle = "号码: \(phone)\n内容: \(message)" return ParsedQRData( type: .sms, title: title, subtitle: subtitle, icon: "message" ) } // MARK: - 解析vCard private static func parseVCard(_ content: String) -> ParsedQRData { let lines = content.components(separatedBy: .newlines) var name = "" var phone = "" var email = "" for line in lines { if line.hasPrefix("FN:") { name = String(line.dropFirst(3)) } else if line.hasPrefix("TEL:") { phone = String(line.dropFirst(4)) } else if line.hasPrefix("EMAIL:") { email = String(line.dropFirst(6)) } } let title = "联系人信息" let subtitle = "姓名: \(name)\n电话: \(phone)\n邮箱: \(email)" return ParsedQRData( type: .vcard, title: title, subtitle: subtitle, icon: "person.crop.rectangle" ) } // MARK: - 解析MeCard private static func parseMeCard(_ content: String) -> ParsedQRData { let mecardInfo = content.replacingOccurrences(of: "MECARD:", with: "") let components = mecardInfo.components(separatedBy: ";") var name = "" var phone = "" var email = "" var address = "" for component in components { if component.hasPrefix("N:") { name = String(component.dropFirst(2)) } else if component.hasPrefix("TEL:") { phone = String(component.dropFirst(4)) } else if component.hasPrefix("EMAIL:") { email = String(component.dropFirst(6)) } else if component.hasPrefix("ADR:") { address = String(component.dropFirst(4)) } } let title = "联系人信息" let subtitle = "姓名: \(name)\n电话: \(phone)\n邮箱: \(email)\n地址: \(address)" return ParsedQRData( type: .mecard, title: title, subtitle: subtitle, icon: "person.crop.rectangle" ) } // MARK: - 解析Calendar private static func parseCalendar(_ content: String) -> ParsedQRData { let lines = content.components(separatedBy: .newlines) var summary = "" var startTime = "" var endTime = "" var location = "" var description = "" for line in lines { if line.hasPrefix("SUMMARY:") { summary = String(line.dropFirst(8)) } else if line.hasPrefix("DTSTART:") { startTime = String(line.dropFirst(8)) } else if line.hasPrefix("DTEND:") { endTime = String(line.dropFirst(6)) } else if line.hasPrefix("LOCATION:") { location = String(line.dropFirst(9)) } else if line.hasPrefix("DESCRIPTION:") { description = String(line.dropFirst(12)) } } // 格式化时间显示 let formattedStartTime = formatCalendarTime(startTime) let formattedEndTime = formatCalendarTime(endTime) let title = "日历事件" var subtitle = "事件: \(summary)\n开始: \(formattedStartTime)\n结束: \(formattedEndTime)" if !location.isEmpty { subtitle += "\n地点: \(location)" } if !description.isEmpty { subtitle += "\n描述: \(description)" } return ParsedQRData( type: .calendar, title: title, subtitle: subtitle, icon: "calendar" ) } // MARK: - 格式化日历时间 private static func formatCalendarTime(_ timeString: String) -> String { guard timeString.count >= 15 else { return timeString } let dateFormatter = DateFormatter() dateFormatter.dateFormat = "yyyyMMdd'T'HHmmss" if let date = dateFormatter.date(from: timeString) { let displayFormatter = DateFormatter() displayFormatter.dateStyle = .medium displayFormatter.timeStyle = .short return displayFormatter.string(from: date) } return timeString } // MARK: - 解析Instagram private static func parseInstagram(_ content: String) -> ParsedQRData { let username = content.components(separatedBy: "/").dropLast().last ?? "" return ParsedQRData( type: .instagram, title: "Instagram", subtitle: "用户名: \(username)", icon: "camera" ) } // MARK: - 解析Facebook private static func parseFacebook(_ content: String) -> ParsedQRData { let pageId = content.components(separatedBy: "/").dropLast().last ?? "" return ParsedQRData( type: .facebook, title: "Facebook", subtitle: "页面: \(pageId)", icon: "person.2" ) } // MARK: - 解析Spotify private static func parseSpotify(_ content: String) -> ParsedQRData { let trackId = content.replacingOccurrences(of: "spotify:track:", with: "") return ParsedQRData( type: .spotify, title: "Spotify", subtitle: "曲目ID: \(trackId)", icon: "music.note" ) } // MARK: - 解析Twitter private static func parseTwitter(_ content: String) -> ParsedQRData { let username = content.components(separatedBy: "/").dropLast().last ?? "" return ParsedQRData( type: .twitter, title: "Twitter", subtitle: "用户名: \(username)", icon: "bird" ) } // MARK: - 解析WhatsApp private static func parseWhatsApp(_ content: String) -> ParsedQRData { let phone = content.replacingOccurrences(of: "https://wa.me/", with: "") return ParsedQRData( type: .whatsapp, title: "WhatsApp", subtitle: "电话号码: \(phone)", icon: "message.circle" ) } // MARK: - 解析Viber private static func parseViber(_ content: String) -> ParsedQRData { let phone = content.replacingOccurrences(of: "viber://contact?number=", with: "") return ParsedQRData( type: .viber, title: "Viber", subtitle: "电话号码: \(phone)", icon: "bubble.left.and.bubble.right" ) } // MARK: - 解析Snapchat private static func parseSnapchat(_ content: String) -> ParsedQRData { let username = content.replacingOccurrences(of: "snapchat://", with: "") return ParsedQRData( type: .snapchat, title: "Snapchat", subtitle: "用户名: \(username)", icon: "camera.viewfinder" ) } // MARK: - 解析TikTok private static func parseTikTok(_ content: String) -> ParsedQRData { let username = content.components(separatedBy: "@").last?.replacingOccurrences(of: "/", with: "") ?? "" return ParsedQRData( type: .tiktok, title: "TikTok", subtitle: "用户名: \(username)", icon: "music.mic" ) } // MARK: - 解析URL private static func parseURL(_ content: String) -> ParsedQRData { return ParsedQRData( type: .url, title: "网址链接", subtitle: content, icon: "link" ) } // MARK: - 解析Location private static func parseLocation(_ content: String) -> ParsedQRData { let coordinates = content.replacingOccurrences(of: "geo:", with: "") let coords = coordinates.components(separatedBy: ",") let latitude = coords.first ?? "" let longitude = coords.count > 1 ? coords[1] : "" let title = "地理位置" let subtitle = "纬度: \(latitude)\n经度: \(longitude)" return ParsedQRData( type: .location, title: title, subtitle: subtitle, icon: "location" ) } // MARK: - 验证URL private static func isValidURL(_ string: String) -> Bool { guard let url = URL(string: string) else { return false } return UIApplication.shared.canOpenURL(url) } }