Detect a captive portal on iOS - ios

So I'm able to detect whether or not the user has basic internet connection fine using Apple's reachability class. However, when I try to detect whether or not they are connected to a Wi-Fi network that utilizes a captive portal, I get back NetworkStatusReachableViaWiFi, which makes sense. However, this will also be returned if the user is simply using a WiFi connection.
I need to be able to detect both no internet connection and the captive portal situation, as that is effectively no internet.
Are there any reliable API's that can accomplish this task? Based off this article, http://blog.erratasec.com/2010/09/apples-secret-wispr-request.html#.VxkmrJMrIy5, Apple pings an internal address when you connect to WiFi to check for a captive portal. I'd prefer to avoid pinging any outside networks, however if I must, does anyone know how I could ping the same Apple address and use the response to tell if my user has a captive portal up?
Edit: I've come across NSURLConnectionDelegate and its method connection:willSendRequestForAuthenticationChallenge:. I think this method may be able to do what I need, I can send a basic request to www.google.com and make myself the delegate, and if this method gets hit do what I need to do. I think I would then be able to call cancelAuthenticanChallenge:
Has anyone ever used this method before to detect a captive portal? How did it work?

Related

how to disable wifi assist without user interaction

I have couple of URLs that has to be called(programatically) through wifi not with mobile data.
As WIFI ASSIST is on , whenever the wifi is weak ,packets get transferred through Mobile data.
I would like to stop this from happening.
As far as I have researched, there is no API to toggle wifi assist switch on and off programatically
I can find if the user has mobile data and wifi on with the help of Reachability Class I believe and I can alert the user to keep wifi assist off but this is a very bad user experience.
so I decided to look if its possible to be done with the help of iOS mobile configuration file.
But I couldn't find any keys related with wifi-assist in Apple configuration profile reference.
so I am wondering , is it possible to force wifi to be used for certain URLs.
I remember this is possible with VPN ON DEMAND we can have certain domains to be accessed via VPN.
I am wondering if same is possible for wifi as well through configuration profile
Any suggestions are welcome.
As others have mentioned, there is no way to do manipulate this setting programmatically in iOS. This is not really what you are asking, as you seem to already know the answer to this is "No".
You are asking about the configuration profile, so I am assuming these are managed devices. Unfortunately, there is no configuration profile payload I am aware of that forces the managed devices to disable Wi-Fi Assist.
Your intent, however, is a bit different than what is being asked, I believe. I think you basically have an app that communicates with a resource that is only accessible via the Wi-Fi network (likely a corporate Wi-Fi network). If the app tries to connect to the resource while on cellular, it will not be able to connect. In some cases, when the Wi-Fi signal is weak, the device tries to be helpful and switches to cellular, causing issues with the app. If we could figure out a way to force iOS to not take advantage of Wi-Fi Assist when your app is running, you would be in good shape.
If you can install this app as a managed app, there is a way to identify that the app should only be allowed to run on a Wi-Fi connection. Setting the network usage rules AllowCellularData to false should do this (see this for more details). The thing I am not sure of with this solution, is whether this simply causes the connections to fail when Wi-Fi Assist is on and active, or if it makes iOS prefer to not use Wi-Fi assist when the app is running because it cannot connect over cellular. So I think you can tell an app to only connect over WiFi, but it doesn't really give you a better solution to your user experience problem. The only think it really buys you is that your app connection won't ever try to connect when connected to cellular. There is a chance, however, if you change this value to false for your app bundle ID, it will prevent Wi-Fi Assist from enabling when your app is running. I don't have access to MDM to try it out, but you could test and see.
Ultimately, given that this is probably a corporate device situation, I think you are going to have to address this through user training. The good news is that this is a one-time step. Sure, users may have slight degradation of network performance when Wi-Fi signal is weak but cell signal is strong. This does not matter as much if these are corporate devices where the corporate apps will mostly work only on the company's Wi-Fi network.
Another solution is what you mentioned, basically using on-demand VPN to provide a connection to the internal resources. This is additional infrastructure work, and you already mentioned it, so I'm not sure if it is even an option.
Obviously, the other solution would be to expose the network resources through your firewall, which could allow you to access it over cellular. I'm suspecting this is not possible due to security constraints.
Unfortunately, there are not a lot of good options in this space. However, have hope that there is some way to do it, as Sonos appears to have done something to
allow their app to avoid switching to WiFi Assist while streaming to a local network resource: https://sonos.custhelp.com/app/answers/detail/a_id/4257/~/wi-fi-assist-and-sonos
I wonder if you could have your app open a streaming audio connection to a fixed local network resource, which would cause it to use Wi-Fi. It's a pretty crazy hack, but with a low enough bitrate audio file streaming, it might do what you need while not eating up too much of the network throughput.
Per Apple's notes on Wi-Fi Assist:
Wi-Fi Assist won't automatically switch to cellular if you're data
roaming.
Wi-Fi Assist only works when you have apps running in the
foreground and doesn't activate with background downloading of
content.
Wi-Fi Assist doesn’t activate with some third-party apps
that stream audio or video, or download attachments, like an email
app, as they might use large amounts of data.
Of course the other possible solution that you could consider is improving your Wi-Fi coverage to that the signal doesn't get bad enough for Wi-Fi Assist to be needed. I know this may not be feasible, but wanted to put it out there.
Good luck with this!
There is no public API that allows you to enable/disable "Wi-Fi Assist", and even if you find a way to do it your app will be rejected.
No you can not enable or disable WiFi by programmatically and there is no API for this.

Data on the iPhone?

I am developing an app that requires the user to be able to request a server and get back some JSON Data. Here are my question and my reasoning behind it:
1) Would this require the user to have "Data" on their cell phone plan?
Dealing with Android, I have figured out that when I do not have "Data" on my cellphone plan, that I can not access the internet, but I am allowed to use twitter. Instagram, however does not load when I do not have "Data".
When I do have Data on my cellphone plan, I am allowed to go onto the internet, use twitter, and use Instagram.
Will my App act as twitter or Instagram in this case? and how do I make the app work without a Data plan?
If your app needs to access the Internet (which is does to reach the server) then the user must either be connected via WiFi or if connected via cellular, the user must have a data plan.
A cellular connection with no data plan will prevent your app from accessing the Internet.
You need to have some sort of connection to the Internet to be able to access the internet.
You don't need a data plan, if your device is connected over wifi (such as iPod touches) then that will allow a connection to the internet.
The apps you mention do run on a device without an internet connection because they handle the case where there is not an internet connection sensibly, and although they load, they don't crash because of a lack of connection.
If you want to do the same thing, then you need to have a way of handling this too.

Reachability - Check if valid with connection on public Wi-Fi

I am currently using an adapted reachabilty framework based on Apple's sample code.
The framework works fine, however it provides false postives.
If the user is attached to a wifi network where they are required to login before having a valid connection, the framework shows as an active connection when in fact it isn't.
An example of this is Starbucks' wifi where you must provide an email address before you get online.
Is there a way around this without pinging a certain address?
Currently I am using the reachabilityWithHostname function
Thanks
Daniel
Update as provided by the link below i see this is a limitation of the framework. Are others finding away to alert the user of this?
If your computer is connected to a Wi-Fi access point, but that access point's internet connection is down, reachability will tell you that yes, you have a network connection
Check out this link
Networking is playing an ever more important role in application
development, and Apple's reachability API is a valuable tool in making
network-centric apps play nicely with varying real-world conditions.
Today I'm going to give an overview of the reachability API, what it
does, and how to use it.
This should help you.

iOS how to connect specific WiFi SSID with minimum user interaction

I have to iphone applications that they use two different networks. Changing network setting for each application is not user friendly. I want to do such thing as follows,
When application starts, it checks the availability of particular network (SSID) and popup a message to the user to permit to connect. Once user click on "OK" they it connect to that particular network.
Anybody has similar experience ?
How can I connect to given SSID using objectiveC ?
I've been reading for a solution to achieve app controlled networking, but it seems impossible without the use of Apple80211 private API.
The best i think you can do is with CaptiveNetwork.
With this you can register a list of SSID's for your device and it will suppress web sheet.
From the doc:
By calling the CNSetSupportedSSIDs function, an application can register a list of wireless network SSIDs with Captive Network Support, thereby assuming responsibility for authenticating with those networks. Typically when a user joins a captive network, Captive Network Support provides a web sheet that allows the user to authenticate with the network. If an application has registered the SSID of the captive network, however, the web sheet is suppressed, and the user can complete authentication in the appropriate application.

Using CaptiveNetwork to authenticate wifi network

I am trying to use the CaptiveNetwork api to have my app authenticate with known wifi networks. I am able to register my app with CNSetSupportedSSIDs, which prevents the os from displaying a web sheet. However, there is little documentation, indeed little information anywhere, it seems, on how my app is notified once a connection is established to a registered network. Perhaps I am missing something?
If anyone has any advice on where to look, or knows of apps that perform wifi authentication, so I can examine their use-case, or spots something that I've obviously missed, do let me know.
Thanks.

Resources