Le code ci-dessous est-il fiable pour déterminer si un périphérique peut prendre en charge les appels téléphoniques ou non? etc.
[[UIDevice currentDevice].model isEqualToString:@"iPhone"]
L'iPhone prend en charge le schéma tel: // URI. Pour que vous puissiez utiliser:
[[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@"tel://"]];
canOpenURL: vérifie explicitement s'il existe une application capable d'ouvrir ce schéma d'URL, pas si l'URL est correcte. Donc, peu importe qu'aucun numéro de téléphone ne soit spécifié. La méthode retourne un BOOL, vérifiez donc que pour OUI ou NON.
Cela devrait littéralement indiquer s'il existe une application capable de passer un appel téléphonique. Cela devrait donc convenir à toute modification future de la segmentation des périphériques.
Vérifier simplement si un appareil "prend en charge" les appels téléphoniques n'est peut-être pas la meilleure façon de procéder, en fonction de ce que vous essayez d'accomplir. Croyez-le ou non, certaines personnes utilisent les anciens iPhones sans service, comme s'il s'agissait d'un iPod Touch. Parfois, les gens n'ont pas de carte SIM installée sur leur iPhone. Dans mon application, je voulais composer un numéro de téléphone si le périphérique de l'utilisateur le permettait. Sinon, je voulais afficher le numéro de téléphone et demander à l'utilisateur de saisir un téléphone et de le composer. Voici une solution que j'ai trouvée qui a fonctionné jusqu'à présent. N'hésitez pas à commenter et à l'améliorer.
// 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;
}
}
Vous remarquerez que je vérifie si le code mobileNetworkCode est 65535. Lors de mes tests, il apparaît que lorsque vous retirez la carte SIM, le code mobileNetworkCode est défini sur 65535. Vous ne savez pas tout à fait pourquoi.
Je dois m'assurer que les appels téléphoniques entrants ne peuvent pas interrompre les enregistrements de mes clients. Je les invite donc à passer en mode avion tout en continuant d'activer le wifi. La méthode ci-dessus d'AlBeebe ne fonctionnait pas pour moi sur iOS 8.1.3, mais si cette solution a été trouvée, elle devrait fonctionner sous iOS 7 et versions ultérieures:
Vous devez ajouter et importer le fichier CoreTelephony.framework.
#import <CoreTelephony/CTTelephonyNetworkInfo.h>
#import <CoreTelephony/CTCarrier.h>
Définissez la propriété sur votre classe si vous souhaitez suivre les modifications
@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];
Et puis vous recevrez un rappel lorsque cela changera:
- (void)radioAccessChanged {
NSLog(@"Now you're connected via %@", self.networkInfo.currentRadioAccessTechnology);
}
Les valeurs de currentRadioAccessTechnology
sont définies dans CTTelephonyNetworkInfo.h et vous obtiendrez null/nil en l'absence de connexion de tour de cellules.
C'est là que je l'ai trouvé: http://www.raywenderlich.com/48001/easily-overlooked-new-features-ios-7
Sur la base de la réponse de @ the-guardian, j'ai proposé ce qui suit (dans 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
}
Ce code a été testé sur un iPad Air 2 Wifi, un simulateur iPad Air 2, un iPhone 6S Plus et semble fonctionner correctement. Déterminera sur un iPad avec des données mobiles bientôt.
Ce UIApplication.shared.openURL((URL(string: "tel://\(phoneNumber)")!))
ne dira pas s'il possède une carte SIM ou pas, cela dira simplement si l'appareil dispose d'options pour passer un appel. Par exemple : Un iPhone avec ou sans SIM, il retournera vrai, mais dans iPod Touch, il retournera toujours faux, comme si un ipad n'avait pas d'option sim, il retournerait faux.
Voici le code qui vérifie tout de manière exhaustive! (Utilisation de 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 cette manière, nous pouvons nous assurer que votre appareil prend en charge l’appel ou non.
Je ne pense pas que votre méthode soit fiable, car les noms de périphériques peuvent changer à l'avenir. Si vous souhaitez empêcher l'application de s'exécuter sur des appareils autres que l'iPhone, vous pouvez ajouter la «téléphonie» au dictionnaire UIRequiredDeviceCapabilities dans votre Info.plist. Cela interdira aux appareils autres que l'iPhone de télécharger votre application depuis l'App Store.
Sinon, si vous avez besoin de vérifier la connectivité 3G à un moment donné, vous pouvez utiliser la classe d'utilitaires Accessibilité d'Apple pour connaître l'état actuel de la connexion 3G/WIFI.
Je pense que c'est généralement le cas. Je préférerais une comparaison de chaînes plus générique (juste pour être plus en sécurité en cas de mise à jour future). Je l'ai utilisé sans problèmes (jusqu'à présent ...).
Si vous voulez être plus sûr de savoir si le périphérique peut effectivement passer des appels, vous devez également tirer parti de l'API Core Telephony. La classe CTCarrier peut vous dire si vous pouvez passer un appel à un moment donné.
Si vous demandez pour appeler un numéro de téléphone et afficher une erreur sur les appareils sans téléphonie:
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);
}
}
}
usage
p97openURL(phoneURL, ^(BOOL success) {
if(!success) {
show message saying there is no telephony on device
}
}