Our application connects to a local WiFi network (using TCPClient) for data communication purposes.
But in iOS 14 the connection fails completely because two processes take place at the same time:
TCP client initialization
Current network permissions
So the connection to the local network is blocked until we reopen the application.
To avoid this, we're doing a hack: Pinging to a local IP address triggers the current network permissions (this is done in the OnActivated() method of AppDelegate).
The connection only works properly if it is connected to that particular network otherwise it fails.
Has anyone faced this issue before? I appreciate any suggestions from the community.
What actual method calls, excluding Bonjour, triggers the "would like to find and connect to devices on your local network" permission notification on iOS 14?
This is the screen shot from the WWDC session on this new permission. Which is only somewhat helpful as an overview. I'm more interested in figuring out what all method calls trigger this.
If you're using react native with a debug configuration, then you are including all the code responsible for communicating with your dev machine so you can probably ignore this message.
However it's best to check you have no other libs that require access too. To do this just build a Release version and see if the message persists.
In a nutshell, Bonjour. Its use is no longer "transparent". See https://developer.apple.com/videos/play/wwdc2020/10110/ for more information:
If your app interacts with devices using Bonjour or other local networking protocols, you must add support for local network privacy permissions in iOS 14.
Even an existing app is subject to this rule; the first attempt to use Bonjour triggers the authorization alert.
Apple (Eskimo on the Dev Forums) released a FAQ providing more details around this alert:
https://developer.apple.com/forums/thread/663858
Particularly, providing more info as to what triggers this alert is FAQ-2:
https://developer.apple.com/forums/thread/663874
What operations require local network access?
The general rule is that outgoing traffic to a local network address
requires that the user grant your app local network access. Common
scenarios include:
Making an outgoing TCP connection — yes
Listening for and accepting incoming TCP connections — no
Sending a UDP unicast — yes
Sending a UDP multicast — yes
Sending a UDP broadcast — yes
Receiving an incoming UDP unicast — no
Receiving an incoming UDP multicast — yes
Receiving an incoming UDP broadcast — yes
These TCP and UDP checks are done at the lowest levels of the system
and thus apply to all networking APIs. This includes Network
framework, BSD Sockets, NSStream, NSURLSession and WKWebView, and any
other protocols that you layer on top of those.
IMPORTANT Receiving an incoming UDP multicast or broadcast does not
currently require local network access but, because we hope to change
that in a future update, our advice right now is that you write your
code as if did (r. 69792887, 70017649).
Resolving link-local DNS names (those ending with local, per RFC 6762)
requires local network access. Again, this check applies to a wide
variety of APIs including <dns_sd.h>, <net_db.h>, Network framework,
NSStream, and NSURLSession.
Finally, all Bonjour operations require local network access:
Registering a service with Bonjour — yes
Browsing for Bonjour services — yes
Resolving a Bonjour service — yes
Again, these checks apply to all APIs that use Bonjour, including
<dns_sd.h>, Network framework, NSNetService, and Multipeer
Connectivity.
Note You must declare the Bonjour service types you use in your
Info.plist. See How do I map my Multipeer Connectivity service type to
an entry in the Bonjour services property? for details.
Bonjour-based services where you don’t see any details of the network
do not require local network access. These include:
AirPlay — no
Printing via UIKit — no
One of my apps was triggering this prompt unexpectedly in our internet multiplayer mode. We use RakNet for our networking (which is a C++ lib that uses BSD sockets to send/receive UDP) and I was able to track the problem to the RNS2_Berkley::BindShared function here.
After creating a UDP socket, RakNet tests health/validity of the socket by having it send a little test packet to itself. iOS 14 was flagging this send-to-self behaviour as communication on the local network. I'm not sure if this send-to-self behaviour is a common pattern in socket programming, or a particular quirk of RakNet. Frustratingly, the OS prompt didn't actually appear until later when the socket was used for real which made the issue very hard to track.
I think that this is a false-positive from the OS and raised it with Apple (FB8802121). I won't be holding my breath though so I've just disabled that RakNet behaviour for iOS and am hoping that it wasn't too important.
Edit: To more directly answer the original question: sendto is a method call that can trigger this prompt.
I get rejected from apple app review for this alert. I'm using GCDWebServer which creates an embedded http server in my app.
I think I should provide a message in info.plist to tell user what my app want to do. Before I didn't set the text string in it.
And I would like to update if this will pass the app review.
<key>NSLocalNetworkUsageDescription</key>
<string>xxx uses the local network to connect with devices around you.</string>
Regarding iOS 14: permission request: would like to find and connect to devices on your local network and after numerous deploys to my physical device, I have figured out what causes this in my case.
I have a Xamarin.Forms app which
calls localhost:xxxx to do some local logging while I develop
I use a product thats called LiveSharp that does local hot reloading for XAML AND C# code changes.
So Livesharp actually communicates with a server on my localhost as well.
After disabling both of these and a fresh clean install on my physical device, the permission request has GONE .. Yay
Note: I had to completely remove LiveSharp nuget packages from my project.
Also I tried to re-enable my localhost logging, and for some reason the permission request does not appear.. :headscratch
So: remove any localhost communication that happens in your app. Or at least put an if statement around it allowing it if set to true in appsettings
I also have a Xamarin app and I used the package LiveXaml. After removing it the message was gone.
I used GCDAsyncUdpSocket to send udp message to discover ssdp service, in iOS reported "No route to host" this error,but there is no problem in the simulator above can be found in service, is that how it happened? I searched a lot of information, but no discovery could help me.
I've run into the same thing. Of course without your source code we can't help you other than to provide vague guesses. I hope you've fixed it by now and if you recall what the problem actually was, please let us know.
Things to check :
Firewall settings on the host. I was trying to receive messages on my mac book and found that Firewall settings can block the port you chose. Firewall is under system preferences on the 3rd tab.
Use apples Reachability class to make sure you've got an active WIFI/Cell connection to the internet. (here : https://developer.apple.com/library/ios/samplecode/Reachability/Listings/Reachability_Reachability_h.html#//apple_ref/doc/uid/DTS40007324-Reachability_Reachability_h-DontLinkElementID_7 )
You can also use other functions in the Reachability class to let you know if the host is reachable before even bothering to open up a socket.
If the host is your mac and the simulator is on the mac, there isn't much of actual network traffic and then when you run on your phone you are actually using real networking. Be aware of, depending on your networking situation, you may need the external IP address of your host (vs the internal network WIFI address e.g. 192.168.1.4 )
Some people have reported a bug where UDP stops working and you get no route to host messages but for some reason turning on and off airplane mode fixes it. Maybe check out their solution (using keep alive messages ever 30 seconds or so to prevent power management from turning off the cell connection). Here is an example : intermittent "No Route to Host" on iOS, flight mode off then on fixes
In case you are developing an App Clip for iOS app, be aware that:
a) Background Session is not supported
b) Multipath is not supported. Setting `multipathServiceType = .handover` on `URLSessionConfiguration` will cause all requests failure due to `No route to host`
I created an application using bonjour and I am able to send files from one device to another. But the question is: I am not able to discover the devices on the LAN without running both the applications on the device. Do I need to run the application using bonjour to get it detected using bonjour.
Yes you do. Running the application registers the appropriate entries into the iOS multicast DNS service. Once you shut the app down I expect it removes itself from the multicast DNS registry (which it is correct to do, because it is no longer available), so you can't find it from other devices.
EDIT: (Very roughly) Bonjour is multicast DNS. The Bonjour service runs a multicast DNS server. When your application starts up it communicates with the local multicast DNS server and creates a number of entries that identify the service it is making available, the ports it is available on and other relevant attributes. It also registers itself as interested in learning about any other network device that is running the service.
The local multicast DNS server makes announcements that signal to any one else listening on the network that a new service is available. Your app (on a different machine) is notified by the Bonjour service that another client has appeared, and that is more or less how the magic is done. Longer multicast DNS writeups are all around: Google is your friend.
I am doing an InternetConnect (Wininet) to an FTP server that happens to be running on an iPhone. When the user is on a normal WiFi network it works fine for him. When he has an ad hoc network with his iPhone he gets an ERROR_INTERNET_TIMEOUT. I presume this is some kind of routing problem. I am curious as to why this gets ERROR_INTERNET_TIMEOUT and not ERROR_INTERNET_CANNOT_CONNECT. Most users, if they are blocked by, for example, a firewall, will get ERROR_INTERNET_CANNOT_CONNECT.
I don't understand enough about low-level TCP/IP to understand what kind of situation would cause a timeout error instead of a connect error. I'm really more intellectually curious in understanding this than I am in actually solving the user's problem. ;-) Can anyone explain what is happening with the network packets (the more detailed the better)?
edit:
note that, as far as I know, the user doesn't have an outgoing firewall enabled, it's not a firewall issue. I think it's some kind of routing issue. I have seen similar issues when a user is connected a VPN and their routing is set up incorrectly and all packets go to their work instead of the iPhone. I want to know what's going on with the packets in this situation: the socket connects but at the next step (whatever that is) they can't communicate.
Firewalls these days choose to not respond at all to packets that they deem suspicious, this is to prevent port scanners from detecting that there is a machine at the IP. So that could be what is happening in your case, the firewall may simply be dropping the packet and causing a timeout rather than a failure to connect error.