Skip to content

Instantly share code, notes, and snippets.

@doozMen
Created February 25, 2022 15:44
Show Gist options
  • Save doozMen/0b5fc54c765bccb7c13792caa4eaa51c to your computer and use it in GitHub Desktop.
Save doozMen/0b5fc54c765bccb7c13792caa4eaa51c to your computer and use it in GitHub Desktop.
Uses bonjour networking to relialby check if user has granted local network access with async await as of iOS14
import Foundation
import Network
/// Uses bonjour networking to relialby check if user has granted local network access
/// 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
/// about the author: https://stackoverflow.com/a/67758105/705761
public class LocalNetworkAuthorization: NSObject {
private var browser: NWBrowser?
private var netService: NetService?
private var completion: ((Bool) -> Void)?
public func requestAuthorization() async -> Bool {
return await withCheckedContinuation { continuation in
requestAuthorization() { result in
continuation.resume(returning: result)
}
}
}
private 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
}
}
extension LocalNetworkAuthorization : NetServiceDelegate {
public func netServiceDidPublish(_ sender: NetService) {
self.reset()
print("Local network permission has been granted")
completion?(true)
}
}
@Rytiggy
Copy link

Rytiggy commented Nov 2, 2022

netServiceDidPublish never gets called, could you help me understand why?

@theoks
Copy link

theoks commented Nov 6, 2022

@Rytiggy you need to schedule the netService on a run loop (I did it on the main runloop)

netService?.schedule(in: .main, forMode: .common)

@matiasbzurovski
Copy link

matiasbzurovski commented Oct 2, 2024

@doozMen is this still working for you on iOS 18?

update: I was missing the NSLocalNetworkUsageDescription key on Info.plist, which for some reason wasn't necessary for iOS 17 and below. Seems it is required on iOS 18.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment