In today's world, the availability of public Wi-Fi in public places is taken for granted. Visiting cafes, shopping centers, hotels, airports, leisure parks and many other places, we immediately look for the cherished signal without a password. And this is not easy, because, firstly, there may be several points in the list, and secondly, free Wi-Fi can be password-protected, so the only way out is to catch an employee who can point to the correct network and call the password. But even after that it happens that nothing works. The user must guess that he needs to open the browser (and also the question of which page should be loaded) and take additional actions (log in, view the advertisement, confirm the user agreement) before being given full access to the network.
However, now many popular places offer applications that facilitate connection to free points. I am sure that each of us can easily recall a couple of similar examples, so I’ll manage without names and advertisements. Moreover, the discussion below will deal with another solution to this problem - we will write our own Network Helper! With this approach, you no longer have to guess which grid to connect to. Even additional actions to gain access to the network can be performed in a convenient native UI and much faster than in a browser.
It's simple. Enough to use technology NEHotspotHelper, which became available to developers since the release of iOS 9. The main task of this tool is the classification of Wi-Fi-networks and user authorization in them. NEHotspotHelper is part of the NetworkExtension framework. Below you will find the scheme included in it at the time of the release of iOS 11 tools:

')
The main documentation is here:
Hotspot Network Subsystem Programming Guide . In addition, no information on the network could not be found, in connection with which I am writing this article. I hope my material will help fill in the documentation gaps and explain how to implement your own Hotspot Helper. An example of using this technology can be found on
GitHub .
Principle of operation
At the heart of Hotspot Helper's work is the Wi-Fi connection state machine and the commands sent by the Helper system, the processing of which transfers the machine from one state to another. The following is a rough outline of the states that Apple itself provides in its documentation:

At first, such a complex picture scares, but do not worry - in practice, everything is quite simple.
It is enough to understand the following:
- When you first connect to the network after the device is rebooted, a Helper is selected to serve it ( Evaluate ).
- As soon as the selection is made, authorization is launched on the network using the selected Hotspot Helper ( Authenticating ).
- If the UI needs to display the UI during the authorization process, Hotspot Helper explicitly requests it ( PresentingUI ). If there is no such need, Helper in the background performs the necessary actions to authorize the user on the network ( Authenticated ).
- Periodically, the system awakens the selected Hotspot Helper to support the session, if necessary ( Maintain ).
- While the session is being supported, the Helper can do nothing, and can request re-authorization or provoke a reconnection to the network.
The only non-obvious point is that after the first connection to the network, the system caches the Hotspot Helper selected for it, so the next time you connect, the machine switches to the Maintain state, bypassing all the previous ones.
Hotspot Helper participates in authorizing a user in a Wi-Fi network at all stages - from displaying the list of networks and connecting to the selected one, to authorization support and independent logout. At the same time, to establish the connection, Hotspot Helper processes all the required commands, thanks to which the system ensures its launch in any situation (even if the user forcibly turns off the application (which would ignore
silent-push notifications). After all, the operation of the entire device depends on it. The whole process is transparent to the user, so the most common scenario is to launch the application in the background.
So, we repeat: to install a Wi-Fi connection, Hotspot Helper must process all the required commands.
In other words, the device will not consider itself connected to the network until StateMachine transitions to the Authenticated state . This is despite the fact that Hotspot Helper will begin to see the connection when it
receives the Evaluate command. This moment is perfectly tracked by means of Reachability, which we will talk about below.
It must be said that NEHotspotHelper is not a separate target, as is often the case with other extension, but the main application, registered as Hotspot Helper. This means that as soon as he needs to process a command, the main application will be launched with all the ensuing consequences. That is, the application will be able to execute any code, but when launched in the background, it can deploy full-scale actions, as if initiated by the user. However, such an activity will only mean wasting resources, therefore,
what is happening in the background should be monitored .
Preliminary preparation
To register an application as Hotspot Helper, you need to get permission from Apple. To do this, the Team Agent must follow the
link and complete the questionnaire.
At the time of this writing, it looks like this:
If all goes well, then when you create a provisioning profile on
https://developer.apple.com, you will be able to choose for it a
entitlement with the key
com.apple.developer.networking.HotspotHelper , which gives the right to use all the buns.

In addition, it is necessary to include the
network-authentication string in the
Background Mode Capability project in
Info.plist in the
UIBackModes section. After that, you can proceed to the most interesting - coding.
check in
In order for the application to become Hotspot Helper, it must be registered in the system. To do this, call the following method:
class NEHotspotHelper class func register(options: [String : NSObject]? = nil, queue: DispatchQueue, handler: @escaping NetworkExtension.NEHotspotHelperHandler) -> Bool
The method takes three parameters:
Register Helper exactly once at each launch. A repeated call in the same run does nothing and returns
false . It is important to note that until the re-registration is completed, the application will not receive the command for which it was processed by the system.
There is no way to cancel registration. You can only stop registering the block, then the application will not handle the connection in any way, but it will still run -
more here .
In addition, unlike many other functions of the system (such as a photo gallery, calendar and even notifications), Wi-Fi connection processing by means of Hotspot Helper does not require any permissions from the user and is transparent to him (he simply does not encounter such concepts) .
Command processing
A command is an object of the NEHotspotHelperCommand class, containing the type and data set characteristic for each command (network or list of networks, if this implies a command).
After processing each of the commands, create the NEHotspotHelperResponse with the result of execution and a data set, which also depends on the specific command.
The NEHotspotHelperResponse object is created by calling on the received command of this method:
func createResponse(_ result: NEHotspotHelperResult) -> NEHotspotHelperResponse
In addition, using the command object allows you to establish a
TCP or
UDP connection based on the network to which the command belongs, by calling the appropriate methods:
func createTCPConnection(_ endpoint: NWEndpoint) -> NWTCPConnection func createUDPSession(_ endpoint: NWEndpoint) -> NWUDPSession
For higher-level communication with the server, you can create NSURLRequest. By attaching a command to it, Hotspot Helper gets the opportunity to interact with the server in conditions when the device does not see the Wi-Fi connection. The connection thus established can be used for authorization “in its own way”. IYKWIM
func bind(to command: NEHotspotHelperCommand)
Below we will look at every command that Hotspot Helper can receive in the order corresponding to the basic network connection scenario. Most of the commands are named like the State Machine states, under which they are called.
Officially, each team is given
no more than 45 seconds to complete (however, if you look at the available time in the background, you can see the figure of 60 seconds). After that, the team is considered unprocessed, and the work of Hotspot Helper is suspended. This restriction is necessary to eliminate unnecessary delays when connecting to the network, because until the command is processed, the user will not see the coveted Wi-Fi icon in the Status Bar. It should be understood that if the system has several Hotspot Helper, which process the same network, the fastest one will be selected (more on this below).
NEHotspotHelperCommandType. filterScanList
This is a special command that, unlike the others, is not tied to any of the States StateMachine states and can be called at any time. The command is invoked on all Hotspot Helper, known to the system,
every 5 seconds . It happens all the time while the user is on the list of Wi-Fi-networks in the system Settings.app.
The team serves a single purpose - to demonstrate to the user which of the networks Hotspot Helper processes. For this command contains a list of available networks in the appropriate field:
var networkList: [NEHotspotNetwork]? { get }
This is the same list that the user sees. At the same time, the list of networks may change with each new command call.
It is assumed that Hotspot Helper should analyze the list of networks and, in response to the command, return those that it is ready to serve. An empty array in the response will mean that the networks available for service by this Helper are not listed.
Hide for a network user from the list does not work.Those networks in the list that Hotspot Helper returned in response to this command will receive a signature. It will correspond to the value that was transmitted when Hotspot Helper was last registered as an option kNEHotspotHelperOptionDisplayName. Signature value can be only one. It is set during registration and cannot be changed until the next registration (and this happens after the application is restarted), so, alas, it will not work to sign networks differently.
It is important to note that in addition to transmitting the network itself, in response,
it needs to set a password if it is protected by it . Without this, the signature will not appear. If the password is set, then besides the appearance of the signature, the user will not need to enter the password himself. I must say, this is the only moment when you can set a password for the network. If you do not set it now, then the user will have to do it.
As a result, the command should be processed as follows:
let network = <A network from command.networkList> network.setPassword("PASSWORD") let response = command.createResponse(.success) response.setNetworkList([network]) response.deliver()
As a result, the user will see something like this:
It should be understood that the filterScanList command entirely serves to demonstrate the list of networks to the user and does not affect the rest of the network connection processing. If, in response to the Hotspot Helper command, it did not return any networks, it will still be asked to process the connection to any of them using the commands described below.
An interesting fact: if you delete the application, the signatures in the list of networks will be saved until the device is restarted.
NEHotspotHelperCommandType. evaluate
This command is called when you first connect to the network on all Hotspot Helper, known to the system.
Note: during subsequent connections, evaluate will not be called, immediately follow maintain on that Hotspot Helper, which was selected during the evaluate process.
The purpose of this command is to first identify the most suitable for processing connection to the selected Hotspot Helper network. To do this, along with the Hotspot Helper team, it also receives data via the network to which it is connected:
var network: NEHotspotNetwork? { get }
The network contains a number of properties, but during the processing of the evaluate command, only the following values are
// var ssid: String { get } var bssid: String { get } // 0.0 1.0 (, , ) var signalStrength: Double { get } // var isSecure: Bool { get } // , , // var didAutoJoin: Bool { get }
After receiving this information, Hotspot Helper should analyze the network in any way (starting from the local table and ending with a request to the server) and set the network to an appropriate level of
confidence :
// Helper , . case none // Helper , , *. case low // Helper , . case high
* In this case, they can provide an opportunity to authorize the user, however, if the Helper process understands that it is incompatible with this network, it will be able to refuse to work with it, and the StateMachine will again return to the evaluate state, and the Helper will be added to the exclusion list this network.It is important to note: Apple strongly makes it clear that confidence should be chosen carefully and you should not mindlessly set all high (and even low) networks, as this directly affects the UX of the entire system.
As a result, the command should be processed as follows:
let network = command.network // confidence... network.setConfidence(<Appropriate level of confidence>) let response = command.createResponse(.success) response.setNetwork(network) response.deliver()
It takes
45 seconds to process a command, and it makes sense to try to do it as quickly as possible. Because, as soon as the system receives the first response with high confidence, the processing of the command is terminated. Then the responded Hotspot Helper is selected for further processing of the connection on the network, and all the others stop their work and go into the suspended state.
NEHotspotHelperCommandType. authenticate
The authenticate command is invoked on the most appropriate Hotspot Helper based on the results of the evaluate command.
The purpose of this command is to perform all the actions necessary to provide the user with full access to the selected Wi-Fi network. To do this, along with the Hotspot Helper team, it also receives data via the network to which it is connected:
var network: NEHotspotNetwork? { get }
The processing of this command is the main essence of the work of Hotspot Helper. At this stage, the only barrier between the user and the access to the network is Hotspot Helper, and he must decide in any way available to the user whether or not to allow the user access.
There are
45 seconds to process the command, after which it is necessary to return a response with one of the following results:
.success - authorization completed successfully. Access to the network is fully open. StateMachine enters the authenticated state.
.unsupportedNetwork - this network is not supported Helper: incorrect network analysis was performed at the evaluate stage. StateMachine returns to the evaluate stage, and Helper is added to the exceptions for this network. This can happen, for example, if the Helper returned low confidence for this network at the stage of evaluate, and now it is convinced that it cannot cope.
.uiRequired - user interaction required. This result is returned if any additional data is required for authorization. However, not everything is so simple: the
UI does not seem to show itself when this result is returned .
It works like this: Hotspot Helper generates a UILocalNotification, through which it informs the user about the need for additional interaction. If the user ignores it, nothing else happens. After receiving the result of processing, StateMachine enters the presentingUI state and remains there until authorization is complete or disconnected from the network.
.temporaryFailure is a fixable error. For example, a network error occurred during authorization. StateMachine enters the failure state, the device is disconnected from the selected network.
.failure (or any other result, as well as its absence) is a fatal error. Something went completely wrong, and the connection cannot be processed: for example, the authorization protocol on the server side has changed, and the client is not ready for this. StateMachine enters the failure state, the device is disconnected from the selected network. Additionally, unlike temporaryFailure,
the auto-join function is disabled for such a network .
As a result, the command should be processed as follows:
let network = command.network // // UILocalNotification (.uiRequired) command.createResponse(<Command result>).deliver()
NEHotspotHelperCommandType. presentUI
This command is invoked on the selected Hotspot Helper in case it returns the result of uiRequired during the processing of the authenticate command.
This is the only command that does not wake up the application in the background and has unlimited execution time. It arrives only after the user starts the application, for example, receiving a UILocalNotification about the need for additional interaction during the processing of the authenticate command.
Just at this stage you should ask the user to enter his domain credits, if the network is corporate, or to show, for example, advertising, if the network is commercial. In short, the options are limited only by the imagination and common sense of the developer.
As a result, you must return a response with one of the following results:
.success - authorization completed successfully. Access to the network is fully open. StateMachine enters the authenticated state.
.unsupportedNetwork - this network is not supported Helper: incorrect network analysis was performed at the evaluate stage. StateMachine returns to the evaluate stage, and Helper is added to the exceptions for this network. This can happen, for example, if the Helper returned low confidence for this network at the stage of evaluate, and now it is convinced that it cannot cope.
.temporaryFailure is a fixable error. Let's say a network error occurred during authorization. StateMachine enters the failure state, the device is disconnected from the selected network.
.failure (or any other result, as well as its absence) is a fatal error. Something went wrong, and the connection cannot be processed: for example, the authorization protocol on the server side has changed, and the client is not ready for this. StateMachine enters the failure state, the device is disconnected from the selected network. Additionally, unlike temporaryFailure,
the auto-join function is disabled for such a network .
As a result, the command should be processed as follows:
let network = command.network // // command.createResponse(<Command result>).deliver()
NEHotspotHelperCommandType. maintain
The maintain command, as you might guess from its name, is designed to maintain a user authorization session on the current network. It is called on the selected Hotspot Helper for the network in the process of evaluate in two cases:
- Every 300 seconds (five minutes) during the whole time the device is connected to a Wi-Fi network.
- When you set up a network connection instead of the evaluate command, for which the current Hotspot Helper was previously selected.
It is assumed that in both cases, Hotspot Helper will analyze the current state of the authorization session and perform one of the following actions:
- instantly provide (continue to provide) the user with access to the network, triggering a response with the result of .success ;
- will require re-authorization by calling response with the result of .authenticationRequired (in this case, the StateMachine switches to the Authenticating state and sends the authenticate command to Hotspot Helper).
- will report the inability to continue the session by completing the command with an error code ( .temporaryFailure / .failure or any other method than the ones listed above). In this case, the StateMachine transitions to the Evaluating state to select the Hotspot Helper that can handle the connection.
To distinguish the first case of calling the maintain command from the second, a special flag was provided in the data array transmitted along with the command —
didJustJoin .
As a result, the command should be processed as follows:
let network = command.network if network.didJustJoin { // , Helper } else { // , ( 300 .) } // // command.createResponse(<Command result>).deliver()
It should be noted that during re-authorization the connection will be unavailable for the device until it returns to the Authenticated state.
NEHotspotHelperCommandType. logoff
The logoff command, as one would expect, is
not sent when disconnected from the network .
It is impossible to track the disconnection from the network using Hotspot Helper.This command is designed to terminate the internal authorization session of the selected Hotspot Helper and is sent to it in response to a call to the NEHotspotHelper static method:
class func logoff(_ network: NEHotspotNetwork) -> Bool
This method can be successfully called only with the current network as a parameter, only by the Hotspot Helper, which made the authorization in it, and only when the application is active. Otherwise, the method will return false and the command will not be called.
As a result, StateMachine switches to the LoggingOff state, and Hotspot Helper receives the coveted command and
45 seconds to execute it.
You can get the network that you need to transfer to the method as follows:
let network = NEHotspotHelper.supportedNetworkInterfaces().first
The main use-case: execution of the logout from the UI of the application, which is important for the authorization script using the presentUI command.
As soon as Hotspot Helper finishes the command (or the runtime expires), the StateMachine switches to the inactive state and the device disconnects from the Wi-Fi network.
As a result, the command should be processed as follows:
let network = command.network
It should be noted that prior to receiving this command, the application should not attempt to perform any actions to disconnect from the network, as this will adversely affect the UX of the entire system (in fact, the user will see the connection, but the data will not go).
What else is useful to know
The above describes the principle of operation and implementation details of Hotspot Helper. However, there are several other features that you should be aware of when starting development, namely:
- Hotspot Helper can not be registered on the simulator - for the development and debugging you need a real device.
- The application registered as Hotspot Helper will be launched by the system in the background in any situation, since the whole system depends on it. Even if the application was unloaded by the user, turned off the background fetch, turned on low power mode, etc.
- Hotspot Helper does not provide any ability to monitor disconnections from the network (even if the logoff command is not misleading: this is the processing of the completion of the authorization session by the Helper itself). If you need to monitor the outage, you should take advantage of notifications from reachability (of course, the application must be active - the system will not raise you in the background).
- The network to which the device is currently connected can be recognized as follows:
let network = NEHotspotHelper.supportedNetworkInterfaces().first
It should be noted that, despite the swift-signature of this method (in which a non-optional-array is specified as a result) and the expected behavior (the absence of a network is represented as an empty array), if there is no connection, you can get a network object with empty strings as SSID and BSSID and signal strength 0.0. , , nil ( crash). , .
Note: C iOS 11 .
- , StateMachine Authenticated. reachbility, , Hotspot Helper .
, , reachability Wi-Fi, Hotspot Helper . , :

, . , , .
- Helper .
Hotspot Helper, . , , .
evaluate: Hotspot Helper, high-confidence . Helper. Helper , . , Hotspot Helper .
, - Helper. : , . Apple UI ( SSID).
, - Hotspot Helper . , , — , Hotspot Helper . :
let network = NEHotspotHelper.supportedNetworkInterfaces().first if !network.isChosenHelper {
, false , Helper (, evaluate). , , . .
- , . :
func createTCPConnection(_ endpoint: NWEndpoint) -> NWTCPConnection func createUDPSession(_ endpoint: NWEndpoint) -> NWUDPSession
NSMutableURLRequest:
func bind(to command: NEHotspotHelperCommand)
- iOS10.3, , . - , . : . , - — .
, , .
- iOS 11 NEHotspotHelper NEHotspotConfigurationManager , Wi-Fi . . :
- , (, - .);
- , Wi-Fi- (, ). .
Conclusion
NEHotspotHelper technology, which appeared several years ago, has not lost its relevance to this day. This tool allows you to significantly improve and facilitate the process of using network services. Here I reviewed the basic principles of operation, methods of application and all the steps that should be taken to use it effectively. In addition, he told about some features of Helper, about which the documentation is tactfully silent.I hope you now have a complete idea of why and how to use this thing in your project. However, if you have any questions, write, I am ready to answer them.useful links
- Implementation example on GitHub
- Hotspot Network Subsystem Programming Guide
- Network extension
- NEHotspotHelper reference
- WWDC'15 What's New in Network Extension and VPN
- WWDC'17 Advances in Networking, Part 1
- Forum: How to cancel register an app as a Hotspot Helper (NEHotspotHelper)?
- Forum: entitlements
- Forum: U I
- HotspotHelper