You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

111 lines
3.9 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import Foundation
import NetworkExtension
import UIKit
import Combine
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()
private init() {}
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
}
}
func resetStatus() {
DispatchQueue.main.async {
self.connectionStatus = .idle
self.isConnecting = false
}
}
}
// MARK: - WiFi
extension WiFiConnectionManager {
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))
}
}