tags:

views:

606

answers:

2

I would like to check "reachability" before/when a webView is shown in my app.

So far I've included the reachbility.h/.m files as well as added the SystemConfiguration.framework to the project.

And that's about where the agreements I have found on the internet end, from all of the posts and blogs etc. etc. everyone has a different idea/opinion of what to do after that. Additionally, I have found a lot partial code snippets that aren't really a complete solution, on which reachibility methods to call etc. etc. how to use them etc.

I have also found that some warn that you should try to reconnect before checking reachability...but I haven't found a consensus or a full solution. My app seems to reconnect to wifi without any extra code... so I'm a litte confused here too...

Any help to clear the muddy waters would be appreciated. I'm just looking for a simple straightforward solution.

Answer Accepted: I would like to note to newbies who may read this q/a later... that you will want to do the following:

Add this into your .h file:

  • (BOOL) connectedToNetwork: (NSString *) remoteServer;
  • (void) appLoadError: (NSString *) altertTitle alertMessage: (NSString *) altertMsg;

And you will need to import these at the top of your .m file:

sys/socket.h

netinet/in.h

netinet6/in6.h

arpa/inet.h

ifaddrs.h

netdb.h

SystemConfiguration/SystemConfiguration.h

Correct me if it is wrong... It seems to work fine for me...

+2  A: 

I have always used this method in my App Delegate when I need to require Internet access. I have tuned it for different access types over time and it has served me well. It is a variant of one of the many methods you can find after a quick Google search on this topic.

It is a tricky thing to come up with a hard and fast strategy around this. The platform itself offers different connectivity options that have pros and cons based on the needs of each specific application. The method I use below is just a general connectivity test meaning the device can reach the Internet via some connectivity mechanism.

- (BOOL) connectedToNetwork: (NSString *) remoteServer {
    // Create zero addy
    struct sockaddr_in zeroAddress;
    bzero(&zeroAddress, sizeof(zeroAddress));
    zeroAddress.sin_len = sizeof(zeroAddress);
    zeroAddress.sin_family = AF_INET;

    // Recover reachability flags
    SCNetworkReachabilityRef defaultRouteReachability = SCNetworkReachabilityCreateWithAddress(NULL, (struct sockaddr *)&zeroAddress);
    SCNetworkReachabilityFlags flags;

    BOOL didRetrieveFlags = SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags);
    CFRelease(defaultRouteReachability);

    if (!didRetrieveFlags){
        NSLog(@"Error. Could not recover network reachability flags");
        return NO;
    }

    BOOL isReachable = flags & kSCNetworkFlagsReachable;
    BOOL needsConnection = flags & kSCNetworkFlagsConnectionRequired;
    BOOL nonWiFi = flags & kSCNetworkReachabilityFlagsTransientConnection;

    NSURL *testURL = [NSURL URLWithString: remoteServer];
    NSURLRequest *testRequest = [NSURLRequest requestWithURL:testURL  cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:20.0];
    NSURLConnection *testConnection = [[NSURLConnection alloc] initWithRequest:testRequest delegate:self];

    return ((isReachable && !needsConnection) || nonWiFi) ? (testConnection ? YES : NO) : NO;
}

I usually call this inside applicationDidFinishLaunching. If the check returns false, I usually generate an error message (see below). This is because Apple forbids exiting the application by any means other than the home button on the device.

...
else if(![self connectedToNetwork: [NSString stringWithFormat: @"http://%@:%@/", sharedSettings.server, sharedSettings.port]]){
     [self appLoadError: @"No Internet Detected" alertMessage:@"This application requires an active Internet connection.  No content is available."];  
}
...
- (void) appLoadError: (NSString *) altertTitle alertMessage: (NSString *) altertMsg {
    UIAlertView *loadErr = [[UIAlertView alloc] initWithTitle: altertTitle message: altertMsg delegate: self cancelButtonTitle: @"OK" otherButtonTitles: nil];
    [loadErr show];
    [loadErr release];

    // Load static screen
    UIImage *image = [UIImage imageNamed:@"Error_NoInternet.png"];
    UIImageView *imageView = [[UIImageView alloc] initWithImage:image];

    [controller setNavigationBarHidden: YES animated: NO];

    [window addSubview: imageView];
    [imageView release];
}
MystikSpiral
A: 

Just a quick note, I believe that method is leaking an NSURLConnection on every call (at the bottom, testConnection).

You might want to use

+ (NSURLConnection *)connectionWithRequest:
        (NSURLRequest *)request delegate:(id)delegate

instead.

theLastNightTrain