I tested different frameworks, e.g.
and I would like to know if a host is reachable. On my iPhone, I set my iMac as proxy (Charles) and block or don't block the connections, but the reachability is always YES. Only if I set a non-existing host, it returns NO. But if the host exists but I block the connection to it, I always get isReachable
. Isn't there a way to check if the host is really reachable?
If I try with KSReachability, I'm doing the following:
self.reachability = [KSReachability reachabilityToHost:@"www.stackoverflow.com"];
self.reachability.notificationName = kDefaultNetworkReachabilityChangedNotification;
self.reachability.onReachabilityChanged = ^(KSReachability *reachability) {
NSLog(@"isReachable: %i", reachability.reachable);
};
I always get isReachable: 1
there with the following configuration:
When I try to reach www.stackoverflow.com in Safari, the page can't be opened (as expected). I would expect the reachability to be false (isReachable: 0
) in this case.
EDIT So the most important question for me is - how to achieve the behavior I'm expecting? I.e. that the app continuously checks if the given host is really reachable?
That means that they will need to only show the iOS native permission prompt when they are certain that the user will accept it. Amazon showcases that the notifications are important and time-sensitive.
Sending notifications to users iOS is tricky. Users are particularly sensitive to spam, which is completely understandable if you’ve ever spent time clearing out useless notifications. Because of this, opt-in rates are really low for iOS permission prompts with little or no context.
Users are sensitive to the term “notification,” particularly because it bring backs memories of Farmville-style notifications they’d received on their Facebook news feed. A best practice for app notifications is to be able to frame the permissions prompt as something more valuable, so that the user understands the value of granting permissions.
The code statement:
self.reachability = [KSReachability reachabilityToHost:@"www.stackoverflow.com"];
actually calls below method:
SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(NULL,
[hostName UTF8String]);
SCNetworkReachability reference says:
The SCNetworkReachability programming interface allows an application to determine the status of a system's current network configuration and the reachability of a target host. A remote host is considered reachable when a data packet, sent by an application into the network stack, can leave the local device. Reachability does not guarantee that the data packet will actually be received by the host.
The explanation clears that iOS system doesn't send any request to outside world to check the reachability. It just tells that data packet can leave the device or not. If system were to send the request it automatically means that it is connected to network.
You can verify this by mentioning a valid host like "www.stackoverflow.com" and check in charles (first unblock it) that no request is sent.You can also check with other valid host names like "www.abcdefgh.com" (verify this by running it in Safari and see in charles) it also gives you the reachability but charles shows no request.Also if you put http:// before any valid host, something like "http://www.stackoverflow.com" it will also fails reachability. So it is clear that it is not an outgoing http request. If system has to send a request outside then what's the point of providing the class? A developer could have created a network connection and try to connect to a host and see if it passes or fails.
However it is interesting that if an invalid host like "www.hjjkhkhk.com" is provided iOS system gives reachability as false. Now the question is how iOS system finds a valid or invalid host without sending any query to outside world? May be it is periodically caching a list of DNS ranges??? Highly improbable to me.
In your AppDelegate
add this method:
#import "Reachability.h"
-(NSString *)checkNetworkConnectivity
{
NSString *networkValue;
Reachability *rc = [Reachability reachabilityWithHostName:@"www.stackoverflow.com"];
NetworkStatus internetStatus = [rc currentReachabilityStatus];
if(internetStatus==0)
{
networkValue = @"NoAccess";
}
else if(internetStatus==1)
{
networkValue = @"ReachableViaWiFi";
} else if(internetStatus==2)
{
networkValue = @"ReachableViaWWAN";
}
else
{
networkValue = @"Reachable";
}
return networkValue;
}
Checking if the host is reachable
NSString *netStr = [appDelegate checkNetworkConnectivity];
if([netStr isEqualToString:@"NoAccess"])
{
[appDelegate callNoNetworkAlert];
}
Firstly, unless we see some code, we cannot make sure what you're doing, you're doing the right way. However I will assume you are doing it correctly.
Secondly, you should test what FreeNickname has suggested in his comment. Maybe it's not actually unreachable, and the reachability is acting correctly, when you expect a different response.
Last, but very important, from the Reachability docs :
Note: Reachability cannot tell your application if you can connect to a particular host, only that an interface is available that might allow a connection, and whether that interface is the WWAN.
What it means is that, even though your server might not be returning any responses, Reachability does NOT check that. It only checks if your server is available , such that a packet can be sent. What it does with that packet is of no concern to Reachability. If Reachability is able to transmit the entire packet, it assumes your host is reachable. It will return unreachable iff your server is down, disconnected, or does not exist.
I would like to add that To listen the Network changes at Runtime, you need to listen to the Notifications that tell you that a Network state has been changed.
This is how you can do this :
AppDelegate
file.[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reachabilityChanged:) name:kReachabilityChangedNotification object:nil];
reachabilityChanged
will be called when there is a change in Network status (perhaps connectivity of internet connection or it's disconnection). You can do appropriate handling in reachabilityChanged
eventlike:
- (void) reachabilityChanged:(NSNotification *)note
{
Reachability* reachability = [note object];
if (reachability == self.hostReachability)
{
isHostReachable = YES; //A flag to keep track of connectivity
}
if (reachability == self.internetReachability)
{
isInternetAvailable = YES;
}
if (reachability == self.wifiReachability)
{
isWifiAvailable = YES;
}
//If all are true that means we have host and Internet available
if (isHostReachable && isInternetAvailable && isWifiAvailable)
{
isInternetAvailable = true;
}
}
Hope this will help you.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With