Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS 14 How to trigger Local Network dialog and check user answer?

I've seen this Q/A What triggers, but it's not what I want. I also read this Network privacy permission check, but there is no answer. I also search for any methods or classes which can help me here: Network, but no luck again.

There is a new dialog for the Local Network authorization, where user can Allow/Don't Allow "to find and connect to devices on your local network".

enter image description here

But I'm struggling to find any API for how to trigger this popup and how to check is access granted or not(for example in AVCapture, I can check the authorization status for AVMediaType).

Thank you!

like image 611
vpoltave Avatar asked Sep 17 '20 14:09

vpoltave


People also ask

How do I check network permissions on iPhone?

To do so, head to Settings > Privacy > Local Network on your iPhone. Any app that has requested permission to access your local network will appear here. Apps with a green switch have access to your local network, while apps with a grayed out switch do not.


3 Answers

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:

  1. Add LocalNetworkAuthorization class to your project
  2. Open .plist file and add "_bonjour._tcp", "_lnp._tcp.", as a values under "Bonjour services"
  3. Call requestAuthorization() to trigger the prompt or get the authorization status if it already been approved/denied
like image 192
Tal Sahar Avatar answered Oct 14 '22 00:10

Tal Sahar


I did open DTS request and had conversion with Apple support team. Here is some important parts which I included below.

How to check is access granted or not

From support team:

For know, there is no such an API to check user permission.

From support team:

If the user declines, the connection fails. Exactly how it fails depends on the network API you’re using and how you use that API.

  • By default the connection will fail with NSURLErrorNotConnectedToInternet.
  • If you set waitsForConnectivity on the session configuration, the request will wait for things to improve. In that case you’ll receive the -URLSession:taskIsWaitingForConnectivity: delegate callback to tell you about this. If the user changes their mind and enables local network access, the connection will then go through.

Unfortunately there’s no direct way to determine if this behaviour is the result of a local network privacy restriction or some other networking failure.


How to trigger this popup

From support team:

the problem here is that the local network permission alert is triggered by outgoing traffic and you do not generate any outgoing traffic. The only way around this is to generate some dummy outgoing traffic in order to trigger this alert.

I’ve seen other developers in this situation and the absence of a direct API to trigger the local network permission alert is quite annoying. I encourage you to file a bug about this.

I’ve been discussing this issue with the local network privacy team and our current advice for apps in your situation — that is, apps that want to receive broadcasts but don’t send any local network traffic — is as follows:

  • The system should do a better job of handling this. We’re tracking that as a bug rdar://problem/67975514. This isn’t fixed in the current iOS 14.2b1 release but you should continue to test with iOS beta seeds as they are released.

  • In the meantime you can force the local network privacy alert to show by sending a message. We specifically recommend that you send a message that’s roughly equivalent to the message you’re trying to receive, so in your case that means sending an IPv4 UDP broadcast.

UPDATE

For iOS 14.2 - prompt is received for inbound traffic FIXED. Because of this you don't need below example for simulating traffic to triggering prompt.


Here is class for dummy outgoing traffic simulation: example

That traffic will never leave the iOS device and thus, even if the interface is asleep, it won’t wake it up. And even if it did wake up the interface, the cost of that is trivial because you’re not doing it over and over again, just once in order to trigger the local network privacy alert.

like image 21
vpoltave Avatar answered Oct 14 '22 00:10

vpoltave


In my case it was accessing this variable for some internal device statistics:

ProcessInfo.processInfo.hostName

Accessing this variable caused the alert to appear. If it doesn't cover your case perhaps you can search source code for some references around the local network/host.

like image 33
Roval Avatar answered Oct 14 '22 00:10

Roval