Search code examples
ios6reachability

ip address change notifications


I'm using the Reachability class to detect wifi availability.

There are some situations when an ipad will be connected to one wifi network,and a user will connect to another available wifi network.

During these network transitions reachable->unreachable->reachable notifications are not generated.

This connection change where the ip address of the ipad changes is what Im trying to listen for.

Do notifications for local wifi connection changes exist or will I have to just poll my ip periodically?


Solution

  • I would personally just poll the IP however frequently you find appropriate (once a second should be fine), using the code found here, and just store the previous occurrences result, see if it changes.

    What I would really recommend is setting up a simple delegate class that does this for you and will send a custom event to whatever class may need those updates. It should be pretty straight forward, especially considering it seems like you have some experience.

    UPDATE

    I have posted some code below that will create a delegate that will call back to whatever class once it detects any change in IP. Note there may be some errors/typos as I am not in front of a computer with XCode currently, but you should get the general idea.

    IPChangeNotifier.h

    #import <UIKit/UIKit.h>
    
    @protocol IPChangeNotifierDelegate;
    
    @interface IPChangeNotifier : NSObject {
        NSString *prevIP;
        NSTimer *changeTimer;
        id changeDelegate;
    }
    -(id) initWithTimer:(float)time andDelegate:(id)del;
    -(NSString*)getIPAddress;
    -(void) checkForChange;
    @end
    
    @protocol IPChangeNotifierDelegate <NSObject>
    @optional
    -(void) IPChangeDetected:(NSString*)newIP previousIP:(NSString*)oldIP;
    @end
    

    IPChangeNotifier.m

    #import IPChangeNotifier.h
    #import <ifaddrs.h>
    #import <arpa/inet.h>
    @implementation IPChangeNotifier
    
    -(id) initWithTimer:(float)time andDelegate:(id)del {
        changeTimer = [NSTimer scheduleTimerWithTimeInterval:time target:self selector:@selector(checkForChange) userInfo:nil repeats:YES];
        prevIP = @"";
        changeDelegate = del;
    }
    
    -(void) checkForChange {
        NSString *currentIP = [self getIPAddress];
        if (![currentIP isEqualToString:prevIP]) {
            if ([changeDelegate respondsToSelector:@selector(IPChangeDetected:)]){
                 [changeDelegate IPChangeDetected:currentIP previousIP:prevIP];    
            }
            prevIP = currentIP;
        }
    }
    
    - (NSString *)getIPAddress {    
        struct ifaddrs *interfaces = NULL;
        struct ifaddrs *temp_addr = NULL;
        NSString *wifiAddress = nil;
        NSString *cellAddress = nil;
    
        // retrieve the current interfaces - returns 0 on success
        if(!getifaddrs(&interfaces)) {
            // Loop through linked list of interfaces
            temp_addr = interfaces;
            while(temp_addr != NULL) {
                sa_family_t sa_type = temp_addr->ifa_addr->sa_family;
                if(sa_type == AF_INET || sa_type == AF_INET6) {
                    NSString *name = [NSString stringWithUTF8String:temp_addr->ifa_name];
                    NSString *addr = [NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_addr)->sin_addr)]; // pdp_ip0     
                    NSLog(@"NAME: \"%@\" addr: %@", name, addr); // see for yourself
    
                    if([name isEqualToString:@"en0"]) {
                        // Interface is the wifi connection on the iPhone
                        wifiAddress = addr;    
                    } else
                    if([name isEqualToString:@"pdp_ip0"]) {
                        // Interface is the cell connection on the iPhone
                        cellAddress = addr;    
                    }
                }
                temp_addr = temp_addr->ifa_next;
            }
            // Free memory
            freeifaddrs(interfaces);
        }
        NSString *addr = wifiAddress ? wifiAddress : cellAddress;
        return addr ? addr : @"0.0.0.0";
    } 
    @end
    

    You can then simply make whatever class you want a delegate by adding <IPChangeNotifierDelegate> to your interface file and then initialize the notifier by doing something simple like below.

    IPChangeNotifier *ipChecker = [[IPChangeNotifier alloc] initWithTimer:1.0 andDelegate:self]
    

    Also make sure you have the following method included to make sure you can get the change events and do whatever you need.

    -(void) IPChangeDetected:(NSString*)newIP previousIP:(NSString*)oldIP {
         // Do what you need
    }