Need some help with Reachability (2.0.3ddg) - iphone

When my app launches, I check for reachability because I need an immediate internet connection. My problem, though, is that it appears there's no immediate confirmation for the NetworkStatus, which means right after the Reachability is setup, I check whether there's a connection, and it returns that there isn't, regardless of whether I am in fact on WiFi/3G, or have turned the radio off.
I can confirm that I am in fact getting an Internet connection, because instantly after applicationDidFinishLaunching, there's a notification which then logs "ReachableViaWiFi"..
What am I doing wrong? Why is it not confirming a valid Internet connection right away?
- (void)applicationDidFinishLaunching:(UIApplication *)application {
NetworkStatus netStatus = [hostReach currentReachabilityStatus];
if (netStatus == NotReachable) {
ErrorViewController *errorViewController = [[ErrorViewController alloc] initWithNibName:#"ErrorView" bundle:[NSBundle mainBundle]];
[tabBarController.view removeFromSuperview];
[window addSubview:[errorViewController view]];
return;
}
}
-(void)setupReachability {
[[NSNotificationCenter defaultCenter] addObserver: self selector: #selector(reachabilityChanged:) name:kReachabilityChangedNotification object: nil];
hostReach = [[Reachability reachabilityWithHostName:#"www.google.com"] retain];
[hostReach startNotifier];
}
-(void)reachabilityChanged:(NSNotification *)notification {
Reachability* curReach = [notification object];
NSParameterAssert([curReach isKindOfClass: [Reachability class]]);
NetworkStatus netStatus = [curReach currentReachabilityStatus];
BOOL connectionRequired = [curReach connectionRequired];
switch (netStatus)
{
case NotReachable:
{
[[NSUserDefaults standardUserDefaults] setInteger:kNOTREACHABLE forKey:kREACHABILITYSTATUS];
NSLog(#"NotReachable");
connectionRequired = NO;
break;
}
case ReachableViaWWAN:
{
[[NSUserDefaults standardUserDefaults] setInteger:kREACHABLEVIAWWAN forKey:kREACHABILITYSTATUS];
NSLog(#"ReachableViaWWAN");
break;
}
case ReachableViaWiFi:
{
[[NSUserDefaults standardUserDefaults] setInteger:kNOTREACHABLE forKey:kREACHABILITYSTATUS];
NSLog(#"ReachableViaWiFi");
break;
}
}
}

OK, so after trying a few things out myself, I actually got it to work, by adding one extra line of code:
-(void)setupReachability {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(reachabilityChanged:) name:kReachabilityChangedNotificationV2 object:nil];
hostReach = [[ReachabilityV2 reachabilityWithHostName:#"www.google.com"] retain];
[hostReach connectionRequired]; // this line was added, and apparently forces a connection requirement..
[hostReach startNotifier];
}

The Reachability sample code provides you with asynchronous callbacks/notifications to inform you of how/when the reachability has changed. In order for your code to work, you should modify your code as follows:
- (void) applicationDidFinishLaunching:(UIApplication *)application {
// setup reachability
[self setupReachability];
}
Then in your callback, when you get the notification you react as needed by your application.
In other words, you can not check immediately for the network status in applicationDidFinishLaunching(). If you want to do so, then you must use a synchronous/blocking method, for instance you can use the code provided in my answer to this question.

You have to make hostReach as class level variable.

Related

iphone - connection recovered callback

I would like to know if there's an automatic way of knowing when the connection was recovered.
My app connects to a webservice, lets say the network is not available in that moment so the app won't get the info from the server, but I would like the app to automactily try to reconect to the server if it "feels" that the connection was recovered.
Is there such a callback?
In whatever class you handle your NSURLConnection you need to add some connection check. So below I have posted an example
Create a Reachability instance
Add an observer to the Reachability did change notification
When the connection will change the - (void)networkReachabilityDidChange:(NSNotification *)notification will be fired.
You obviously check the networkStatus before firing off a connection in the first place.
-(id)init
{
self = [super init];
if(self)
{
Reachability* newInternetReachability = [Reachability reachabilityForInternetConnection];
[newInternetReachability startNotifier];
self.networkReachability = newInternetReachability;
networkStatus = [self.networkReachability currentReachabilityStatus];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(networkReachabilityDidChange:) name:kReachabilityChangedNotification object:nil];
}
return self;
}
- (void) startHTTPRequest
{
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:YOUR_URL cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:YOUR_REQUEST_TIMEOUT];
NSURLConnection *urlConnection = [[NSURLConnection alloc] initWithRequest: delegate:self];
}
- (void)networkReachabilityDidChange:(NSNotification *)notification
{
Reachability *currReach = [notification object];
NSParameterAssert([currReach isKindOfClass: [Reachability class]]);
int currStatus = [currReach currentReachabilityStatus];
// Check that current reachability is not the same as the old one
if(currReach != self.networkReachability)
{
switch (currStatus) {
case ReachableViaWiFi:
// fire off connection
[self startHTTPRequest];
break;
case ReachableViaWWAN:
// Fire off connection (3G)
[self startHTTPRequest];
break;
case NotReachable:
// Don't do anything internet not reachable
break;
default:
break;
}
[self updateReachability];
}
This is only a simple example but you probably need to persist the request until the connection has become available so you can fire it off later. This could be done via NSOperationQueue or something similar.
There isn't such a thing from the standard library perspective. You will have to implement that yourself. You could use apple's Reachability code to listen for network changes. So once you receive a notification from the Reachability code saying that the internet is now connected, you could fire off an URL connection. If you need an example I could mock something up quickly for you.

CNSetSupportedSSIDs returning false/ not working correctly?

I tried to use CaptiveNetwork in order to replace the web sheet that for user authentication with the network. The method is CNSetSupportedSSIDs.
I tried to add the list, but the web sheet for user authentication still keeps popping up every time I open up my App.
I tried to debug it and I realized that I keep getting the return Value as FALSE.
This is my Code:
-(void)updateSSIDlist
{
[[NSNotificationCenter defaultCenter] postNotificationName:#"ssidInitStarted" object:nil userInfo:nil];
ATT_Remote_Access_Wifi_ClientAppDelegate *delegate = (ATT_Remote_Access_Wifi_ClientAppDelegate *)[[UIApplication sharedApplication] delegate];
delegate.ssidInitFinished = NO;
Hotspots *h = [Hotspots defaultHotspots];
NSArray *ssids2 = [h uniqueSSIDs];
NSLog(#"ssids we're shoving down into the system config for iOS to leave alone: %#", [ssids2 description]);
bool ok = CNSetSupportedSSIDs((CFArrayRef) ssids2);
if(ok)
{
[[NSNotificationCenter defaultCenter] postNotificationName:#"ssidInitCompleted" object:nil userInfo:nil];
NSLog(#"completed");
}
else
{
[[NSNotificationCenter defaultCenter] postNotificationName:#"ssidInitFailed" object:nil userInfo:nil];
NSLog(#"failed");
}
delegate.ssidInitFinished = YES;
delegate.dbIsBusy = NO;
}
I searched a LOT, but I couldn't find any correct examples or documentation on this.
I also tried the below link example, but even that retuned the same results.
Any help is Appreciated! Thanks!
NSString *values[] = {#"yourssid"};
CFArrayRef arrayRef = CFArrayCreate(kCFAllocatorDefault, (void *)values, (CFIndex)1, &kCFTypeArrayCallBacks);
if( CNSetSupportedSSIDs(arrayRef))
{
NSLog(#"Successfully registered supported network SSIDs");
}
else
{
NSLog(#"Error: Failed to register supported network SSIDs");
}
the login page is blocked but my application will not be called. let's share the experience. thank you

How to download data from Carrier data/3GS not wifi?

In my iphone app, the user can set whether he wants to download data from internet via wifi or 3G/Carrier data.
How can we do that programatically?
In other words, how can I force iphone to get data from carrier data not from wifi?
Any suggestion guys?
You can't, if the iPhone is connect to WiFi you can not programmaticly force it to use the cellular network to download.
You can't force the iPhone to use carrier data (3G / Edge) instead of WiFi if the phone is connected to WiFi. You can use the SCNetworkReachabilityGetFlags function to determine if you're on WiFi or have a carrier data connection.
What you could do is, if the user is connected to WiFi, pop up a message saying that your app only works with carrier data and ask the user to switch off WiFi and restart the app. I would not recommend this though as it will just irritate the hell out of your users, although this didn't stop Vodafone Portugal from doing it for a number of their apps in a silly attempt to force you to use more (expensive) carrier data.
I'm not sure if this is helpful to you:
http://developer.apple.com/library/ios/#samplecode/Reachability/Introduction/Intro.html
For that you need to detect the state of the phone and you can easily identifies the weather data isn't transfer when a phone uses the wifi.
-(void) viewWillAppear:(BOOL)animated
{
// check for internet connection
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(checkNetworkStatus:) name:kReachabilityChangedNotification object:nil];
internetReachable = [[Reachability reachabilityForInternetConnection] retain];
[internetReachable startNotifier];
// check if a pathway to a random host exists
hostReachable = [[Reachability reachabilityWithHostName: #"www.apple.com"] retain];
[hostReachable startNotifier];
// now patiently wait for the notification
}
- (void) checkNetworkStatus:(NSNotification *)notice {
// called after network status changes
NetworkStatus internetStatus = [internetReachable currentReachabilityStatus];
switch (internetStatus){
case NotReachable:
{
NSLog(#"The internet is down.");
self.internetActive = NO;
break;
}
case ReachableViaWiFi:
{
NSLog(#"The internet is working via WIFI.");
self.internetActive = YES;
break;
}
case ReachableViaWWAN:
{
NSLog(#"The internet is working via WWAN.");
self.internetActive = YES;
break;
}
}
NetworkStatus hostStatus = [hostReachable currentReachabilityStatus];
switch (hostStatus)
{
case NotReachable:
{
NSLog(#"A gateway to the host server is down.");
self.hostActive = NO;
break;
}
case ReachableViaWiFi:
{
NSLog(#"A gateway to the host server is working via WIFI.");
self.hostActive = YES;
break;
}
case ReachableViaWWAN:
{
NSLog(#"A gateway to the host server is working via WWAN.");
self.hostActive = YES;
break;
}
}
}
more information visits this link.

How to check network connection in iphone

this code is to check if internet connection is available or not.If internet connection is available then username and password should get validated from server database i.e send request method should get called and if not then username and password should get validated from local database i.e check method should get called.but the prob here is when the internet is off then also it gets into the send request method instead of getting in check nethod.What may be the prob.Please help me in solving this problem. i have added reachability files and imported the CFNetwork.framework.
- (void) showNetWorkAlert {
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
UIAlertView *networkAlert = [[UIAlertView alloc] initWithTitle:#"Error" message:#"Network connection unavailable."
delegate:self cancelButtonTitle:#"OK" otherButtonTitles:#"Retry", nil];
[networkAlert show];
[networkAlert release];
}
#pragma mark To Check Network Connection.
- (BOOL) currentNetworkStatus {
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
BOOL connected;
const char *host = "www.apple.com";
SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(NULL, host);
SCNetworkReachabilityFlags flags;
connected = SCNetworkReachabilityGetFlags(reachability, &flags);
BOOL isConnected = YES;
isConnected = connected && (flags & kSCNetworkFlagsReachable) && !(flags & kSCNetworkFlagsConnectionRequired);
CFRelease(reachability);
if(!isConnected) {
// sleep(1);
[self showNetWorkAlert];
//[self check];
}
else
return isConnected;
//[self sendRequest];
return isConnected;
}
-(IBAction)buttonPressed:(id)sender
{
//[self sendRequest];
//[[Reachability sharedReachability] setHostName:kHostName];
//Set Reachability class to notifiy app when the network status changes.
//[[Reachability sharedReachability] setNetworkStatusNotificationsEnabled:YES];
//Set a method to be called when a notification is sent.
//[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(reachabilityChanged:) name:#"kNetworkReachabilityChangedNotification" object:nil];
//[self updateStatus];
//[self sendRequest];
//NSLog(<#NSString *format#>)
//this is to select username and password from database.
//[self check];
if ([self currentNetworkStatus]) {
[self sendRequest];
}
else {
[self check];
}
}
Rocky your code is right .Just check the URL is proper or not .
there is other way also
On button check the host like this
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(reachabilityChanged:)
name:kReachabilityChangedNotification
object:nil];
hostReach = [[Reachability reachabilityWithHostName:#"www.google.com"]retain];
[hostReach startNotifier];
and in the (reachabilityChanged:) method call make like this
-(void)reachabilityChanged:(NSNotification*)note
{
static BOOL showNotConnnected =NO;
Reachability *curReach =[note object];
NSParameterAssert([curReach isKindOfClass:[Reachability class]]);
NetworkStatus netStatus = [curReach currentReachabilityStatus];
if(netStatus != NotReachable)
{
UIAlertView *notconnect1 = [[UIAlertView alloc]initWithTitle:#"Server is connected" message:#"Server is connected" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:#"Cancel",nil];
[notconnect1 show];
[notconnect1 release];
}
else if(showNotConnnected == NO)
{
showNotConnnected =YES;
UIAlertView *notconnect = [[UIAlertView alloc]initWithTitle:#"Server is Not connected" message:#"Server may be slow or not connected" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:#"Cancel",nil];
[notconnect show];
[notconnect release];
}
}
I hope this will help you
I do think there is a sample code called Reachability from apple can help you. see the URL below
http://developer.apple.com/library/ios/samplecode/Reachability/Introduction/Intro.html
You should look at Apple's reachability code to check for a connection to the Internet. There is a sample project you can get from them in the iOS Developer Portal.
Reachability should not be used to detect if the network is available before making a network request because the act of making a network request can bring up the network if needed. Reachability should only be used to detect when the network becomes available after being unavailable.
Just try making the network request -- you'll get an error back if the network is unavailable. Usually the response will come back right away, but if the network is spotty it can take a while, so you shouldn't ever make synchronous network calls on the main thread. Use NSURLConnection if possible and you'll get callbacks when something happens.

Reachability problem with notifications on a separate thread

I make use of Apples Reachability class and it works if I keep it on the main thread(bad approach). If I instead move it to a separate thread the notification is never called.
In didFinishLaunchingWithOptions i call the following:
[NSThread detachNewThreadSelector:#selector(checkConnection) toTarget:self withObject: nil];
checkConnection looks like follows:
-(void)checkConnection {
//Test for Internet Connection
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(reachabilityChanged:) name:kReachabilityChangedNotification object:nil];
Reachability *r = [[Reachability reachabilityWithHostName:#"appspot.com"] retain];
[r updateReachability:appDelegate.reachability];
[r startNotifier];
[pool release];
}
and reachabilityChanged looks like this:
- (void)reachabilityChanged:(NSNotification *)note {
Reachability* curReach = [note object];
NSParameterAssert([curReach isKindOfClass: [Reachability class]]);
[self updateReachability: curReach];
}
and finally updateReachability looks like this:
- (void)updateReachability:(Reachability *)curReach {
NetworkStatus internetStatus = [curReach currentReachabilityStatus];
if ((internetStatus != ReachableViaWiFi) && (internetStatus != ReachableViaWWAN)) {
NSLog(#"No net");
} else {
NSLog(#"Lots of net");
}}
Hope you guys can help me to understand why reachabilityChanged is never called.
Cheers...
I've used Apple's reachability example for the Mac and have had it working fine. You are suppose to run reachability on the main thread. The whole point of the reachability is that you don't have to pool for an internet connection. The system automatically spawns a background thread to monitor for changes in interent connection and will notify you of any changes.
Have your app ever stalled because of reachability or are you just postulating that it might happen?
See this answer:
Reachability sometimes fails, even when we do have an internet connection