определяет, поддерживает ли устройство телефонные звонки?

<p>надежен ли приведенный ниже код для определения, может ли устройство поддерживать телефонные звонки или нет? меня беспокоит, если apple изменит строку iphone на что-то еще, скажем, они решат иметь «iphone 3g», «iphone 4» и т.п.</p><pre><code>[[uidevice currentdevice].model isequaltostring:@"iphone"] </code></pre>

<p>iphone поддерживает схему tel: // uri. таким образом, вы можете использовать:</p><pre><code>[[uiapplication sharedapplication] canopenurl:[nsurl urlwithstring:@"tel://"]]; </code></pre><p>canopenurl: явно проверяет, есть ли приложение, способное открыть эту схему url, а не то, что url правильный. поэтому не имеет значения, что номер телефона не указан. метод возвращает bool, поэтому проверьте это для да или нет.</p><p>это должно буквально ответить на вопрос, есть ли какое-либо приложение, способное сделать телефонный звонок. так что это должно быть хорошо против любых будущих изменений в сегментации устройства.</p>

<p>простая проверка того, поддерживает ли устройство телефонные звонки, может быть не лучшим способом решения проблем, в зависимости от того, что вы пытаетесь выполнить. верьте или нет, некоторые люди используют старые айфоны без обслуживания, как если бы они были ipod touch. иногда люди не имеют sim-карты, установленные в их iphone. в моем приложении я хотел набрать номер телефона, если устройство пользователя могло, в противном случае я хотел бы отобразить номер телефона и предложить пользователю взять телефон и набрать его. вот решение, которое я придумала, которое сработало до сих пор. не стесняйтесь комментировать и улучшать его.</p><pre><code>// 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; } } </code></pre><p>вы заметите, что я проверяю, является ли mobilenetworkcode 65535. в моем тестировании выяснилось, что при удалении sim-карты mobilenetworkcode устанавливается на 65535. не уверен на 100%, почему это так.</p>

<p>мне нужно убедиться, что входящие телефонные звонки не могут прервать записи, которые делают мои клиенты, поэтому я предлагаю им перейти в режим полета, но при этом включить wi-fi. описанный выше метод от albeebe не работает для меня на ios 8.1.3, но если будет найдено это решение, которое должно работать в ios 7 и более поздних версиях:</p><p>вы должны добавить и импортировать coretelephony.framework.</p><pre><code>#import <coretelephony/cttelephonynetworkinfo.h> #import <coretelephony/ctcarrier.h> </code></pre><p>определите свойство в своем классе, если вы хотите отслеживать изменения</p><pre><code>@property (strong, nonatomic) cttelephonynetworkinfo* networkinfo; </code></pre><p>инициатива <code>cttelephonynetworkinfo</code>: </p><pre><code>self.networkinfo = [[cttelephonynetworkinfo alloc] init]; nslog(@"initial cell connection: %@", self.networkinfo.currentradioaccesstechnology); [[nsnotificationcenter defaultcenter] addobserver:self selector:@selector(radioaccesschanged) name:ctradioaccesstechnologydidchangenotification object:nil]; </code></pre><p>и тогда вы получите ответный звонок, когда он изменится:</p><pre><code>- (void)radioaccesschanged { nslog(@"now you're connected via %@", self.networkinfo.currentradioaccesstechnology); } </code></pre><p>значения для <code>currentradioaccesstechnology</code> определены в cttelephonynetworkinfo.h, и вы получите нулевое/нулевое значение, когда нет соединения с вышкой сотовой связи.</p><p>вот где я его нашел: <a href="http://www.raywenderlich.com/48001/easily-overlooked-new-features-ios-7">http://www.raywenderlich.com/48001/easily-overlooked-new-features-ios-7</a> </p>

<p>основываясь на ответе @ the-guardian, я придумал следующее (на языке swift):</p><pre><code>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 } </code></pre><p>этот код был протестирован на ipad air 2 wifi, ipad air 2 simulator, iphone 6s plus и, похоже, работает надлежащим образом. скоро определится на ipad с мобильными данными. </p>

<p>эта функция <code>uiapplication.shared.openurl((url(string: "tel://\(phonenumber)")!))</code> не скажет, имеет ли она sim-карту, или not not, она просто скажет, есть ли у устройства параметры для совершения вызова.<strong> например </strong>: iphone с sim-картой или без нее будет возвращать значение true, но в ipod touch он всегда будет возвращать значение false, как и в случае, если на ipad нет опции sim, он возвращает значение false.</p><p><strong> вот код, который все проверяет всесторонне! </strong>(использование swift 3.0)</p><pre><code>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() } </code></pre><p>таким образом, мы можем убедиться, что устройство поддерживает вызовы или нет.</p>

<p>я не думаю, что ваш метод является надежным, поскольку имена устройств могут измениться в будущем. если ваша задача - не запускать приложение на устройствах, отличных от iphone, вы можете добавить «телефонию» в словарь <a href="http://developer.apple.com/library/ios/#documentation/general/reference/infoplistkeyreference/articles/iphoneoskeys.html">uirequireddevicecapabilities</a> в вашем info.plist. это запретит другим устройствам, кроме iphone, загружать ваше приложение из app store.</p><p>в качестве альтернативы, если вам нужно проверить наличие соединения 3g в определенный момент, вы можете использовать класс утилит apple <a href="http://developer.apple.com/library/ios/#samplecode/reachability/index.html">reachability</a> , чтобы узнать о текущем состоянии соединения 3g/wifi.</p>

<p>я думаю, что в целом это так. я бы пошел для более общего сравнения строк (просто, чтобы быть более безопасным в случае будущего обновления). я использовал это без проблем (пока ...). </p><p>если вы хотите быть более уверенным в том, может ли устройство на самом деле совершать звонки, вам также следует воспользоваться api-интерфейсом core telephony. класс ctcarrier может сказать вам, можете ли вы действительно сделать звонок в любой конкретный момент.</p>

<p>в случае, если вы запрашиваете, чтобы позвонить по номеру телефона и показать an ошибка на устройствах, которые не имеют телефонии:</p><pre><code>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); } } } </code></pre><p>использование</p><pre><code> p97openurl(phoneurl, ^(bool success) { if(!success) { show message saying there is no telephony on device } } </code></pre>