NEHotspotHelper (NetworkExtension iOS9.0) Sample code

Hi,

I would like to achive below tasks in my app ,

1) Annotate Wifi networks in the WiFi network scanner (Display WiFi networks in the iOS X network scanner with a little tag that displays something (your company name, for example) under the SSID name.)

2) Authenticate for WiFi Hotspots in backgorund .


I am able see my binary signed with NEHotspotHelper Entitlements also i have added network-authentication background mode to the Info.plist

Referred link https://forums.developer.apple.com/thread/9015 , https://forums.developer.apple.com/message/30660#30660


My current code is pasted below . registerWithOptions is returning true and handler code is called in backgorund and when user scans Wifi list .


NSDictionary* options = [NSDictionary dictionaryWithObjectsAndKeys:@"Connect Here",kNEHotspotHelperOptionDisplayName, nil];

dispatch_queue_t queue = dispatch_queue_create("com.my.NewtworkExt", 0);


BOOL returnType = [NEHotspotHelper registerWithOptions:options queue:queue handler: ^(NEHotspotHelperCommand * cmd) {


if(cmd.network) {

NEHotspotNetwork* network = cmd.network;

if( (cmd.commandType == kNEHotspotHelperCommandTypeEvaluate || cmd.commandType == kNEHotspotHelperCommandTypeFilterScanList ) {

[network setConfidence:kNEHotspotHelperConfidenceHigh];

}

}

}];


Please provide me some sample code/ steps to achive above tasks.

Replies

Updated code ,


We tried out the new NetworkExtention API. We were successful in recreating all the steps in our app. But, we have an issue that we are still not seeing the custom annotation below the SSID name in the Wifi settings screen. We are on ios 9 Beta 3, xcode 7 beta 3.

We have done these steps successfully:

  • @note 1 The application's Info.plist MUST include a UIBackgroundModes array * containing 'network-authentication'.
  • @note 2 * The application MUST set 'com.apple.developer.networking.HotspotHelper' * as one of its entitlements. The value of the entitlement is a boolean * value true.

Here's our code in the App. We are trying to annotate a SSID by the name of "Internet" by a text "Try Here". We get the log that the setConfidence method is called for SSID "Internet". Yet, we do not see the actual annotation in the Wifi selection screen.

We also tried to pass 'nil' for the options object which promised to show the App name as the default annotation. But we do not see that either. We get return 'true' for the call to method registerWithOptions() and we do get callbacks when we open the wifi settings screen



NSMutableDictionary* options = [[NSMutableDictionary alloc] init];

[options setObject:@"Try Here" forKey:kNEHotspotHelperOptionDisplayName];

BOOL returnType = [NEHotspotHelper registerWithOptions:options queue:dispatch_get_main_queue() handler: ^(NEHotspotHelperCommand * cmd) {

if(cmd.commandType == kNEHotspotHelperCommandTypeEvaluate || cmd.commandType == kNEHotspotHelperCommandTypeFilterScanList ) {

for (NEHotspotNetwork* network in cmd.networkList) {

if ([network.SSID isEqualToString:@"Internet"]){

[network setConfidence:kNEHotspotHelperConfidenceHigh];

NSLog(@"Confidance set to high for ssid:%@",network.SSID);

}

}

}


}];

Please help us to understand what we are missing ?

You need to create a response.


This Swift code is working for me:

if let list = cmd.networkList where cmd.commandType == .FilterScanList {
    var networks = [NEHotspotNetwork]()
    for network in list {
        if network.SSID.hasPrefix("BTVNET") {
            network.setPassword("12345678")
            network.setConfidence(.High)
            networks.append(network)
        }
    }
    let response = cmd.createResponse(.Success)
    response.setNetworkList(networks)
    response.deliver()
}


So you need to call createResponse on the given command, setNetworkList using only networks where you changed confidence for at least .Low and then deliver().

Thanks a lot quiker that wroked 🙂

I never get cmd.commandType == kNEHotspotHelperCommandTypeAuthenticate get called. It only calls kNEHotspotHelperCommandTypeEvaluate and kNEHotspotHelperCommandTypeFilterScanList all the time. My wifi network has both password protection and captive network also.

Is there any specific reason ?

I do have same issue I could receive kNEHotspotHelperCommandTypeEvaluate and kNEHotspotHelperCommandTypeFilterScanList in my code . But kNEHotspotHelperCommandTypeAuthenticate command never gets called . I am trying to connect captive newtwok ( i.e. public WiFi Hotspot) . The html login page is not coming at all .


Let me know how i can connect captive newtwok ( i.e. public WiFi Hotspot) programatically using NEHotspotHelper .

I do have same issue I could receive

kNEHotspotHelperCommandTypeEvaluate
and
kNEHotspotHelperCommandTypeFilterScanList
in my code. But
kNEHotspotHelperCommandTypeAuthenticate
command never gets called.

How do you respond to the

.Evaluate
command? The standard approach is:
  1. create a response from the command (using

    -[NEHotspotHelperCommand createResponse:]
    )
  2. get the network from the command (the

    network
    property)
  3. set your confidence for handling that network (

    -setConfidence:
    )
  4. put that network in the response (using

    -setNetwork:
    )
  5. deliver the response (

    -deliver
    )

What happens next depends on the confidence value you set:

  • If it’s

    .High
    , your plug-in should immediately transition to the Authenticating state.
  • If it’s

    .Low
    , the system will wait for any other plug-ins to respond before deciding how to proceed. If any plug-in responds with
    .High
    , it’ll go to Authenticating state. If not, the system will proceed through the list of
    .Low
    plug-in in some unspecified order.
  • If it’s

    .None
    , your plug-in will transition to the Authenticated state (that is, as far your plug-in is concerned, this is not a captive network, although it may actually be a captive network that some other plug-in can handle).

Share and Enjoy

Quinn "The Eskimo!"
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

give me demo ,thank you

give me a demo ,thank you ,please

can you give me a demo, thank you!

The Method registerWithOptions:queue:handler is NO, i don't know Why?

The Method registerWithOptions:queue:handler is NO, i don't know Why?

The most common causes for this are related to how you construct your app. Make sure that you:

  • have signed the app with the

    com.apple.developer.networking.HotspotHelper
    entitlement

    IMPORTANT It’s easy to get this wrong; you should double check it using the process described in Debugging Entitlement Issues.

  • have set

    network-authentication
    in the
    UIBackgroundModes
    array in your
    Info.plist

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Thank you very much! I have already solved the problem in your help!

😐

The Method registerWithOptions:queue:handler is NO, i don't know Why?


Hello, I also met the same problem with you, could you tell me how do you solve?I was Debugging Entitlement Issues checked it again, I don't know where I went wrong.i need your help.

😐

The Method registerWithOptions:queue:handler is NO, i don't know Why?

Hello, I also met the same problem with you, could you tell me how do you solve?I was Debugging Entitlement Issues checked it again, I don't know where I went wrong.i need your help.

Hi folx! :-)


Same here: authentication via WISPr to a captive WLAN, kNEHotspotHelperCommandTypeAuthenticate never gets caught. As a workaround I return kNEHotspotHelperResultSuccess in kNEHotspotHelperCommandTypeEvaluate. Works with one exeption: the arbitrary URL call (captive.apple.com) gets opened *sometimes* in the captive webview controller of iOS *after* beeing successfully authenticated to the WLAN.


Is there any documented reason why the state machine never enters kNEHotspotHelperCommandTypeAuthenticate?

Here's some sample code:

- (void)registerHelper {
    NSDictionary *options = @{ kNEHotspotHelperOptionDisplayName : self.configuration.annotation };
   
    BOOL theResult = [NEHotspotHelper registerWithOptions:options queue:dispatch_get_main_queue() handler:^(NEHotspotHelperCommand *_Nonnull cmd) {
        self.apiClient.cmd = cmd;
        switch (cmd.commandType) {
             case kNEHotspotHelperCommandTypeFilterScanList: {
                 NSMutableArray *theNetworks = [NSMutableArray new];
                 for (NEHotspotNetwork *theNetwork in cmd.networkList) {
                     if ([self ssidIsSupported:theNetwork.SSID]) {
                         [theNetwork setConfidence:kNEHotspotHelperConfidenceHigh];
                         [theNetworks addObject:theNetwork];
                         [self wisprSupportedNetworkFound:theNetwork];
                     }
                 }
                 NEHotspotHelperResponse *response = [cmd createResponse:kNEHotspotHelperResultSuccess];
                 [response setNetworkList:theNetworks];
                 [response deliver];
                 break;
             }
             case kNEHotspotHelperCommandTypeEvaluate: {
                 if ([self ssidIsSupported:cmd.network.SSID]) {
                     self.connectedNetwork = cmd.network;
                     [cmd.network setConfidence:kNEHotspotHelperConfidenceHigh];
                     [self authenticateWithForCmd:cmd Completion:^(EAPWisprResponse theWisprResponse) {
                         NEHotspotHelperResult responseResult;
                         switch (theWisprResponse) {
                             case EAPWisprResponseNoError:
                             case EAPWisprResponseLoginSucceeded:
                             case EAPWisprResponseAlreadyAuthenticated:
                                 responseResult = kNEHotspotHelperResultSuccess;
                                 break;
                             default:
                                 responseResult = kNEHotspotHelperResultFailure;
                                 break;
                         }
                         NEHotspotHelperResponse *response = [cmd createResponse:responseResult];
                         [response setNetwork:cmd.network];
                         [response deliver];
                     }];
                 }
                 break;
             }
             case kNEHotspotHelperCommandTypeNone:break;
             case kNEHotspotHelperCommandTypeAuthenticate:{
                 break;
             }
             case kNEHotspotHelperCommandTypePresentUI:break;
             case kNEHotspotHelperCommandTypeMaintain:break;
             case kNEHotspotHelperCommandTypeLogoff:break;
             default:
                 break;
         }
     }];
}

What createresponse value should I use? Success, AuthenticationRequired, UIRequired?


I tried them all, with high confidence, and resetting the iPhone's network and rebooting each time. None of the combinations result in me becoming the chosen helper. ( NEHotspotHelper.SupportedNetworkInterfaces[0].ChosenHelper)


Nor is Authenticate ever called.