I have this code to start monitoring and when I test with this made-up domain, I'm still getting a status of reachableViaWWAN. Why?
Using AFNetworking version 2.5.0 from cocoapods. I also tried downloading the latest from github and got the same thing.
+ (void)startMonitoring {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
reachabilityManager = [AFNetworkReachabilityManager managerForDomain:#"thisIsNonsense.testSDK.irg"];
});
[reachabilityManager setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status){
switch (status) {
case AFNetworkReachabilityStatusReachableViaWWAN:
NSLog(#"reachable viaWWAN");
break;
case AFNetworkReachabilityStatusReachableViaWiFi:
NSLog(#"reachable viaWiFi");
break;
case AFNetworkReachabilityStatusNotReachable:
NSLog(#"NOT reachable");
break;
default:
NSLog(#"unknown status");
break;
}
}];
[reachabilityManager startMonitoring];
}
If I'm understanding how AFNetworkReachabilityManager is checking, it looks like it's just using SCNetworkReachability which looks like it claims
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.
docs
Related
I'm not found simple solution for this question on SO.
I need simple check logic for my URL and return YES - if available or NO - if not.
What i found:
-(BOOL)connectedToNetwork {
NSURL* url = [[NSURL alloc] initWithString:#"http://google.com/"];
NSData* data = [NSData dataWithContentsOfURL:url];
if (data != nil)
return YES;
return NO;
}
founded this
But i need more correctly answer.
UPD
I found SimplePing by Apple.
UPD1
Found answer on SO Thx all!
UPD2
Better solution SimplePingHelper required SimplePing:
- (void)tapPing {
[SimplePingHelper ping:#"www.google.com"
target:self sel:#selector(pingResult:)];
}
- (void)pingResult:(NSNumber*)success {
if (success.boolValue) {
[self log:#"SUCCESS"];
} else {
[self log:#"FAILURE"];
}
}
The preferred approach is trying to connect, and if that fails due to the host is not reachable check and monitor the network state. See Reachability. If the network state indicates that a host can be possibly reached, try again.
There are also a couple of third party libs that implement a handy API over Apple's Reachability interface.
I use AFNetworking to check reachability.
Pod file: pod "AFNetworking"
You have to include AFNetworkReachabilityManager.h in the file you want to use it.
This is a sample, basic code to check reachability.
// -- Start monitoring network reachability (globally available) -- //
[[AFNetworkReachabilityManager sharedManager] startMonitoring];
[[AFNetworkReachabilityManager sharedManager] setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
NSLog(#"Reachability changed: %#", AFStringFromNetworkReachabilityStatus(status));
switch (status) {
case AFNetworkReachabilityStatusReachableViaWWAN:
case AFNetworkReachabilityStatusReachableViaWiFi:
// -- Reachable -- //
NSLog(#"Reachable");
break;
case AFNetworkReachabilityStatusNotReachable:
default:
// -- Not reachable -- //
NSLog(#"Not Reachable");
break;
}
}];
A valid URL is made of these characters :
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~:/?#[]#!$&'()*+,;=
You simply need to make a String checking function to validate your URL's characters are falling in or out.
Its was simple:
-(BOOL)connectedToNetwork {
NSURL* url = [[NSURL alloc] initWithString:#"http://google.com/"];
NSData* data = [NSData dataWithContentsOfURL:url];
if (data != nil)
return YES;
return NO;
}
founded this
Psuedocode of my current solution:
if (disconnected):
while (disconnected):
check for connection
if (connected):
fetch results
Is there a more idiomatic way to tell when the device goes from being disconnected to establishing an internet connection?
Take a look at Apple's Reachability sample code
You don't have to investigate detailed implementation of Reachability.m. You can just use it as a library.
Absolutely! This is what SCNetworkReachability is for!
Unfortunately, people tend to use it incorrectly. What you are describing would be a correct use case for it.
Attempt a connection normally.
If it fails with NSURLErrorNotConnectedToInternet:
Use SCNetworkReachability to monitor the device network configuration for changes
When the network configuration moves to a state that indicates packets can again leave the device, your application will be notified and you can make connections again.
What you should NOT do is try to use SCNetworkReachability to see if the device is connected before connecting. This is not recommended for many reasons. The SCNetworkReachability API can tell you when it is, or is not, possible for packets to leave the device. It can't tell you if the thing you're connecting to is down, DNS isn't working, etc.
The Apple sample projects MVCNetworking and Reachability demonstrate use of the SCNetworkReachability API.
In practice, this looks like....
In your connection error handling:
if ([[error domain] isEqualToString:NSURLErrorDomain]){
NSURL *failingURL = [[error userInfo] valueForKey:NSURLErrorFailingURLErrorKey];
switch ([error code]){
case NSURLErrorNotConnectedToInternet:
[self beginObservingReachabilityStatusForHost:[failingURL host]];
break;
default:
break;
}
}
The beginObservingReachabilityStatusForHost: and endObsvervingReachabilityStatusForHost: methods:
- (void) beginObservingReachabilityStatusForHost:(NSString *)host {
SCNetworkReachabilityRef reachabilityRef = NULL;
void (^callbackBlock)(SCNetworkReachabilityFlags) = ^(SCNetworkReachabilityFlags flags) {
BOOL reachable = (flags & kSCNetworkReachabilityFlagsReachable) != 0;
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
[self host:host didBecomeReachable:reachable];
}];
};
SCNetworkReachabilityContext context = {
.version = 0,
.info = (void *)CFBridgingRetain(callbackBlock),
.release = CFRelease
};
if ([host length] > 0){
reachabilityRef = SCNetworkReachabilityCreateWithName(kCFAllocatorDefault, [host UTF8String]);
if (SCNetworkReachabilitySetCallback(reachabilityRef, ReachabilityCallback, &context)){
if (!SCNetworkReachabilitySetDispatchQueue(reachabilityRef, [self scNetworkQueue]) ){
// Remove our callback if we can't use the queue
SCNetworkReachabilitySetCallback(reachabilityRef, NULL, NULL);
}
[self setCurrentReachability:reachabilityRef];
}
}
}
- (void) endObsvervingReachabilityStatusForHost:(NSString *)host {
// Un-set the dispatch queue
if (!SCNetworkReachabilitySetDispatchQueue([self currentReachability], NULL) ){
}
SCNetworkReachabilitySetCallback([self currentReachability], NULL, NULL);
}
The C callback that wraps our block:
static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkConnectionFlags flags, void* info) {
void (^callbackBlock)(SCNetworkReachabilityFlags) = (__bridge id)info;
callbackBlock(flags);
}
And the method that the block calls to do something when reachability changes:
- (void) host:(NSString *)host didBecomeReachable:(BOOL)reachable {
// Update your UI to indicate reachability status here
if (reachable){
[self endObsvervingReachabilityStatusForHost:nil];
}
}
Obviously to use the above you need a serial dispatch queue and a way to hold on to the SCNetworkReachabilityRef for later cancellation when you're done.
I need to check for reachability for a socket connection in my application. I have gone through apple's sample code and few examples I could find from SO and other websites but I'm out of luck as I do not get any response. Here's a sample code I'm trying.
My requirement is simply to verify connectivity to myhost:port which is a socket connection. myhost is an address from dyndns.org
struct sockaddr_in server_address;
server_address.sin_len = sizeof(server_address);
server_address.sin_family = AF_INET;
server_address.sin_port = htons(1234);
server_address.sin_addr.s_addr = inet_addr("host-from-dyndns.org");
Reachability *reachability = [Reachability reachabilityWithAddress:&server_address];
__weak Reachability *weakReachability = reachability;
reachability.reachableBlock = ^(Reachability*reach)
{
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(#"REACHABLE!");
});
[weakReachability stopNotifier];
};
reachability.unreachableBlock = ^(Reachability*reach)
{
NSLog(#"UNREACHABLE!");
[weakReachability stopNotifier];
};
[reachability startNotifier];
After few failed attempts of meddling with with reachability classes, I gave up and used a temporary asynchronous socket connection created on demand to verify the connection. It works as expected and is built on top of gcd. Also I found the AsyncSocket by Robbie Hanson (https://github.com/robbiehanson/CocoaAsyncSocket) to be quite helpful while implementing for my requirement.
I seem to have trouble understanding how to best deal with the BFTask (Bolts framework) return object for several AWS SDK iOS v2 methods. I am trying to get the name of the region my bucket resides in. Could anyone suggest how to do that given the locationConstraint information I am successfully receiving from the following code? Or is there a generic way to understand what the task.result object contains?
AWSS3TransferManagerUploadRequest *uploadRequest = [AWSS3TransferManagerUploadRequest new];
AWSS3 *myS3 = [[AWSS3 alloc] initWithConfiguration:self.configurationS3];
AWSS3GetBucketLocationRequest *locReq = [AWSS3GetBucketLocationRequest new];
locReq.bucket=#"testAWS";
[[myS3 getBucketLocation:locReq] continueWithExecutor:[BFExecutor mainThreadExecutor] withBlock:^id(BFTask *task) {
if(task.error != nil){
NSLog(#"%s Location not found: [%#]",__PRETTY_FUNCTION__, task.error);
} else {
NSLog(#"Location found: [%#] - %li", task.result, [task.result locationConstraint]);
}
return nil;
}];
Also, if anyone has suggestions for tutorials/examples for best understanding BFTask that would be helpful. Thanks for your help. Cheers, Trond
ps. I also asked this question on AWS support site.
Here is the code snippet to determine the bucket location:
AWSS3 *s3 = [AWSS3 defaultS3];
AWSS3GetBucketLocationRequest *getBucketLocationRequest = [AWSS3GetBucketLocationRequest new];
getBucketLocationRequest.bucket = testBucketNameGeneral;
[[s3 getBucketLocation:getBucketLocationRequest] continueWithBlock:^id(BFTask *task) {
if(task.error != nil){
XCTAssertNil(task.error, #"The request failed. error: [%#]", task.error);
}
AWSS3GetBucketLocationOutput *getBucketLocationOutput = task.result;
XCTAssertEqual(getBucketLocationOutput.locationConstraint, AWSS3BucketLocationConstraintBlank);
switch (getBucketLocationOutput.locationConstraint) {
case AWSS3BucketLocationConstraintBlank:
NSLog(#"Classic Region");
break;
case AWSS3BucketLocationConstraintEU:
NSLog(#"EU");
break;
case AWSS3BucketLocationConstraintEUWest1:
NSLog(#"eu-west-1");
break;
case AWSS3BucketLocationConstraintUSWest1:
NSLog(#"us-west-1");
break;
case AWSS3BucketLocationConstraintUSWest2:
NSLog(#"us-west-2");
break;
case AWSS3BucketLocationConstraintAPSoutheast1:
NSLog(#"ap-southeast-1");
break;
case AWSS3BucketLocationConstraintAPSoutheast2:
NSLog(#"ap-southeast-2");
break;
case AWSS3BucketLocationConstraintAPNortheast1:
NSLog(#"ap-northeast-1");
case AWSS3BucketLocationConstraintSAEast1:
NSLog(#"sa-east-1");
break;
case AWSS3BucketLocationConstraintUnknown:
default:
// Error
break;
}
return nil;
}];
However, there is a bug in the SDK, and getBucketLocationOutput.locationConstraint is always AWSS3BucketLocationConstraintUnknown. We are working on the fix right now.
The Bolts-iOS GitHub repo has a pretty good instructions on how to use Bolts.
Hope this helps,
Update
The AWS Mobile SDK for iOS 2.0.4 has been released. The update fixes the issue, and now it returns the correct locationConstraint.
I started using AFNetworking's reachability manager instead of Apple's Reachability class but it doesn't work. Its reachability status is AFNetworkReachabilityStatusUnknown despite the internet connection is turned on on the device. This is my code:
reachabilityManager = [AFNetworkReachabilityManager sharedManager];
[reachabilityManager startMonitoring];
[reachabilityManager setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status){
NSLog(#"Current status %#", reachabilityManager.localizedNetworkReachabilityStatusString);
}];
I put NSLog inside the block but i don't mean to say that i see results there. Actually the block is never called (while my device has normal internet connection). I just check the status before performing my first network request and i see it is -1 i.e. unknown. What's wrong?
This is how i check reachability status:
- (BOOL)connected
{
#if TARGET_IPHONE_SIMULATOR
return YES;
#else
NSLog(#"Status %d", reachabilityManager.networkReachabilityStatus);
return reachabilityManager.reachable;
#endif
}