So I'm working on an IoT app, where I need to configure the hardware by connecting to its WiFi. If I use AFNetworking or URLSession to make the call, they fail with this error message.
"The Internet connection appears to be offline."
I need a way to make the API call to the local Wifi of the hardware by overriding the Reachability check. I'm sure there must be a way to do so, but I can't seem to come across something like that.
Reachability tells you if a certain host is reachable via Wifi. reachability.connection == .wifi test should be enough for that.
However, to know the reachability via that utility, you must know your host's IP within the wifi network, not internet.
What are all IP addresses that your host exposes? They will each belong to a network - internet, wifi, LAN and such.
What you probably need is the correct network utility to tell you that, for example, arp.
Related
I'd like to find out if a Wi-Fi has internet connection or not. Sometimes our devices are connected with Wi-Fi, but the Wi-Fi doesn't have an internet connection.
NWPathMonitor or Connectivity thirdparty. I tried it, but it is not fool proof.
I know I can write a method to ping a server, but this is a very ineffective and costly affair.
Any ideas?
The only way to know for sure if a network has an Internet connection is to try and make a connection to the Internet. There is nothing on the device that you can query to get the answer.
Even if there were it would have to resort to polling/pinging since connectivity can change at any instant.
A WiFi connection can transition from no-Internet to Internet when the user completes a Hotspot login form. A WiFi connection can transition from Internet to no-Internet if the upstream Internet connection fails in some way. A WiFi connection may be connected to the Internet but not be able to communicate with the specific host your app needs due to a routing failure or some other issue.
For all of these reasons Apple actively discourages "pre flight" checks. Even if a check passes a network operation can still fail due to a change in network status that occurred a microsecond later. It is also unnecessary overhead as it is generally a safe assumption that most devices have some sort of Internet connection most of the time, particularly if the device is an iPhone.
You need to handle errors anyway. Just try the operation and see what happens. If there is no network connection it will fail pretty quickly.
If you want to provide more feedback to the user then you could begin actively checking Internet connectivity with exponential back off in response to a connection error.
That way your app isn't constantly "pinging".
You can also use the error to start a process that uses SCNetworkReachability to check connectivity for you. Rather than using that framework directly, particularly if you are writing in Swift, you might like to use something that wraps it and makes it more accessible like Ashley Mills' Reachability.swift
When I checked the apple Reachability class, it does return true even though the connected network doesn't have an active internet connection. So I'm having few doubts here -
Why is Reachability class made to throw YES if the packet can leave the local device even though it doesn't ensure it is delivered at the endpoint? Are there any special reasons to limit the ability?
Reachability has reachabilityWithHostName method still, YES will be thrown by class even if we add familiar hostname in the same network. If it doesn't ensure endpoint packet delivery why they provided this method?
Is there any other way to check whether there is an active internet connection in the connected network other than Reachability? Do we need to add our custom APIs or logic to tackle this thing?
I did connect an android phone to the same network, it instantaneously notified me the connection has no internet connection.
I have implemented the Reachability class successfully. However, in my app I'd like to notify the user when a connection to our server only can't be made (but the regular internet is working).
Reachability is reporting that the iPhone successfully can reach a hostname, when I thought it might return an error b/c I was not on an authenticated network:
The hostname I use is 'foreverfreebank.com'. Again, Reachability's hostname check reports success.
However,
--to access this site via the web, one needs to use https in the browser, i.e. 'https://foreverfreebank.com'
Does Reachability account for this case? Or does the protocol part ('https') not count for anything?
I am confused b/c if you type in in the Firefox browser 'http://foreverfreebank.com', (leaving out the 's'), you get an error. That is, http:// should NOT be reachable.
Similarly, I have another site that requires VPN access to get to the site: http://checksforever.com. When I try the hostname: 'checksforever.com', Reachability reports success even though I am not on VPN.
Is this expected behavior? Thanks
You need to check reachability on a specific port (443 in this case). This is something that is not supported by Reachability API. Refer to this question, or this.
Relevant part from documentation:
A remote host is considered reachable when a data packet, sent by an
application into the network stack, can leave the local device.
Reachability does not guarantee that the data packet will actually be
received by the host.
So, basically Reachability doesn't test if the remote host accepts incoming connections. For this purpose, I suspect you'll need to open an URL connection and wait for time out/other errors.
I want to use a messaging protocol that works fine over 3G, but not over some corporate firewalls. How can my app force the use of the cellular network when it fails to connect over WiFi even in the case that the WiFi network is reachable?
EDIT: After reading through the implementation of the Reachability class I remain unsure whether the two are indeed mutually exclusive. It could well be possible to discover both interfaces via gethostbyname(), which I might try just to see what comes out.
Use getifaddrs to enumerate the network interfaces. Look for ifa_name that starts with "pdp." This will be the cellular interface (e.g., pdp_ip0). Test (ifa_flags & IFF_UP) to make sure the interface is up, and get the IP address from ifa_addr. Then use bind() to bind your socket to that address.
Not sure how you activate the cellular interface if it is not already up. Normally, I just make a high level http call to get iOS to wake up the network, but not sure under what conditions the cellular service becomes active when wifi is also available. I suspect it is usually there as a fallback to the wifi.
http://iphonedevsdk.com/discussion/comment/120957
From the looks of that thread, it seems like its impossible. Your best bet may be to try using the protocol, and saying something like "please disconnect from wifi and retry" if it doesn't work.
This thread says just about the same thing:
how to programatically start 3g connection on iphone?
You can use the Reachability class which apple wrote in order to test whether the network connection is currently over 3G or WiFi, and even to check if a specific resource is available on the network.
You can use any of the socket library to force to use cellular. Find the cellular interface from getifaddrs, pass the interface to the socket function, socket bind will happen with cellular. e.g. CocoaAsyncSocket
I am working on a web application for iOS that is going to be accesed from a local webserver in a network that has NO internet connectivity at all.
My problem is that everytime an iOS device is locked, it disconnects from the WiFi network, so when the device is unlocked again, it has to reconnect. Part of that reconnection process is determining if there is Internet connection (which there isn't). Until the process is not finished iOS does not allow any DNS resolution (so if I write http://10.0.0.1 it will go there, but not if I request http://something.local.com).
Since we control that network, we want to know how to does iOS verifies Internet connectivity so that we can fake the responses it expects.
I don't know if it's possible to resolve DNS without an internet connection on iOS, but if that's the case, that would be a way better solution since you don't need to mess with your router settings. Use my solution only if it really isn't possible with only code.
I'll suggest you to follow this guide: http://blog.jerodsanto.net/2009/06/sniff-your-iphones-network-traffic to check which actions your iPhone executes to detect an internet connection.
Using this information you could forward the is-there-internet-requests on your router to a local server which fakes the there-is-internet-responses.
This assumes Apple really uses an external server to detect this, which I'm not sure about. But it wouldn't hurt to give it a try!
Have you looked at the Reachability Class? You don't have to use the reachabilityForInternetConnection method, which checks if a default route is available. You can use the reachabilityWithAddress: method and check if your server is reachable.