diff --git a/demo-esp32.xcodeproj/project.pbxproj b/demo-esp32.xcodeproj/project.pbxproj index 9a975c1..0848172 100644 --- a/demo-esp32.xcodeproj/project.pbxproj +++ b/demo-esp32.xcodeproj/project.pbxproj @@ -756,6 +756,9 @@ "HEADER_SEARCH_PATHS[arch=*]" = "$(SRCROOT)/BlufiLibrary/Security/openssl/include/"; INFOPLIST_KEY_NSBluetoothAlwaysUsageDescription = "需要使用蓝牙来配置ESP32设备"; INFOPLIST_KEY_NSBluetoothPeripheralUsageDescription = "需要蓝牙权限来搜索和连接ESP32设备"; + INFOPLIST_KEY_NSLocationAlwaysAndWhenInUseUsageDescription = "This application uses location permissions to obtain currently connected Wi-Fi information. This application does not collect, store or record any location data."; + INFOPLIST_KEY_NSLocationAlwaysUsageDescription = "This application uses location permissions to obtain currently connected Wi-Fi information. This application does not collect, store or record any location data."; + INFOPLIST_KEY_NSLocationWhenInUseUsageDescription = "This application uses location permissions to obtain currently connected Wi-Fi information. This application does not collect, store or record any location data."; INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchScreen_Generation = YES; @@ -794,6 +797,9 @@ "HEADER_SEARCH_PATHS[arch=*]" = "$(SRCROOT)/BlufiLibrary/Security/openssl/include/"; INFOPLIST_KEY_NSBluetoothAlwaysUsageDescription = "需要使用蓝牙来配置ESP32设备"; INFOPLIST_KEY_NSBluetoothPeripheralUsageDescription = "需要蓝牙权限来搜索和连接ESP32设备"; + INFOPLIST_KEY_NSLocationAlwaysAndWhenInUseUsageDescription = "This application uses location permissions to obtain currently connected Wi-Fi information. This application does not collect, store or record any location data."; + INFOPLIST_KEY_NSLocationAlwaysUsageDescription = "This application uses location permissions to obtain currently connected Wi-Fi information. This application does not collect, store or record any location data."; + INFOPLIST_KEY_NSLocationWhenInUseUsageDescription = "This application uses location permissions to obtain currently connected Wi-Fi information. This application does not collect, store or record any location data."; INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchScreen_Generation = YES; diff --git a/demo-esp32.xcodeproj/project.xcworkspace/xcuserdata/xinceioskaifa.xcuserdatad/UserInterfaceState.xcuserstate b/demo-esp32.xcodeproj/project.xcworkspace/xcuserdata/xinceioskaifa.xcuserdatad/UserInterfaceState.xcuserstate index 2ba42dd..0cabdc6 100644 Binary files a/demo-esp32.xcodeproj/project.xcworkspace/xcuserdata/xinceioskaifa.xcuserdatad/UserInterfaceState.xcuserstate and b/demo-esp32.xcodeproj/project.xcworkspace/xcuserdata/xinceioskaifa.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/demo-esp32/BlufiManager.swift b/demo-esp32/BlufiManager.swift index 09a7794..dbba285 100644 --- a/demo-esp32/BlufiManager.swift +++ b/demo-esp32/BlufiManager.swift @@ -22,6 +22,7 @@ class BlufiManager: NSObject { var onConnected: (() -> Void)? var onConfigured: (() -> Void)? var onDeviceFound: ((CBPeripheral, NSNumber) -> Void)? + var onWifiScanResult: (([BlufiScanResponse]) -> Void)? override private init() { super.init() @@ -261,8 +262,8 @@ extension BlufiManager: BlufiDelegate { if status == StatusSuccess { print("WiFi 扫描成功") if let results = scanResults { - for result in results { - print("发现 WiFi: \(result.ssid ?? "Unknown"), 信号强度: \(result.rssi)") + DispatchQueue.main.async { [weak self] in + self?.onWifiScanResult?(results) } } } else { diff --git a/demo-esp32/ContentView.swift b/demo-esp32/ContentView.swift index 8304ac6..d24fe60 100644 --- a/demo-esp32/ContentView.swift +++ b/demo-esp32/ContentView.swift @@ -56,6 +56,7 @@ class BluetoothViewModel: ObservableObject { @Published var state: BluetoothState = .poweredOff @Published var discoveredDevices: [DiscoveredDevice] = [] @Published var wifiNetworks: [(ssid: String, rssi: Int8)] = [] + @Published var isWifiScanning: Bool = false private let blufiManager = BlufiManager.shared @@ -93,6 +94,15 @@ class BluetoothViewModel: ObservableObject { DispatchQueue.main.async { self?.state = .configured } + } + + // 在 setupCallbacks() 中添加 + blufiManager.onWifiScanResult = { [weak self] results in + DispatchQueue.main.async { + self?.isWifiScanning = false + self?.wifiNetworks = results.map { ($0.ssid ?? "Unknown", $0.rssi) } + .sorted { $0.rssi > $1.rssi } // 按信号强度排序 + } } // 添加设备发现回调 @@ -139,7 +149,8 @@ class BluetoothViewModel: ObservableObject { } func scanWiFi() { - state = .configuring + isWifiScanning = true + wifiNetworks.removeAll() blufiManager.scanWiFi() } } @@ -207,18 +218,67 @@ struct ContentView: View { } private var wifiConfigForm: some View { - VStack(spacing: 16) { - TextField("WiFi名称", text: $wifiSSID) - .textFieldStyle(RoundedBorderTextFieldStyle()) - .padding(.horizontal) + VStack(spacing: 20) { + Button(action: { + viewModel.scanWiFi() + }) { + HStack { + Text(viewModel.state == .configuring ? "正在扫描..." : "扫描附近WiFi") + if viewModel.state == .configuring { + ProgressView() + .progressViewStyle(CircularProgressViewStyle()) + } + } .frame(maxWidth: .infinity) + .padding() + .background(viewModel.state == .configuring ? Color.gray : Color.blue) + .foregroundColor(.white) + .cornerRadius(8) + } + .disabled(viewModel.state == .configuring) - SecureField("WiFi密码", text: $wifiPassword) - .textFieldStyle(RoundedBorderTextFieldStyle()) - .padding(.horizontal) - .frame(maxWidth: .infinity) + if viewModel.isWifiScanning { + ProgressView("正在扫描WiFi网络...") + .progressViewStyle(CircularProgressViewStyle()) + } else if viewModel.wifiNetworks.isEmpty { + Text("未找到WiFi网络") + .foregroundColor(.gray) + } else { + Picker("选择WiFi", selection: $wifiSSID) { + ForEach(viewModel.wifiNetworks, id: \.ssid) { network in + HStack { + Image(systemName: "wifi") + Text("\(network.ssid)") + Spacer() + Text("\(network.rssi)dBm") + .foregroundColor(.gray) + } + .tag(network.ssid) + } + } + .pickerStyle(MenuPickerStyle()) + } + + // WiFi密码输入框 + if !wifiSSID.isEmpty { + SecureField("WiFi密码", text: $wifiPassword) + .textFieldStyle(RoundedBorderTextFieldStyle()) + .padding(.horizontal) + } + + // 配置按钮 + Button(action: { + viewModel.configureWiFi(ssid: wifiSSID, password: wifiPassword) + }) { + Text("配置WiFi") + .frame(maxWidth: .infinity) + .padding() + .background(Color.green) + .foregroundColor(.white) + .cornerRadius(8) + } } - .padding(.vertical) + .padding() } private var actionButton: some View {