From a5f0cc1df4ab4d3d7601da08b4f26791d396d91f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 29 Dec 2025 12:10:36 +0000 Subject: [PATCH 1/4] Initial plan From 56b36a8035244a43d3c452dd17973b09995c0d9d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 29 Dec 2025 12:21:05 +0000 Subject: [PATCH 2/4] Add async currentNetworkInfo API to ConnectivityWrapper and async activeURL to ConnectionInfo Co-authored-by: bgoncal <5808343+bgoncal@users.noreply.github.com> --- .../NetworkInput/HomeNetworkInputView.swift | 5 +- .../Extensions/ConnectionInfo+WebView.swift | 54 ++++++++ ...onnectionSecurityLevelBlockViewModel.swift | 35 ++--- Sources/App/WebView/WebViewController.swift | 8 +- Sources/Improv/ImprovDiscoverView.swift | 7 +- Sources/Shared/API/ConnectionInfo.swift | 99 ++++++++++++++ .../Environment/ConnectivityWrapper.swift | 59 +++++++++ Tests/Shared/ConnectionInfo.test.swift | 124 ++++++++++++++++++ 8 files changed, 367 insertions(+), 24 deletions(-) diff --git a/Sources/App/Onboarding/Steps/Permissions/Steps/LocalAccessAndNetworkInput/NetworkInput/HomeNetworkInputView.swift b/Sources/App/Onboarding/Steps/Permissions/Steps/LocalAccessAndNetworkInput/NetworkInput/HomeNetworkInputView.swift index c5eeb477a5..dfd77beaa3 100644 --- a/Sources/App/Onboarding/Steps/Permissions/Steps/LocalAccessAndNetworkInput/NetworkInput/HomeNetworkInputView.swift +++ b/Sources/App/Onboarding/Steps/Permissions/Steps/LocalAccessAndNetworkInput/NetworkInput/HomeNetworkInputView.swift @@ -141,8 +141,9 @@ struct HomeNetworkInputView: View { } private func loadCurrentNetworkInfo() { - Current.connectivity.syncNetworkInformation { - networkName = Current.connectivity.currentWiFiSSID() ?? "" + Task { @MainActor in + let networkInfo = await Current.connectivity.currentNetworkInfo() + networkName = networkInfo.ssid ?? "" hardwareAddress = Current.connectivity.currentNetworkHardwareAddress() ?? "" } } diff --git a/Sources/App/WebView/Extensions/ConnectionInfo+WebView.swift b/Sources/App/WebView/Extensions/ConnectionInfo+WebView.swift index 9be3f4609e..591b590073 100644 --- a/Sources/App/WebView/Extensions/ConnectionInfo+WebView.swift +++ b/Sources/App/WebView/Extensions/ConnectionInfo+WebView.swift @@ -21,10 +21,35 @@ extension ConnectionInfo { return components } + /// Async version that fetches real-time network info. + mutating func webviewURLComponents() async -> URLComponents? { + if Current.appConfiguration == .fastlaneSnapshot, prefs.object(forKey: "useDemo") != nil { + return URLComponents(string: "https://companion.home-assistant.io/app/ios/demo")! + } + guard let activeURL = await activeURL() else { + Current.Log.error("No activeURL available while webviewURLComponents was called") + return nil + } + + guard var components = URLComponents(url: activeURL, resolvingAgainstBaseURL: true) else { + return nil + } + + let queryItem = URLQueryItem(name: "external_auth", value: "1") + components.queryItems = [queryItem] + + return components + } + mutating func webviewURL() -> URL? { webviewURLComponents()?.url } + /// Async version that fetches real-time network info. + mutating func webviewURL() async -> URL? { + await webviewURLComponents()?.url + } + mutating func webviewURL(from raw: String) -> URL? { guard let baseURLComponents = webviewURLComponents(), let baseURL = baseURLComponents.url else { return nil @@ -52,4 +77,33 @@ extension ConnectionInfo { return nil } } + + /// Async version that fetches real-time network info. + mutating func webviewURL(from raw: String) async -> URL? { + guard let baseURLComponents = await webviewURLComponents(), let baseURL = baseURLComponents.url else { + return nil + } + + if raw.starts(with: "/") { + if let rawComponents = URLComponents(string: raw) { + var components = baseURLComponents + components.path.append(rawComponents.path) + components.fragment = rawComponents.fragment + + if let items = rawComponents.queryItems { + var queryItems = components.queryItems ?? [] + queryItems.append(contentsOf: items) + components.queryItems = queryItems + } + + return components.url + } else { + return baseURL.appendingPathComponent(raw) + } + } else if let url = URL(string: raw), url.baseIsEqual(to: baseURL) { + return url + } else { + return nil + } + } } diff --git a/Sources/App/WebView/Views/ConnectionSecurityLevelBlock/ConnectionSecurityLevelBlockViewModel.swift b/Sources/App/WebView/Views/ConnectionSecurityLevelBlock/ConnectionSecurityLevelBlockViewModel.swift index 39621176aa..f70f397a0c 100644 --- a/Sources/App/WebView/Views/ConnectionSecurityLevelBlock/ConnectionSecurityLevelBlockViewModel.swift +++ b/Sources/App/WebView/Views/ConnectionSecurityLevelBlock/ConnectionSecurityLevelBlockViewModel.swift @@ -40,23 +40,28 @@ final class ConnectionSecurityLevelBlockViewModel: ObservableObject { } func loadRequirements() { - requirements = [] - - // Check if home network is defined - if server.info.connection.internalSSIDs?.isEmpty ?? true, - server.info.connection.internalHardwareAddresses?.isEmpty ?? true { - requirements.append(.homeNetworkMissing) - } else { - // Check if user is on home network - if !server.info.connection.isOnInternalNetwork { - requirements.append(.notOnHomeNetwork) + Task { @MainActor in + var newRequirements: [Requirement] = [] + + // Check if home network is defined + if server.info.connection.internalSSIDs?.isEmpty ?? true, + server.info.connection.internalHardwareAddresses?.isEmpty ?? true { + newRequirements.append(.homeNetworkMissing) + } else { + // Check if user is on home network (fetch real-time network info) + let isOnInternal = await server.info.connection.isOnInternalNetwork() + if !isOnInternal { + newRequirements.append(.notOnHomeNetwork) + } + } + + // Check location permission + let currentPermission = Current.locationManager.currentPermissionState + if currentPermission != .authorizedAlways, currentPermission != .authorizedWhenInUse { + newRequirements.append(.locationPermission) } - } - // Check location permission - let currentPermission = Current.locationManager.currentPermissionState - if currentPermission != .authorizedAlways, currentPermission != .authorizedWhenInUse { - requirements.append(.locationPermission) + requirements = newRequirements } } } diff --git a/Sources/App/WebView/WebViewController.swift b/Sources/App/WebView/WebViewController.swift index ff696c2c0b..348dccea3f 100644 --- a/Sources/App/WebView/WebViewController.swift +++ b/Sources/App/WebView/WebViewController.swift @@ -781,13 +781,13 @@ final class WebViewController: UIViewController, WKNavigationDelegate, WKUIDeleg loadActiveURLIfNeededInProgress = true Current.Log.info("loadActiveURLIfNeeded called") - Current.connectivity.syncNetworkInformation { [weak self] in + Task { @MainActor [weak self] in defer { self?.loadActiveURLIfNeededInProgress = false } guard let self else { return } - guard let webviewURL = server.info.connection.webviewURL() else { + guard let webviewURL = await server.info.connection.webviewURL() else { Current.Log.info("not loading, no url") showNoActiveURLError() return @@ -1526,10 +1526,10 @@ extension WebViewController: WebViewControllerProtocol { } @objc func refresh() { - Current.connectivity.syncNetworkInformation { [weak self] in + Task { @MainActor [weak self] in guard let self else { return } // called via menu/keyboard shortcut too - if let webviewURL = server.info.connection.webviewURL() { + if let webviewURL = await server.info.connection.webviewURL() { if webView.url?.baseIsEqual(to: webviewURL) == true, !lastNavigationWasServerError { reload() } else { diff --git a/Sources/Improv/ImprovDiscoverView.swift b/Sources/Improv/ImprovDiscoverView.swift index 536beffd11..ff3e2c3c5e 100644 --- a/Sources/Improv/ImprovDiscoverView.swift +++ b/Sources/Improv/ImprovDiscoverView.swift @@ -167,9 +167,10 @@ struct ImprovDiscoverView: View where Manager: ImprovManagerProtocol { selectedPeripheral = peripheral // This only works if location permission is permitted - Current.connectivity.syncNetworkInformation { - if let ssid = Current.connectivity.currentWiFiSSID() { - self.ssid = ssid + Task { @MainActor in + let networkInfo = await Current.connectivity.currentNetworkInfo() + if let networkSSID = networkInfo.ssid { + self.ssid = networkSSID } } showWifiAlert = true diff --git a/Sources/Shared/API/ConnectionInfo.swift b/Sources/Shared/API/ConnectionInfo.swift index 0174d62525..cdad7ce7a2 100644 --- a/Sources/Shared/API/ConnectionInfo.swift +++ b/Sources/Shared/API/ConnectionInfo.swift @@ -258,6 +258,65 @@ public struct ConnectionInfo: Codable, Equatable { return url?.sanitized() } + /// Returns the url that should be used at this moment to access the Home Assistant instance. + /// This version fetches real-time network information asynchronously, avoiding race conditions. + public mutating func activeURL() async -> URL? { + if let overrideActiveURLType { + let overrideURL: URL? + + switch overrideActiveURLType { + case .internal: + activeURLType = .internal + overrideURL = internalURL + case .remoteUI: + activeURLType = .remoteUI + overrideURL = remoteUIURL + case .external: + activeURLType = .external + overrideURL = externalURL + case .none: + activeURLType = .none + overrideURL = nil + } + + if let overrideURL { + return overrideURL.sanitized() + } + } + + let url: URL? + let onInternalNetwork = await isOnInternalNetwork() + + if let internalURL, onInternalNetwork || overrideActiveURLType == .internal { + // Home network, local connection + activeURLType = .internal + url = internalURL + } else if let remoteUIURL, useCloud { + // Home Assistant Cloud connection + activeURLType = .remoteUI + url = remoteUIURL + } else if let externalURL { + // Custom remote connection + activeURLType = .external + url = externalURL + } else if let internalURL, [.lessSecure, .undefined].contains(connectionAccessSecurityLevel) { + // Falback to internal URL if no other URL is set + // In case user opted to not check for home network or haven't made a decision yet + // we allow usage of internal URL as fallback + activeURLType = .internal + url = internalURL + } else if let internalURL, internalURL.scheme == "https" { + // Falback to internal URL if no other URL is set and internal URL is HTTPS + activeURLType = .internal + url = internalURL + } else { + url = nil + activeURLType = .none + } + + return url?.sanitized() + } + /// Returns the url that should be used at this moment to share with someone else to access the Home Assistant /// instance. /// Cloud > Remote > Internal @@ -282,6 +341,15 @@ public struct ConnectionInfo: Codable, Equatable { } } + /// Returns the activeURL with /api appended. Fetches real-time network info. + public mutating func activeAPIURL() async -> URL? { + if let activeURL = await activeURL() { + return activeURL.appendingPathComponent("api", isDirectory: false) + } else { + return nil + } + } + public mutating func webhookURL() -> URL? { if let cloudhookURL, !isOnInternalNetwork { return cloudhookURL @@ -294,6 +362,20 @@ public struct ConnectionInfo: Codable, Equatable { } } + /// Returns the webhook URL. Fetches real-time network info. + public mutating func webhookURL() async -> URL? { + let onInternalNetwork = await isOnInternalNetwork() + if let cloudhookURL, !onInternalNetwork { + return cloudhookURL + } + + if let activeURL = await activeURL() { + return activeURL.appendingPathComponent(webhookPath, isDirectory: false) + } else { + return nil + } + } + public var webhookPath: String { "api/webhook/\(webhookID)" } @@ -321,6 +403,7 @@ public struct ConnectionInfo: Codable, Equatable { } /// Returns true if current SSID is SSID marked for internal URL use. + /// Note: This uses cached network info. For real-time network state, use `isOnInternalNetwork() async`. public var isOnInternalNetwork: Bool { if let current = Current.connectivity.currentWiFiSSID(), internalSSIDs?.contains(current) == true { @@ -335,6 +418,22 @@ public struct ConnectionInfo: Codable, Equatable { return false } + /// Returns true if current SSID is SSID marked for internal URL use. + /// This fetches real-time network information asynchronously. + public func isOnInternalNetwork() async -> Bool { + let networkInfo = await Current.connectivity.currentNetworkInfo() + if let ssid = networkInfo.ssid, internalSSIDs?.contains(ssid) == true { + return true + } + + if let current = Current.connectivity.currentNetworkHardwareAddress(), + internalHardwareAddresses?.contains(current) == true { + return true + } + + return false + } + public var hasInternalURLSet: Bool { internalURL != nil } diff --git a/Sources/Shared/Environment/ConnectivityWrapper.swift b/Sources/Shared/Environment/ConnectivityWrapper.swift index 2fce7dcb3e..2492ca082d 100644 --- a/Sources/Shared/Environment/ConnectivityWrapper.swift +++ b/Sources/Shared/Environment/ConnectivityWrapper.swift @@ -6,6 +6,17 @@ import Reachability import Communicator import NetworkExtension +/// Real-time network information fetched asynchronously +public struct NetworkInfo: Equatable { + public let ssid: String? + public let bssid: String? + + public init(ssid: String?, bssid: String?) { + self.ssid = ssid + self.bssid = bssid + } +} + /// Wrapper around CoreTelephony, Reachability public class ConnectivityWrapper { public var connectivityDidChangeNotification: () -> Notification.Name @@ -17,6 +28,10 @@ public class ConnectivityWrapper { public var cellularNetworkType: () -> NetworkType public var networkAttributes: () -> [String: Any] + /// Async method to fetch current WiFi network info in real-time. + /// This is the preferred method to use for critical operations that need the latest network state. + public var currentNetworkInfo: () async -> NetworkInfo + #if targetEnvironment(macCatalyst) init() { self.hasWiFi = { Current.macBridge.networkConnectivity.hasWiFi } @@ -43,6 +58,13 @@ public class ConnectivityWrapper { return [:] } } + // For macCatalyst, we can get the info synchronously from macBridge + self.currentNetworkInfo = { + NetworkInfo( + ssid: Current.macBridge.networkConnectivity.wifi?.ssid, + bssid: Current.macBridge.networkConnectivity.wifi?.bssid + ) + } } #elseif os(iOS) @@ -67,6 +89,11 @@ public class ConnectivityWrapper { self.currentNetworkHardwareAddress = { nil } self.networkAttributes = { [:] } + // Default async implementation that fetches real-time network info + self.currentNetworkInfo = { + await Self.fetchNetworkInfo() + } + syncNetworkInformation() NotificationCenter.default.addObserver( @@ -90,6 +117,11 @@ public class ConnectivityWrapper { self.cellularNetworkType = { .unknown } self.currentNetworkHardwareAddress = { nil } self.networkAttributes = { [:] } + // For watchOS, get SSID from user defaults (synced from iOS) + self.currentNetworkInfo = { + let ssid = WatchUserDefaults.shared.string(for: .watchSSID) + return NetworkInfo(ssid: ssid, bssid: nil) + } } #endif @@ -130,4 +162,31 @@ public class ConnectivityWrapper { } #endif } + + /// Fetches network info asynchronously. This should be used for operations requiring real-time data. + private static func fetchNetworkInfo() async -> NetworkInfo { + #if targetEnvironment(macCatalyst) + return NetworkInfo( + ssid: Current.macBridge.networkConnectivity.wifi?.ssid, + bssid: Current.macBridge.networkConnectivity.wifi?.bssid + ) + #elseif os(iOS) + return await withCheckedContinuation { continuation in + NEHotspotNetwork.fetchCurrent { hotspotNetwork in + #if targetEnvironment(simulator) + let ssid: String? = "Simulator" + #else + let ssid = hotspotNetwork?.ssid + #endif + let bssid = hotspotNetwork?.bssid + Current.Log + .verbose("Fetched network info - SSID: \(String(describing: ssid)), BSSID: \(String(describing: bssid))") + continuation.resume(returning: NetworkInfo(ssid: ssid, bssid: bssid)) + } + } + #else + let ssid = WatchUserDefaults.shared.string(for: .watchSSID) + return NetworkInfo(ssid: ssid, bssid: nil) + #endif + } } diff --git a/Tests/Shared/ConnectionInfo.test.swift b/Tests/Shared/ConnectionInfo.test.swift index 54a49c7ed7..acaf23952b 100644 --- a/Tests/Shared/ConnectionInfo.test.swift +++ b/Tests/Shared/ConnectionInfo.test.swift @@ -701,4 +701,128 @@ class ConnectionInfoTests: XCTestCase { XCTAssertEqual(info.activeURL(), internalURL) XCTAssertEqual(info.activeURLType, .internal) } + + // MARK: - Async API Tests + + func testAsyncActiveURLWithInternalNetwork() async { + let internalURL = URL(string: "http://internal.example.com:8123") + let externalURL = URL(string: "http://external.example.com:8123") + var info = ConnectionInfo( + externalURL: externalURL, + internalURL: internalURL, + cloudhookURL: nil, + remoteUIURL: nil, + webhookID: "webhook_id1", + webhookSecret: nil, + internalSSIDs: ["unit_tests"], + internalHardwareAddresses: nil, + isLocalPushEnabled: false, + securityExceptions: .init(), + connectionAccessSecurityLevel: .undefined + ) + + // Mock the async currentNetworkInfo to return the internal network SSID + Current.connectivity.currentNetworkInfo = { + NetworkInfo(ssid: "unit_tests", bssid: nil) + } + + let url = await info.activeURL() + XCTAssertEqual(url, internalURL) + XCTAssertEqual(info.activeURLType, .internal) + } + + func testAsyncActiveURLWithExternalNetwork() async { + let internalURL = URL(string: "http://internal.example.com:8123") + let externalURL = URL(string: "http://external.example.com:8123") + var info = ConnectionInfo( + externalURL: externalURL, + internalURL: internalURL, + cloudhookURL: nil, + remoteUIURL: nil, + webhookID: "webhook_id1", + webhookSecret: nil, + internalSSIDs: ["home_network"], + internalHardwareAddresses: nil, + isLocalPushEnabled: false, + securityExceptions: .init(), + connectionAccessSecurityLevel: .undefined + ) + + // Mock the async currentNetworkInfo to return a different network + Current.connectivity.currentNetworkInfo = { + NetworkInfo(ssid: "coffee_shop", bssid: nil) + } + + let url = await info.activeURL() + XCTAssertEqual(url, externalURL) + XCTAssertEqual(info.activeURLType, .external) + } + + func testAsyncIsOnInternalNetwork() async { + var info = ConnectionInfo( + externalURL: URL(string: "http://external.example.com:8123"), + internalURL: URL(string: "http://internal.example.com:8123"), + cloudhookURL: nil, + remoteUIURL: nil, + webhookID: "webhook_id1", + webhookSecret: nil, + internalSSIDs: ["home_wifi"], + internalHardwareAddresses: nil, + isLocalPushEnabled: false, + securityExceptions: .init(), + connectionAccessSecurityLevel: .undefined + ) + + // Test when on internal network + Current.connectivity.currentNetworkInfo = { + NetworkInfo(ssid: "home_wifi", bssid: nil) + } + + let onInternal = await info.isOnInternalNetwork() + XCTAssertTrue(onInternal) + + // Test when on external network + Current.connectivity.currentNetworkInfo = { + NetworkInfo(ssid: "other_wifi", bssid: nil) + } + + let onExternal = await info.isOnInternalNetwork() + XCTAssertFalse(onExternal) + } + + func testAsyncWebhookURL() async { + let internalURL = URL(string: "http://internal.example.com:8123") + let externalURL = URL(string: "http://external.example.com:8123") + let cloudhookURL = URL(string: "http://cloudhook.example.com") + + var info = ConnectionInfo( + externalURL: externalURL, + internalURL: internalURL, + cloudhookURL: cloudhookURL, + remoteUIURL: nil, + webhookID: "webhook_id1", + webhookSecret: nil, + internalSSIDs: ["home_wifi"], + internalHardwareAddresses: nil, + isLocalPushEnabled: false, + securityExceptions: .init(), + connectionAccessSecurityLevel: .undefined + ) + + // Test when on internal network - should return internal URL webhook + Current.connectivity.currentNetworkInfo = { + NetworkInfo(ssid: "home_wifi", bssid: nil) + } + + let internalWebhookURL = await info.webhookURL() + XCTAssertEqual(internalWebhookURL, internalURL?.appendingPathComponent("api/webhook/webhook_id1")) + + // Test when on external network - should return cloudhook URL + Current.connectivity.currentNetworkInfo = { + NetworkInfo(ssid: "coffee_shop", bssid: nil) + } + + let externalWebhookURL = await info.webhookURL() + XCTAssertEqual(externalWebhookURL, cloudhookURL) + } } From f0da63a785d84d5f041941ab06253a93aeeec605 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 29 Dec 2025 12:23:18 +0000 Subject: [PATCH 3/4] Fix spelling errors: Falback -> Fallback in ConnectionInfo.swift Co-authored-by: bgoncal <5808343+bgoncal@users.noreply.github.com> --- Sources/Shared/API/ConnectionInfo.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Sources/Shared/API/ConnectionInfo.swift b/Sources/Shared/API/ConnectionInfo.swift index cdad7ce7a2..59c188e7dd 100644 --- a/Sources/Shared/API/ConnectionInfo.swift +++ b/Sources/Shared/API/ConnectionInfo.swift @@ -241,13 +241,13 @@ public struct ConnectionInfo: Codable, Equatable { activeURLType = .external url = externalURL } else if let internalURL, [.lessSecure, .undefined].contains(connectionAccessSecurityLevel) { - // Falback to internal URL if no other URL is set + // Fallback to internal URL if no other URL is set // In case user opted to not check for home network or haven't made a decision yet // we allow usage of internal URL as fallback activeURLType = .internal url = internalURL } else if let internalURL, internalURL.scheme == "https" { - // Falback to internal URL if no other URL is set and internal URL is HTTPS + // Fallback to internal URL if no other URL is set and internal URL is HTTPS activeURLType = .internal url = internalURL } else { @@ -300,13 +300,13 @@ public struct ConnectionInfo: Codable, Equatable { activeURLType = .external url = externalURL } else if let internalURL, [.lessSecure, .undefined].contains(connectionAccessSecurityLevel) { - // Falback to internal URL if no other URL is set + // Fallback to internal URL if no other URL is set // In case user opted to not check for home network or haven't made a decision yet // we allow usage of internal URL as fallback activeURLType = .internal url = internalURL } else if let internalURL, internalURL.scheme == "https" { - // Falback to internal URL if no other URL is set and internal URL is HTTPS + // Fallback to internal URL if no other URL is set and internal URL is HTTPS activeURLType = .internal url = internalURL } else { From 0dff99c01dbb8e5444e32823fdc1ee532756a2ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Pantale=C3=A3o?= <5808343+bgoncal@users.noreply.github.com> Date: Tue, 6 Jan 2026 15:41:15 +0100 Subject: [PATCH 4/4] Lint --- Sources/Improv/ImprovDiscoverView.swift | 2 +- Sources/Shared/Environment/ConnectivityWrapper.swift | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Sources/Improv/ImprovDiscoverView.swift b/Sources/Improv/ImprovDiscoverView.swift index ff3e2c3c5e..fcdf9709d0 100644 --- a/Sources/Improv/ImprovDiscoverView.swift +++ b/Sources/Improv/ImprovDiscoverView.swift @@ -170,7 +170,7 @@ struct ImprovDiscoverView: View where Manager: ImprovManagerProtocol { Task { @MainActor in let networkInfo = await Current.connectivity.currentNetworkInfo() if let networkSSID = networkInfo.ssid { - self.ssid = networkSSID + ssid = networkSSID } } showWifiAlert = true diff --git a/Sources/Shared/Environment/ConnectivityWrapper.swift b/Sources/Shared/Environment/ConnectivityWrapper.swift index dda10ccc2f..2e25c78fd5 100644 --- a/Sources/Shared/Environment/ConnectivityWrapper.swift +++ b/Sources/Shared/Environment/ConnectivityWrapper.swift @@ -181,7 +181,9 @@ public class ConnectivityWrapper { #endif let bssid = hotspotNetwork?.bssid Current.Log - .verbose("Fetched network info - SSID: \(String(describing: ssid)), BSSID: \(String(describing: bssid))") + .verbose( + "Fetched network info - SSID: \(String(describing: ssid)), BSSID: \(String(describing: bssid))" + ) continuation.resume(returning: NetworkInfo(ssid: ssid, bssid: bssid)) } }