Has anyone found a halfway decent guide to implementing Reachability on iOS?
I have implemented Reachability like this.
Download https://developer.apple.com/library/content/samplecode/Reachability/Introduction/Intro.html and add Reachability.h and .m to your project. Add the SystemConfiguration framework to your project. #import "Reachability.h" where you want to use it. Use this code.
-(BOOL)reachable {
Reachability *r = [Reachability reachabilityWithHostName:#"enbr.co.cc"];
NetworkStatus internetStatus = [r currentReachabilityStatus];
if(internetStatus == NotReachable) {
return NO;
}
return YES;
}
When you want to check for reachability...
if ([self reachable]) {
NSLog(#"Reachable");
}
else {
NSLog(#"Not Reachable");
}
Here is the example project that I made. http://dl.dropbox.com/u/3656129/ReachabilityExample.zip
I think the best way to check the availability of host address is by checking the results of NSURL Request.
NSURLRequest *theRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:reqURL]];
NSURLResponse *resp = nil;
NSError *error = nil;
NSData *response = [NSURLConnection sendSynchronousRequest: theRequest returningResponse: &resp error: &error];
NSString *responseString = [[NSString alloc] initWithData:response encoding:NSUTF8StringEncoding];
Using this bit of Code, if your device cannot reach the provided URL, it provides some output to the error variable, if it can access the URL Request, error is Nil.
Reachability gives a positive output even if you URL packets can route out from your device and never reach the host server.
This question seems to have only obsolete answers. Since iOS 12 we have NWPathMonitor so you should at least look into that as well.
Related
When I tried to make a call "name" to "name" via twilio I had this error :
pjsua_call.c .Dialog creation failed: Invalid URI (PJSIP_EINVALIDURI)
As I followed the twilio tutorial I have no idea why this error happen.
Any clue ?
Here the way I got the token (should be ok)
- (void)getTwilioToken{
NSString *urlString = [NSString stringWithFormat:#"http://foo.herokuapp.com/token?client=%#", [[[Utils getUserCredential] componentsSeparatedByString:#"|"] objectAtIndex:1]];
NSURL *url = [NSURL URLWithString:urlString];
NSError *error = nil;
NSString *token = [NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:&error];
if(token == nil){
NSLog(#"Error retrieving token: %#", [error localizedDescription]);
} else {
_phone = [[TCDevice alloc] initWithCapabilityToken:token delegate:self];
}
}
Here the code used to make the call :
-(IBAction)callResponder:(id)sender{
NSIndexPath *indexPath = [self.tableView indexPathForCell:sender];
NSString *responderEmail = [[self.responders objectAtIndex:indexPath.row] email];
NSDictionary *params = #{#"To": responderEmail};
//check if we can make an outgoing call and attempt a connection
NSNumber* hasOutgoing = [_phone.capabilities objectForKey:TCDeviceCapabilityOutgoingKey];
if ( [hasOutgoing boolValue] == YES ){
//Disconnect if we've already got a connection in progress
if(_connection){
[_connection disconnect];
}
_connection = [_phone connect:params delegate:self];
[_connection retain];
}
}
I also ran into this same issue myself. The problem pertained to how I set permissions for the Twilio token (using their Javascript API):
var capability = new twilio.Capability(twilioAccountSid, twilioAuthToken);
capability.allowClientOutgoing(twilioAppSid);
capability.allowClientIncoming(); // this is the problematic line
After I removed the (apparently incorrect) incoming permission setting line my device completed the call perfectly.
I am working on iOS application where I am using Twilio SDK to manage client calling through device. To implement this i am using hello monkey demo application which i have successfully imported in Xcode.
After initial setup i am able to establish connection successfully but receiving delegate is no longer working. I have gone through complete twilio documentation but no success. Please suggest any alternative or solution ASAP.
Here is my code of Hello Monkey sample project
- (void)viewDidLoad
{
NSLog(#"CLINT ID----------------------- %#",name);
//check out https://github.com/twilio/mobile-quickstart to get a server up quickly
NSString *urlString = [NSString stringWithFormat:#"https://testdemo786.herokuapp.com/token?client=%#", name];
NSURL *url = [NSURL URLWithString:urlString];
NSError *error = nil;
NSString *token = [NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:&error];
if (token == nil) {
NSLog(#"Error retrieving token: %#", [error localizedDescription]);
} else {
_phone = [[TCDevice alloc] initWithCapabilityToken:token delegate:self];
}
}
- (IBAction)dialButtonPressed:(id)sender
{
NSString *to;
if ([name isEqualToString:#"jenny"]) {
to=#"client:tommy";
}
else
{
to=#"client:jenny";
}
to=#"4nmf5j";
NSLog(#"TO---------------------%#",to);
NSDictionary *params = #{#"To": to};
_connection = [_phone connect:params delegate:nil];
}
- (IBAction)hangupButtonPressed:(id)sender
{
[_connection disconnect];
}
- (void)device:(TCDevice *)device didReceiveIncomingConnection:(TCConnection *)connection
{
NSLog(#"Incoming connection from: %#", [connection parameters][#"From"]);
if (device.state == TCDeviceStateBusy) {
[connection reject];
} else {
[connection accept];
_connection = connection;
}
}
-(void)connection:(TCConnection*)connection didFailWithError: (NSError*)error{
NSLog(#"Connection failed with error : %#", error);
}
-(void)connectionDidStartConnecting:(TCConnection*)connection{
NSLog(#"connection started");
}
-(void)connectionDidDisconnect:(TCConnection*)connection{
NSLog(#"connection disconnected");
}
-(void)connectionDidConnect:(TCConnection*)connection{
NSLog(#"connected");
}
- (void)deviceDidStartListeningForIncomingConnections: (TCDevice*)device
{
NSLog(#"Device: %# deviceDidStartListeningForIncomingConnections", device);
}
- (void)device:(TCDevice *)device didStopListeningForIncomingConnections:(NSError *)error
{
NSLog(#"Device: %# didStopListeningForIncomingConnections: %#", device, error);
}
Twilio evangelist here.
Its a bit hard to tell from the code you included, which does look correct to me.
Here are a couple of things to check:
Did you add the TCDeviceDelegate as a protocol on your interface:
#interface FooViewController() <TCDeviceDelegate>
Are you sure you passing the correct client name to the connect method, and that the TwiML being returned from your TwiML Apps Voice Request URL is including that name properly?
You could check this by looking at the Twilio Monitor to see if Twilio logged any errors when retrieving or parsing your TwiML. You can also check your Twilio call logs to see what Twilio says the outcome of the inbound and outbound call legs were.
Hope that helps.
did you set the delegate to self?
_device = [[TCDevice alloc] initWithCapabilityToken:capabilityToken delegate:self];
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
I have a simple Reachability code that returns if I can connect to a server or not:
-(BOOL)checkConnectionForHost:(NSString*)host{
_checkStatus = [Reachability reachabilityWithHostname:host];
NetworkStatus networkStatus = [_checkStatus currentReachabilityStatus];
return networkStatus != NotReachable;
}
I tested it by adding stuff like google.com, and it works fine. However, if I type in a junk number like 8170319837018, and call this function, it still return TRUE. However, if I add any char to it, like 8170319837018a, it will return FALSE, as it should. Am I calling the wrong method on Reachability? Do I have to check if the string is a URL or an IP address?
Thanks!
Reachability has some issues. If You are connected to wifi it will return it's rechable but doesn't actually ping the host. Better way would be to use NSURLCONNECTION to ping the server directly
+ (BOOL)pingURL:(NSString *)url
{
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:url] cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:1];
NSURLResponse *response = nil;
NSError *error = nil;
[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
NSLog(#"response %d", [(NSHTTPURLResponse *)response statusCode]);
if ([(NSHTTPURLResponse *)response statusCode] == 200) {
return YES;
}
return NO;
}
I think this is because the internal reachability flags are long numbers. So when you pass 8170319837018 the [_checkStatus currentReachabilityStatus] must be returning some number which is not equal to NotReachable(0) and that's why it must be returning TRUE. What you can instead do is to check against each type of reachability like below:
-(BOOL)checkConnectionForHost:(NSString*)host{
_checkStatus = [Reachability reachabilityWithHostname:host];
NetworkStatus networkStatus = [_checkStatus currentReachabilityStatus];
return (networkStatus == ReachableViaWiFi) || (networkStatus == ReachableViaWWAN);
}
I am making an jsonstring. When i execute it, it works when i do it in my browser. I do this by logging the exact url and copy it in the browser. Than i get the HTTP Get that i want, but in the iPhone i only get a Bad Login.
- (IBAction)getDown:(id)sender { //perform get request
NSLog(#"beginnen met versturen");
//NSString * _barCode = [[NSUserDefaults standardUserDefaults] objectForKey:#"phoneNumber"];
//build up the request that is to be sent to the server
//NSString*jsonString = [[NSString alloc] initWithFormat:#"{\"barcode\":\"%#\"}", _barCode];
NSString*jsonString = [[NSString alloc] initWithFormat:#"{\"barcode\":\"123456\"}"];
NSString *str = [NSString stringWithFormat: #"http://server.nl/scan.php?data=%#",jsonString];
NSLog(#"%#", str);
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:str]];
NSLog(#"url: %#", request);
[request setHTTPMethod:#"GET"];
// [request addValue:#"getValues" forHTTPHeaderField:#"METHOD"]; //selects what task the server will perform
NSLog(#"met value: %#", request);
//initialize an NSURLConnection with the request
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
if(!connection){
NSLog(#"Connection Failed");
}
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{ // executed when the connection receives data
receivedData = data;
/* NOTE: if you are working with large data , it may be better to set recievedData as NSMutableData
and use [receivedData append:Data] here, in this event you should also set recievedData to nil
when you are done working with it or any new data received could end up just appending to the
last message received*/
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{ //executed when the connection fails
NSLog(#"Connection failed with error: %#",error.localizedDescription);
}
-(void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge{
/*This message is sent when there is an authentication challenge ,our server does not have this requirement so we do not need to handle that here*/
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection{
NSLog(#"Request Complete,recieved %d bytes of data",receivedData.length);
//[self.delegate requestReturnedData:receivedData];//send the data to the delegate
NSData *data = receivedData;
NSDictionary *dictionary = [NSDictionary dictionaryWithJSONData:data];
NSLog(#"%#",dictionary.JSONString ); ; // set the textview to the raw string value of the data recieved
NSString *value1 = [dictionary objectForKey:#"barcode"];
NSLog(#"%#", value1);
NSString *value2 = [dictionary objectForKey:#"product"];
NSLog(#"%#",dictionary);
NSLog(#"%#", value2);
}
Here's the log:
2013-01-10 16:31:46.550 Scanner[14875:907] http://server.nl/scan.php?data={"barcode":"123456"}
2013-01-10 16:31:46.551 Scanner[14875:907] url: <NSMutableURLRequest (null)>
2013-01-10 16:31:46.553 Scanner[14875:907] met value: <NSMutableURLRequest (null)>
**2013-01-10 16:31:46.556 Scanner[14875:907] Connection failed with error: bad URL**
When i delete the complete json from the string i get no bad url. So there might be the problem. Anyone know what i am doing wrong?
You need to encode it, before perfoming an URL request.
Best and most elegant solution would be adding a category over NSString for example, something like this:
- (NSString*)URLEncode {
// Should not be encoded:-_.
return [(NSString *)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef)self, NULL, CFSTR(";/?:#&=+$,!*'()<>#%\"{}|\\^[]`~"), kCFStringEncodingUTF8) autorelease];
//
}
And when you make the request:
NSString *str = [NSString stringWithFormat: #"http://server.nl/scan.php?data=%#",jsonString];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:[str URLEncode]];
If you don't want to use additional files (even thought that would be recommended), add this method to your class:
- (NSString*)URLEncode:(NSString )yourURL {
// Should not be encoded:-_.
return [(NSString *)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef)self, NULL, CFSTR(";/?:#&=+$,!'()<>#%\"{}|\\^[]`~"), kCFStringEncodingUTF8) autorelease];
}
and use
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:[self URLEncode:str]];
I don't have much information right now, I apologize, I'm in a bit of a hurry and just saw your question. But I saw your question and I remember working on a project which was essentially an HTML-based remote control for the iphone, and when the user clicked on some of the buttons for the remote, it followed the urls that opened up identical pages but had server-side code to instruct the server to pause, play, stop, etc... I DO remember that the iPhone had a bug that caused it to not be able to parse all of my URLs, even though they were correctly formatted and worked on a desktop client. That is why I switched over to POST requests (where user clicks instead activated javascript functions that set hidden form variables and then submitted forms rather than directly navigating to long URLS). Anyways, I know this may not directly apply to you, but the point is that I did find a bug in the iPhone's URL parsing, so it might not be your fault. I'll look up any new information I can find a little later. Good luck.