Is the below code reliable to be used to determine whether a device can support phone calls or not? My concern is if apple changes the iphone string to anything else let\'s
Based on @the-guardian's response, I have come up with the following (in swift):
import CoreTelephony
/**
Indicates if the device can make a phone call.
- seealso: [Source](http://stackoverflow.com/a/11595365/3643020)
- returns: `true` if the device can make a phone call. `false` if not.
*/
final class func canMakePhoneCall() -> Bool {
guard let url = URL(string: "tel://") else {
return false
}
let mobileNetworkCode = CTTelephonyNetworkInfo().subscriberCellularProvider?.mobileNetworkCode
let isInvalidNetworkCode = mobileNetworkCode == nil
|| mobileNetworkCode?.count == 0
|| mobileNetworkCode == "65535"
return UIApplication.shared.canOpenURL(url)
&& !isInvalidNetworkCode
}
This code has been tested on an iPad Air 2 Wifi, an iPad Air 2 Simulator, an iPhone 6S Plus, and seems to work appropriately. Will determine on an iPad with mobile data soon.
This UIApplication.shared.openURL((URL(string: "tel://\(phoneNumber)")!))
will not say if it has SIM or Not this will just say, if the device has options to make a call. For example : A iPhone with or without SIM it'll return true, but in iPod Touch it will always return false, like wise if an ipad doesn't have sim option it will return false.
Here is the code that checks everything comprehensively ! (Using Swift 3.0)
if UIApplication.shared.canOpenURL(URL(string: "tel://\(phoneNumber)")!) {
var networkInfo = CTTelephonyNetworkInfo()
var carrier: CTCarrier? = networkInfo.subscriberCellularProvider
var code: String? = carrier?.mobileNetworkCode
if (code != nil) {
UIApplication.shared.openURL((URL(string: "tel://\(phoneNumber)")!))
}
else {
var alert = UIAlertView(title: "Alert", message: "No SIM Inserted", delegate: nil, cancelButtonTitle: "ok", otherButtonTitles: "")
alert.show()
}
}
else {
var alert = UIAlertView(title: "Alert", message: "Device does not support phone calls.", delegate: nil, cancelButtonTitle: "ok", otherButtonTitles: "")
alert.show()
}
By this way, we can make sure, device supports calling or not.
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
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.
I don't think your method is reliable, as device names may change in the future. If your concern is to prevent the app from running on non-iPhone devices, you may add the 'telephony' to the UIRequiredDeviceCapabilities dictionary in your Info.plist. That will disallow devices other than the iPhone to download your app from the App Store.
Alternatively, if what you need is checking for 3G connectivity at a particular moment, you can use Apple's Reachability utility class to ask about current 3G/WIFI connection status.
Based on @TheGuardian's answer, I think this might be a simpler approach:
private final func canMakePhoneCall() -> Bool {
guard UIDevice.currentDevice().userInterfaceIdiom == UIUserInterfaceIdiom.Phone else {
return false
}
let mobileNetworkCode = CTTelephonyNetworkInfo().subscriberCellularProvider?.mobileNetworkCode
let isInvalidNetworkCode = mobileNetworkCode == nil || mobileNetworkCode?.characters.count <= 0
|| mobileNetworkCode == "65535"
//When sim card is removed, the Code is 65535
return !isInvalidNetworkCode
}