I found a way to trigger the prompt, receive a callback of the user’s selection, and detect if the user has previously allowed or denied the prompt if it already appeared.
To trigger the permission we use a service discovery API. When the user declines or previously declined we receive an error.
It doesn’t indicate if the permission was granted, so we also published a network service that returns success if the permission has been granted.
By combining the 2 into a single component, we can trigger the prompt and get an indication of approval or decline: Until we receive success from the network service or error from the service discovery we assume that the permission is still pending.
import Foundation
import Network
@available(iOS 14.0, *)
public class LocalNetworkAuthorization: NSObject {
private var browser: NWBrowser?
private var netService: NetService?
private var completion: ((Bool) -> Void)?
public func requestAuthorization(completion: @escaping (Bool) -> Void) {
self.completion = completion
// Create parameters, and allow browsing over peer-to-peer link.
let parameters = NWParameters()
parameters.includePeerToPeer = true
// Browse for a custom service type.
let browser = NWBrowser(for: .bonjour(type: "_bonjour._tcp", domain: nil), using: parameters)
self.browser = browser
browser.stateUpdateHandler = { newState in
switch newState {
case .failed(let error):
print(error.localizedDescription)
case .ready, .cancelled:
break
case let .waiting(error):
print("Local network permission has been denied: \(error)")
self.reset()
self.completion?(false)
default:
break
}
}
self.netService = NetService(domain: "local.", type:"_lnp._tcp.", name: "LocalNetworkPrivacy", port: 1100)
self.netService?.delegate = self
self.browser?.start(queue: .main)
self.netService?.publish()
}
private func reset() {
self.browser?.cancel()
self.browser = nil
self.netService?.stop()
self.netService = nil
}
}
@available(iOS 14.0, *)
extension LocalNetworkAuthorization : NetServiceDelegate {
public func netServiceDidPublish(_ sender: NetService) {
self.reset()
print("Local network permission has been granted")
completion?(true)
}
}
How to use:
- Add LocalNetworkAuthorization class to your project
- Open .plist file and add “_bonjour._tcp”, “_lnp._tcp.”, as a values under “Bonjour services”
- Call requestAuthorization() to trigger the prompt or get the authorization status if it already been approved/denied