# WiFi功能增强实现文档 ## 概述 基于Medium文章 [Connect to WiFi from iOS App](https://medium.com/@rachnaios/connect-to-wifi-from-ios-app-37253a70aa4e) 的实现方法,我们为MyQrCode应用添加了完整的WiFi自动连接功能。用户扫描WiFi二维码后,可以一键复制密码并自动连接到WiFi网络。 ## 功能特性 ### 1. 扫描WiFi二维码 用户扫描包含WiFi信息的二维码后,可以: - 查看WiFi网络信息(SSID、加密方式、密码状态) - 一键复制WiFi密码 - 智能WiFi设置: - 使用NEHotspotConfiguration进行WiFi自动连接(iOS 11+) - 降级到系统WiFi设置页面 - 最终显示详细的手动设置指导 ### 2. 历史记录管理 在历史记录中查看WiFi二维码时: - 重新获取WiFi密码 - 智能WiFi设置(支持NEHotspotConfiguration和降级方案) - 管理收藏的WiFi信息 ### 3. 便捷操作 - **一键复制密码**: 快速复制WiFi密码到剪贴板 - **智能WiFi设置**: - iOS 11+:使用NEHotspotConfiguration进行WiFi自动连接 - 降级方案:跳转到系统WiFi设置页面 - 最终降级:显示详细的手动设置指导,包含网络名称和密码 - **用户反馈**: 操作后显示确认提示 ### 4. 用户体验 - **视觉区分**: 使用不同颜色的图标区分功能 - **直观操作**: 图标按钮功能一目了然 - **智能降级**: 根据系统版本和权限提供最佳的用户体验 - **标准API**: 使用iOS官方NEHotspotConfiguration API,确保可靠性和兼容性 - **详细指导**: 提供完整的手动设置步骤和网络信息 ## 技术实现 ### 1. 数据结构扩展 #### WiFiDetails结构体 ```swift struct WiFiDetails: Codable { let ssid: String let password: String let encryption: String } ``` #### ParsedQRData扩展 ```swift public struct ParsedQRData: NSSecureCoding { // ... 现有属性 public let extraData: Data? // 新增:存储WiFi详细信息 // 更新初始化方法以支持extraData public init(type: QRCodeType, content: String, extraData: Data? = nil) { self.type = type self.content = content self.extraData = extraData } } ``` ### 2. WiFi连接管理器 创建了专门的`WiFiConnectionManager`类来管理WiFi连接: ```swift class WiFiConnectionManager: ObservableObject { @Published var isConnecting = false @Published var connectionStatus: ConnectionStatus = .idle enum ConnectionStatus { case idle case connecting case connected case failed(String) } static let shared = WiFiConnectionManager() func connectToWiFi(ssid: String, password: String, completion: @escaping (Bool, String?) -> Void) { guard #available(iOS 11.0, *) else { completion(false, "iOS 11+ required for WiFi connection") return } DispatchQueue.main.async { self.isConnecting = true self.connectionStatus = .connecting } // 创建WiFi配置 let configuration = NEHotspotConfiguration(ssid: ssid, passphrase: password, isWEP: false) configuration.joinOnce = true // 应用配置 NEHotspotConfigurationManager.shared.apply(configuration) { [weak self] error in DispatchQueue.main.async { self?.isConnecting = false if let error = error { let errorMessage = self?.handleWiFiError(error) self?.connectionStatus = .failed(errorMessage ?? "Unknown error") completion(false, errorMessage) } else { self?.connectionStatus = .connected completion(true, nil) } } } } private func handleWiFiError(_ error: Error) -> String { let errorCode = (error as NSError).code switch errorCode { case NEHotspotConfigurationError.userDenied.rawValue: return "wifi_user_denied".localized case NEHotspotConfigurationError.alreadyAssociated.rawValue: return "wifi_already_connected".localized case NEHotspotConfigurationError.invalidSSID.rawValue: return "wifi_invalid_ssid".localized case NEHotspotConfigurationError.invalidWPAPassphrase.rawValue: return "wifi_invalid_password".localized default: return "wifi_connection_failed".localized } } } ``` #### 智能降级策略 ```swift func connectWithFallback(ssid: String, password: String, completion: @escaping (Bool, String?) -> Void) { connectToWiFi(ssid: ssid, password: password) { [weak self] success, error in if success { completion(true, nil) } else { // 如果NEHotspotConfiguration失败,尝试降级方案 self?.tryFallbackConnection(ssid: ssid, password: password, completion: completion) } } } private func tryFallbackConnection(ssid: String, password: String, completion: @escaping (Bool, String?) -> Void) { // 尝试打开系统WiFi设置 let systemWifiURLString = "App-Prefs:root=WIFI" if let url = URL(string: systemWifiURLString) { if UIApplication.shared.canOpenURL(url) { UIApplication.shared.open(url) { success in if success { completion(false, "wifi_opened_settings".localized) } else { completion(false, String(format: "wifi_manual_setup_instruction".localized, ssid, password)) } } return } } // 最终降级方案:显示手动设置指导 completion(false, String(format: "wifi_manual_setup_instruction".localized, ssid, password)) } ``` ### 3. 解析器更新 #### QRCodeParser扩展 ```swift private func parseWiFi(_ content: String) -> ParsedQRData? { // WiFi格式: WIFI:S:;T:;P:;; let pattern = "WIFI:S:([^;]+);T:([^;]*);P:([^;]+);;" guard let regex = try? NSRegularExpression(pattern: pattern), let match = regex.firstMatch(in: content, range: NSRange(content.startIndex..., in: content)) else { return nil } let ssid = String(content[Range(match.range(at: 1), in: content)!]) let encryption = String(content[Range(match.range(at: 2), in: content)!]) let password = String(content[Range(match.range(at: 3), in: content)!]) // 创建WiFi详细信息 let wifiDetails = WiFiDetails(ssid: ssid, password: password, encryption: encryption) // 编码为Data存储 let extraData = try? JSONEncoder().encode(wifiDetails) return ParsedQRData(type: .wifi, content: content, extraData: extraData) } ``` ### 4. UI界面更新 #### QRCodeDetailView增强 ```swift // MARK: - 设置WiFi private func setupWiFi() { guard let wifiDetails = getWiFiDetails() else { return } // 使用WiFi连接管理器 WiFiConnectionManager.shared.connectWithFallback(ssid: wifiDetails.ssid, password: wifiDetails.password) { [weak self] success, error in DispatchQueue.main.async { if success { self?.alertMessage = "wifi_connected_successfully".localized } else { self?.alertMessage = error ?? "wifi_connection_failed".localized } self?.showingAlert = true } } } // MARK: - 复制WiFi密码 private func copyWiFiPassword() { guard let wifiDetails = getWiFiDetails() else { return } UIPasteboard.general.string = wifiDetails.password alertMessage = "wifi_password_copied".localized showingAlert = true } // MARK: - 获取WiFi详情 private func getWiFiDetails() -> WiFiDetails? { guard let extraData = historyItem.parsedData?.extraData else { return nil } return try? JSONDecoder().decode(WiFiDetails.self, from: extraData) } ``` #### 条件显示WiFi按钮 ```swift // 在actionButtonsSection中条件显示WiFi按钮 if getQRCodeType() == .wifi { // 复制WiFi密码按钮 Button(action: copyWiFiPassword) { Image(systemName: "doc.on.doc.fill") .font(.title2) .foregroundColor(.orange) } // 设置WiFi按钮 Button(action: setupWiFi) { Image(systemName: "wifi.circle") .font(.title2) .foregroundColor(.purple) } } ``` ### 5. 本地化支持 #### 新增本地化字符串 ```strings // 中文 "wifi_password_copied" = "WiFi密码已复制到剪贴板"; "wifi_connected_successfully" = "WiFi连接成功!"; "wifi_connection_failed" = "WiFi连接失败"; "wifi_opened_settings" = "已打开系统WiFi设置"; "wifi_user_denied" = "用户拒绝了WiFi连接请求"; "wifi_already_connected" = "已经连接到该WiFi网络"; "wifi_invalid_ssid" = "无效的WiFi网络名称"; "wifi_invalid_password" = "WiFi密码格式无效"; // 英文 "wifi_password_copied" = "WiFi password copied to clipboard"; "wifi_connected_successfully" = "WiFi connected successfully!"; "wifi_connection_failed" = "WiFi connection failed"; "wifi_opened_settings" = "Opened system WiFi settings"; "wifi_user_denied" = "User denied WiFi connection request"; "wifi_already_connected" = "Already connected to this WiFi network"; "wifi_invalid_ssid" = "Invalid WiFi network name"; "wifi_invalid_password" = "Invalid WiFi password format"; // 泰语 "wifi_password_copied" = "รหัสผ่าน WiFi ถูกคัดลอกไปยังคลิปบอร์ดแล้ว"; "wifi_connected_successfully" = "เชื่อมต่อ WiFi สำเร็จแล้ว!"; "wifi_connection_failed" = "การเชื่อมต่อ WiFi ล้มเหลว"; "wifi_opened_settings" = "เปิดการตั้งค่า WiFi ของระบบแล้ว"; "wifi_user_denied" = "ผู้ใช้ปฏิเสธคำขอเชื่อมต่อ WiFi"; "wifi_already_connected" = "เชื่อมต่อกับเครือข่าย WiFi นี้แล้ว"; "wifi_invalid_ssid" = "ชื่อเครือข่าย WiFi ไม่ถูกต้อง"; "wifi_invalid_password" = "รูปแบบรหัสผ่าน WiFi ไม่ถูกต้อง"; ``` ## 实现亮点 ### 1. 基于Medium文章的最佳实践 - 使用NEHotspotConfiguration API进行WiFi自动连接 - 实现完整的错误处理和用户反馈 - 采用智能降级策略确保兼容性 ### 2. 架构设计 - 创建专门的WiFi连接管理器类 - 使用ObservableObject进行状态管理 - 实现单例模式便于全局访问 ### 3. 用户体验优化 - 实时连接状态反馈 - 多语言错误提示 - 智能降级策略 - 直观的图标设计 ### 4. 技术特性 - iOS 11+版本兼容性检查 - 完整的错误类型处理 - 异步操作和主线程UI更新 - 内存管理(weak self) ## 使用流程 1. **扫描WiFi二维码**: 用户扫描包含WiFi信息的二维码 2. **查看详情**: 在详情页面查看WiFi网络信息 3. **复制密码**: 点击橙色复制图标复制WiFi密码 4. **自动连接**: 点击紫色WiFi图标尝试自动连接 5. **降级处理**: 如果自动连接失败,系统会尝试打开WiFi设置或显示手动设置指导 ## 错误处理 NEHotspotConfiguration支持的错误类型: - **用户拒绝**: 用户拒绝了WiFi连接请求 - **已连接**: 已经连接到该WiFi网络 - **无效SSID**: 无效的WiFi网络名称 - **无效密码**: WiFi密码格式无效 ## 总结 通过参考Medium文章的实现方法,我们成功为MyQrCode应用添加了完整的WiFi自动连接功能。该实现具有以下优势: 1. **标准API**: 使用iOS官方NEHotspotConfiguration API 2. **智能降级**: 多层降级策略确保所有用户都能使用 3. **完整错误处理**: 详细的错误类型处理和用户反馈 4. **多语言支持**: 支持中文、英文、泰语三种语言 5. **用户体验**: 直观的操作界面和实时状态反馈 这个实现为用户提供了便捷的WiFi连接体验,同时确保了在各种情况下的可靠性和兼容性。