using startMonitoringEventWithType: error: in the effort to detect wifi SSID change

MacOS

Question or issue on macOS:

Apple seems to introduce quite a change with Yosemite and CoreWLAN framework. I would like to use its new API, quoting the header file:

/*!
 * @method
 *
 * @param type
 * A CWEventType value.
 *
 * @param error
 * An NSError object passed by reference, which upon return will contain the error if an error occurs.
 * This parameter is optional.
 *
 * @result
 * A BOOL value indicating whether or not an error occurred. YES indicates no error occurred.
 *
 * @abstract 
 * Register for specific Wi-Fi event notifications.
 * 
 * @discussion
 * Requires the com.apple.wifi.events entitlement.
 */
- (BOOL)startMonitoringEventWithType:(CWEventType)type error:(out NSError **)error NS_AVAILABLE_MAC(10_10);

and setting CWEventType to: CWEventTypeSSIDDidChange

It says it requires entitlement, but I am not being able to run it on my mac. The error message is:

And my entitlements file (where I suspect the problem to be) is like this:





    com.apple.wifi.events
    


and I am setting the code signing path in the build setting for the target. And speaking of which, if I exclude the local entitlements file, the app runs but doesn’t behave as expected. The API under study returns an error object with following description:

Error Domain=com.apple.wifi.request.error Code=4 "The operation couldn’t be completed. (com.apple.wifi.request.error error 4.)"

It is definitely a mind twister, or at least I hope it is otherwise I am a total idiot. I have a specific App ID for my app in the member center, as well as a specific development profile (although I shouldn’t have to since I am using a wildcard dev profile).

Thanks in advance.

How to solve this problem?

Solution no. 1:

It seems that there is currently (31st of July 2015) a bug in CWWiFiClient: entitlements are not properly granted. This even extends to non-sandboxed apps. See this question on the Apple developer forums for more information.

As a result, we may have to resort to the deprecated API for the time being. syammala provides a good example of how to use the deprecated API.

Solution no. 2:

This does the same job what you want to achieve in above. It notifies you whenever SSID changes

In order for you to get those notifications you need to be holding on to an instance of CWInterface. Your .h would look like this

#import 
@class CWInterface;

@interface AppDelegate : NSObject 

@property (assign) IBOutlet NSWindow *window;
@property (retain) CWInterface *wirelessInterface;

@end

Then in your .m file would look like this

#import "AppDelegate.h"
#import 

@implementation AppDelegate

@synthesize window = _window;
@synthesize wirelessInterface;

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    // Insert code here to initialize your application

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleNotification:) name:CWModeDidChangeNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleNotification:) name:CWSSIDDidChangeNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleNotification:) name:CWBSSIDDidChangeNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleNotification:) name:CWCountryCodeDidChangeNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleNotification:) name:CWLinkDidChangeNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleNotification:) name:CWPowerDidChangeNotification object:nil];

    self.wirelessInterface = [CWInterface interfaceWithName:@"en1"];
}

-(void) handleNotification:(NSNotification*) notification
{
    NSLog(@"Notification Received");
}

@end

Take care while using interface name en1 or en0. Check your sysytem by seeing to which interface ip is present by giving ifconfig

Solution no. 3:

you should use CWEventDelegate together with startMonitoringEventWithType, according to the document of CWEventDelegate:
https://developer.apple.com/documentation/corewlan/cweventdelegate

the whole code is :

- (void)testDelegateMethod{
    [CWWiFiClient sharedWiFiClient].delegate = self;
    
    NSError *error;
    [[CWWiFiClient sharedWiFiClient] startMonitoringEventWithType:CWEventTypePowerDidChange error:&error];
    [[CWWiFiClient sharedWiFiClient] startMonitoringEventWithType:CWEventTypeSSIDDidChange error:&error];
    [[CWWiFiClient sharedWiFiClient] startMonitoringEventWithType:CWEventTypePowerDidChange error:&error];
    [[CWWiFiClient sharedWiFiClient] startMonitoringEventWithType:CWEventTypeLinkDidChange error:&error];
    [[CWWiFiClient sharedWiFiClient] startMonitoringEventWithType:CWEventTypeNone error:&error];
    
    if (error) {
        NSLog(@"error : %@",error);
    }
}

#pragma mark - CWEventDelegate
- (void)clientConnectionInterrupted{
    NSLog(@"-- clientConnectionInterrupted");
}

- (void)clientConnectionInvalidated{
    
    NSLog(@"-- clientConnectionInvalidated");
}


- (void)powerStateDidChangeForWiFiInterfaceWithName:(NSString *)interfaceName{
    NSLog(@"-- %@ powerStateDidChange  ",interfaceName);
}

- (void)ssidDidChangeForWiFiInterfaceWithName:(NSString *)interfaceName{
    NSLog(@"-- %@ ssidDidChange",interfaceName);
}

Hope this helps!