Search code examples
objective-cmacoswifi

Notification when wifi connected (OS X)


I need a notification from the system when airport is connecting to an ap. Is there any possibility to do that with the SystemConfiguration framework? I have problems to understand the systemconfigurations api documentation.


Solution

  • You are on the right track with the SystemConfiguration network, which offers the SCNetworkReachability set of functions. You could try using

    SCNetworkReachabilitySetCallback
    

    to set a callback which will be called when the reachability changes; and

    SCNetworkReachabilityScheduleWithRunLoop
    

    to schedule the reachability check within the run loop

    Or you might try using a reachability framework (both for MacOS and iOS) which is built on top of the SystemConfiguration framework to make things even easier (higher-level).

    If you want to go the SystemConfiguration way, this is how you check for present reachability and install the callback to be notified of changes (source):

    - (void)checkReachability {
      NSString *server = [[NSUserDefaults standardUserDefaults] stringForKey:@"NCIDServer"];
    
      if (server == nil) {
        ncid_message_callback(self, [NSLocalizedString(@"No caller ID server was specified.", nil) UTF8String]);
        return;
      }
    
      const char *serverName = [[[server componentsSeparatedByString:@":"] objectAtIndex:0] UTF8String];
      SCNetworkReachabilityContext context = {0, (void *)self, NULL, NULL, NULL};
      networkReachability = SCNetworkReachabilityCreateWithName(NULL, serverName);
    
      if (networkReachability == NULL)
        goto fail;
    
      // If reachability information is available now, we don't get a callback later
      SCNetworkConnectionFlags flags;
    
      if (SCNetworkReachabilityGetFlags(networkReachability, &flags))
        networkReachabilityCallback(networkReachability, flags, self);
    
      if (!SCNetworkReachabilitySetCallback(networkReachability, networkReachabilityCallback, &context))
        goto fail;
    
      if (!SCNetworkReachabilityScheduleWithRunLoop(networkReachability, [[NSRunLoop currentRunLoop] getCFRunLoop], kCFRunLoopCommonModes))
         goto fail;
      return;
    
    fail:
      if (networkReachability != NULL)
        CFRelease(networkReachability);
    
      networkReachability = NULL; //-- ivar representing current reachability
    
    }
    

    And this is a sample of the callback:

    static void networkReachabilityCallback(SCNetworkReachabilityRef target,
                    SCNetworkConnectionFlags flags,
                    void *object) {
      // Observed flags:
      // - nearly gone: kSCNetworkFlagsReachable alone (ignored)
      // - gone: kSCNetworkFlagsTransientConnection | kSCNetworkFlagsReachable | kSCNetworkFlagsConnectionRequired
      // - connected: kSCNetworkFlagsIsDirect | kSCNetworkFlagsReachable
    
      if (networkReachability == NULL)
        return;
    
      if ((flags & kSCNetworkFlagsReachable) && !(flags & kSCNetworkFlagsConnectionRequired))    {
    
        if (isReachable) // typically receive a reachable message ~20ms before the unreachable one
        return;
    
        isReachable = YES;
        ncid_network_kill();
        [NSThread detachNewThreadSelector:@selector(runThread:) toTarget:object withObject:nil];
    
      } else {
        isReachable = NO;
        ncid_network_kill();
      }
    }