¿Detecta si las llamadas telefónicas de soporte del dispositivo son compatibles o no?

¿Es confiable el siguiente código para ser utilizado para determinar si un dispositivo puede admitir llamadas telefónicas o no? Mi preocupación es si Apple cambia la cadena de iphone a cualquier otra cosa, digamos que deciden tener “iphone 3g”, “iphone 4”, etc.

[[UIDevice currentDevice].model isEqualToString:@"iPhone"] 

El iPhone admite el esquema tel: // URI. Entonces podrías usar:

 [[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@"tel://"]]; 

canOpenURL: verifica explícitamente si hay una aplicación capaz de abrir ese esquema de URL, no que la URL sea correcta. Por lo tanto, no importa que no se especifique ningún número de teléfono. El método devuelve un BOOL, así que verifique que sí o NO.

Eso debería responder literalmente si hay alguna aplicación presente capaz de hacer una llamada telefónica. Por lo tanto, debería estar bien contra cualquier cambio futuro en la segmentación del dispositivo.

Simplemente verificar si un dispositivo “admite” llamadas telefónicas puede no ser la mejor manera de hacer las cosas dependiendo de lo que intente lograr. Créanlo o no, algunas personas usan iPhones viejos sin servicio como si fueran un iPod Touch. A veces las personas no tienen tarjetas SIM instaladas en sus iPhones. En mi aplicación, quería marcar un número de teléfono si el dispositivo de los usuarios era capaz de hacerlo, de lo contrario, quería mostrar el número de teléfono y pedirle al usuario que tome un teléfono y lo marque. Aquí hay una solución que se me ocurrió que funcionó hasta ahora. Siéntete libre de comentar y mejorarlo.

 // You must add the CoreTelephony.framework #import  #import  -(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; } } 

Notarás que verifico si mobileNetworkCode es 65535. En mi prueba, parece que cuando eliminas la tarjeta SIM, el mobileNetworkCode se establece en 65535. No está 100% seguro de por qué.

Necesito asegurarme de que las llamadas telefónicas entrantes no puedan interrumpir las grabaciones que hacen mis clientes, así que les pido que vayan al modo avión pero aún así activen el wifi. El método anterior de AlBeebe no funcionó para mí en iOS 8.1.3, pero si encontré esta solución que debería funcionar en iOS 7 y posteriores:

Debe agregar e importar el CoreTelephony.framework.

 #import  #import  

Defina la propiedad en su clase si desea rastrear cambios

 @property (strong, nonatomic) CTTelephonyNetworkInfo* networkInfo; 

CTTelephonyNetworkInfo :

 self.networkInfo = [[CTTelephonyNetworkInfo alloc] init]; NSLog(@"Initial cell connection: %@", self.networkInfo.currentRadioAccessTechnology); [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(radioAccessChanged) name:CTRadioAccessTechnologyDidChangeNotification object:nil]; 

Y luego recibirá una callback cuando cambie:

 - (void)radioAccessChanged { NSLog(@"Now you're connected via %@", self.networkInfo.currentRadioAccessTechnology); } 

Los valores de currentRadioAccessTechnology se definen en CTTelephonyNetworkInfo.h y obtendrá null / nil cuando no haya conexión de torre de celda.

Aquí es donde lo encontré: http://www.raywenderlich.com/48001/easily-overlooked-new-features-ios-7

Basado en la respuesta de @ the-guardian, he llegado a lo siguiente (en breve):

 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 } 

Este código ha sido probado en un iPad Air 2 Wifi, un iPad Air 2 Simulator, un iPhone 6S Plus, y parece funcionar adecuadamente. Pronto determinará en un iPad con datos móviles.

No creo que su método sea confiable, ya que los nombres de los dispositivos pueden cambiar en el futuro. Si su preocupación es evitar que la aplicación se ejecute en dispositivos que no sean iPhone, puede agregar la ‘telefonía’ al diccionario UIRequiredDeviceCapabilities en su Info.plist. Eso impedirá que dispositivos que no sean el iPhone descarguen tu aplicación de la tienda de aplicaciones.

Alternativamente, si lo que necesita es verificar la conectividad 3G en un momento determinado, puede usar la clase de utilidad Reachability de Apple para preguntar sobre el estado actual de la conexión 3G / WIFI.

Creo que en general es así. Me gustaría una comparación más genérica de cadenas (para estar más seguro en caso de una actualización futura). Lo he usado sin problemas (hasta ahora …).

Si desea estar más seguro de si el dispositivo realmente puede hacer llamadas, también debe aprovechar la API de Core Telephony. La clase CTCarrier puede decirle si realmente puede hacer una llamada en cualquier momento en particular.

Este UIApplication.shared.openURL((URL(string: "tel://\(phoneNumber)")!)) No dirá si tiene SIM o No, esto solo dirá, si el dispositivo tiene opciones para hacer una llamada. Por ejemplo : un iPhone con o sin SIM devolverá verdadero, pero en el iPod Touch siempre devolverá falso, al igual que si un ipad no tiene la opción sim, devolverá falso.

¡Aquí está el código que verifica todo de manera comprensiva! (Usando 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() } 

De esta manera, podemos asegurarnos de que el dispositivo admita llamadas o no.

En caso de que pregunte para llamar a un número de teléfono y mostrar un error en dispositivos que no tienen telefonía:

 void openURL(NSURL *url, void (^ __nullable completionHandler). (BOOL success)) { if (@available(iOS 10.0, *)) { [application openURL:url options:@{} completionHandler:^(BOOL success) { completionHandler(success); }]; } else { if([application openURL:url]) { completionHandler(YES); } else { completionHandler(NO); } } } 

uso

  p97openURL(phoneURL, ^(BOOL success) { if(!success) { show message saying there is no telephony on device } } 

Basado en la respuesta de @ TheGuardian, creo que este podría ser un enfoque más simple:

  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 }