Определяет, поддерживает ли устройство телефонные звонки? - PullRequest
45 голосов
/ 23 февраля 2011

Надежен ли приведенный ниже код для определения, может ли устройство поддерживать телефонные звонки или нет?Меня беспокоит, если Apple изменит строку iphone на что-то еще, скажем, они решат иметь «iphone 3g», «iphone 4» и т. Д.

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

Ответы [ 9 ]

97 голосов
/ 23 февраля 2011

iPhone поддерживает схему URI tel: //. Таким образом, вы можете использовать:

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

canOpenURL: явно проверяет, есть ли приложение, способное открыть эту схему URL, а не то, что URL правильный. Поэтому не имеет значения, что номер телефона не указан. Метод возвращает BOOL, поэтому проверьте это для ДА или НЕТ.

Это должно буквально ответить на вопрос, есть ли какое-либо приложение, способное сделать телефонный звонок. Так что это должно быть хорошо против любых будущих изменений в сегментации устройства.

64 голосов
/ 21 июля 2012

Простая проверка того, поддерживает ли устройство телефонные звонки, может быть не лучшим способом решения проблем, в зависимости от того, что вы пытаетесь выполнить. Верьте или нет, некоторые люди используют старые айфоны без обслуживания, как если бы они были iPod Touch. Иногда люди не имеют SIM-карты, установленные в их iPhone. В моем приложении я хотел набрать телефонный номер, если устройство пользователя было в состоянии, в противном случае я хотел отобразить номер телефона и предложить пользователю взять телефон и набрать его. Вот решение, которое я придумала, которое сработало до сих пор. Не стесняйтесь комментировать и улучшать его.

// 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;
    }
}

Вы заметите, что я проверяю, является ли mobileNetworkCode 65535. В моем тестировании выяснилось, что при извлечении SIM-карты mobileNetworkCode устанавливается на 65535. Не уверен на 100%, почему это так.

11 голосов
/ 06 февраля 2015

Мне нужно убедиться, что входящие телефонные звонки не могут прервать записи, которые делают мои клиенты, поэтому я предлагаю им перейти в режим полета, но при этом включить Wi-Fi.Описанный выше метод от AlBeebe не работал для меня на iOS 8.1.3, но если было найдено это решение, которое должно работать в iOS 7 и более поздних версиях:

Вы должны добавить и импортировать CoreTelephony.framework.

#import <CoreTelephony/CTTelephonyNetworkInfo.h>
#import <CoreTelephony/CTCarrier.h>

Определите свойство в вашем классе, если вы хотите отслеживать изменения

@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];

И тогда вы получите обратный вызов, когда оноизменения:

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

Значения для currentRadioAccessTechnology определены в CTTelephonyNetworkInfo.h, и вы получите значение null / nil, если нет соединения с вышкой сотовой связи.

Здесь янашел это: http://www.raywenderlich.com/48001/easily-overlooked-new-features-ios-7

10 голосов
/ 31 мая 2016

Основываясь на ответе @ the-guardian, я придумал следующее (по-быстрому):

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
}

Этот код был протестирован на iPad Air 2 Wifi, iPad Air 2 Simulator, iPhone 6S Plus и, похоже, работает надлежащим образом. Скоро определится на iPad с мобильными данными.

2 голосов
/ 16 марта 2017

Этот UIApplication.shared.openURL((URL(string: "tel://\(phoneNumber)")!)) не скажет, есть ли у него SIM-карта или нет. Он просто скажет, есть ли у устройства опции для совершения вызова. Например, : iPhone с SIM-картой или без нее будет возвращать значение true, но в iPod Touch он всегда будет возвращать значение false, как и в случае, если на ipad нет опции sim, он возвращает значение false.

Вот код, который все проверяет всесторонне! (Используя 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()
        }

Таким образом, мы можем убедиться, что устройство поддерживает вызовы или нет.

2 голосов
/ 23 февраля 2011

Я думаю, что в целом это так. Я бы пошел для более общего сравнения строк (просто, чтобы быть более безопасным в случае будущего обновления). Я использовал это без проблем (пока ...).

Если вы хотите быть более уверенным в том, может ли устройство на самом деле совершать вызовы, вам также следует воспользоваться API-интерфейсом Core Telephony API. Класс CTCarrier может сообщить вам, действительно ли вы можете сделать вызов в любой конкретный момент.

2 голосов
/ 23 февраля 2011

Я не думаю, что ваш метод надежен, поскольку имена устройств могут измениться в будущем. Если ваша задача - не запускать приложение на устройствах, отличных от iPhone, вы можете добавить «телефонию» в словарь UIRequiredDeviceCapabilities в вашем Info.plist. Это запретит другим устройствам, кроме iPhone, загружать ваше приложение из App Store.

В качестве альтернативы, если вам нужно проверить наличие соединения 3G в определенный момент, вы можете воспользоваться утилитой Apple Reachability , чтобы узнать о текущем состоянии соединения 3G / WIFI.

0 голосов
/ 16 октября 2017

В случае, если вы просите, чтобы позвонить по номеру телефона и показать ошибка на устройствах без телефонии:

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);
        }
    }
}

использование

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

            }
        }
0 голосов
/ 14 июня 2016

Основываясь на ответе @ TheGuardian, я думаю, что это может быть более простой подход:

   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
    }
...