Detecting whether or not device support phone calls?
Solution 1:
The iPhone supports the tel:// URI scheme. So you could use:
[[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@"tel://"]];
canOpenURL: explicitly checks whether there's an application capable of opening that URL scheme, not that the URL is correct. So it doesn't matter that no phone number is specified. The method returns a BOOL, so check that for YES or NO.
That should literally answer whether there's any application present capable of making a telephone call. So it should be okay against any future changes in device segmentation.
Solution 2:
Simply checking if a device "supports" phone calls might not be the best way to go about things depending on what your trying to accomplish. Believe it or not, some people use old iPhones without service as if they were an iPod Touch. Sometimes people don't have SIM cards installed in their iPhones. In my app I wanted to dial a phone number if the users device was able to, otherwise I wanted to display the phone number and prompt the user to grab a phone and dial it. Here is a solution I came up with that has worked so far. Feel free to comment and improve it.
// You must add the CoreTelephony.framework
#import <CoreTelephony/CTTelephonyNetworkInfo.h>
#import <CoreTelephony/CTCarrier.h>
-(bool)canDevicePlaceAPhoneCall {
/*
Returns YES if the device can place a phone call
*/
// Check if the device can place a phone call
if ([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@"tel://"]]) {
// Device supports phone calls, lets confirm it can place one right now
CTTelephonyNetworkInfo *netInfo = [[[CTTelephonyNetworkInfo alloc] init] autorelease];
CTCarrier *carrier = [netInfo subscriberCellularProvider];
NSString *mnc = [carrier mobileNetworkCode];
if (([mnc length] == 0) || ([mnc isEqualToString:@"65535"])) {
// Device cannot place a call at this time. SIM might be removed.
return NO;
} else {
// Device can place a phone call
return YES;
}
} else {
// Device does not support phone calls
return NO;
}
}
You'll notice I check if the mobileNetworkCode is 65535. In my testing, it appears that when you remove the SIM card, then the mobileNetworkCode is set to 65535. Not 100% sure why that is.
Solution 3:
I need to make sure that incoming phone calls cannot interrupt the recordings that my clients make, so I prompt them to go to airplane mode but still turn on wifi. The method above from AlBeebe didn't work for me on iOS 8.1.3, but If found this solution which should work in iOS 7 and later:
You must add and import the CoreTelephony.framework.
#import <CoreTelephony/CTTelephonyNetworkInfo.h>
#import <CoreTelephony/CTCarrier.h>
Define the property on your class if you want to track changes
@property (strong, nonatomic) CTTelephonyNetworkInfo* networkInfo;
Init the CTTelephonyNetworkInfo
:
self.networkInfo = [[CTTelephonyNetworkInfo alloc] init];
NSLog(@"Initial cell connection: %@", self.networkInfo.currentRadioAccessTechnology);
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(radioAccessChanged) name:CTRadioAccessTechnologyDidChangeNotification object:nil];
And then you will receive callback when it changes:
- (void)radioAccessChanged {
NSLog(@"Now you're connected via %@", self.networkInfo.currentRadioAccessTechnology);
}
The values for currentRadioAccessTechnology
are defined in
CTTelephonyNetworkInfo.h and you'll get back null / nil when there is no cell tower connection.
This is where I found it: http://www.raywenderlich.com/48001/easily-overlooked-new-features-ios-7