【问题标题】:Detecting whether or not device support phone calls?检测设备是否支持电话?
【发布时间】:2011-07-02 23:15:41
【问题描述】:

以下代码用于确定设备是否支持电话通话是否可靠? 我担心的是,如果苹果将 iphone 字符串更改为其他任何内容,假设他们决定使用“iphone 3g”、“iphone 4”等。

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

【问题讨论】:

    标签: ios objective-c iphone cocoa-touch phone-call


    【解决方案1】:

    根据@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 模拟器、iPhone 6S Plus 上进行了测试,并且似乎可以正常工作。很快将确定在带有移动数据的 iPad 上。

    【讨论】:

      【解决方案2】:

      如果您要求拨打电话号码并显示 没有电话的设备上的错误:

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

      【讨论】:

        【解决方案3】:

        这个UIApplication.shared.openURL((URL(string: "tel://\(phoneNumber)")!)) 不会说它是否有 SIM 卡这只会说设备是否有拨打电话的选项。 例如:有或没有 SIM 卡的 iPhone 都会返回 true,但在 iPod Touch 中它总是会返回 false,就像 ipad 没有 sim 选项它会返回 false 一样。 p>

        这是全面检查所有内容的代码!(使用 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()
                }
        

        通过这种方式,我们可以确定设备是否支持通话。

        【讨论】:

          【解决方案4】:

          根据@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
              }
          

          【讨论】:

            【解决方案5】:

            仅检查设备是否“支持”电话呼叫可能不是处理事情的最佳方式,具体取决于您要完成的任务。信不信由你,有些人在没有维修服务的情况下使用旧 iPhone,就好像它们是 iPod Touch 一样。有时人们的 iPhone 中没有安装 SIM 卡。在我的应用程序中,如果用户设备能够拨打电话号码,我想拨打电话号码,否则我想显示电话号码并提示用户拿起电话并拨打电话。这是我想出的一个迄今为止有效的解决方案。随意评论和改进它。

            // 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% 确定这是为什么。

            【讨论】:

            • 这在 iOS 8.1.3 上对我不起作用,无论是否处于飞行模式,mnc 始终等于“02”。但我找到了适用于 iOS 7 及更高版本的解决方案,请参阅下面的答案。
            • 我知道这是一个老话题,但我只想指出,65535 MNC 在南非是绝对有效的 MNC。因此,根据您的市场,您需要谨慎使用这种方法。
            • 我认为你不正确@GaborFuredi 因为在南非,MCC 是 655(移动国家代码),而 35 是 MNC(移动网络代码)。两种截然不同的东西。在我的示例中,我正在检查 MNC 是否为 65536,并且根据 en.wikipedia.org/wiki/Mobile_country_code 没有 MNC 大于 1,000
            • 这个方法很棒,但仍然不完美。我正在接受 tel: url 并返回有效 mmc 的 3G iPad 上进行测试。当您单击应用程序中的相关按钮时,它会很好地处理 url,但是在结果弹出窗口中选择调用选项后,什么也没有发生。我实际上已将您的检测与设备名称检查结合起来,因此所有 iPad 都被排除在外。它可能不是 100% 未来证明,但它具有所需的功能。
            • @GaborFuredi @albeebe 请注意,MCC 是一个 10 位值 [1],显然有人将它塞进了一个 16 位有符号整数,因此有人将 65535 设置为 FF 以表明该值是'不设置 [1] standards.ieee.org/content/dam/ieee-standards/standards/web/…
            【解决方案6】:

            我需要确保来电不会中断我的客户进行的录音,所以我提示他们进入飞行模式但仍然打开 wifi。上面来自 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

            【讨论】:

              【解决方案7】:

              我认为通常是这样。我会进行更通用的字符串比较(只是为了在将来更新时更安全)。我使用它没有任何问题(到目前为止......)。

              如果您想更确定设备是否可以实际拨打电话,您还应该利用 Core Telephony API。 CTCarrier 类可以告诉您是否真的可以在任何特定时刻拨打电话。

              【讨论】:

                【解决方案8】:

                iPhone 支持 tel:// URI 方案。所以你可以使用:

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

                canOpenURL:明确检查是否有应用程序能够打开该 URL 方案,而不是 URL 是否正确。因此,没有指定电话号码并不重要。该方法返回一个 BOOL,因此请检查 YES 或 NO。

                这应该从字面上回答是否存在任何能够拨打电话的应用程序。因此,它应该可以应对未来设备细分的任何变化。

                【讨论】:

                • 我想指出一些人们使用这种方法可能会忽略的东西。如果设备处于飞行模式,或者 SIM 卡被移除,或者 SIM 卡服务被停用,那么设备“技术上”支持电话,但这并不意味着它“可以”拨打电话。尽管听起来很罕见,但人们使用没有服务的旧 iPhone 作为 iPod Touches。只是需要考虑的事情取决于您要完成的工作。
                • 完全同意AlBeebe,对于我的应用来说,关键是手机现在能不能打电话,不是一般情况。我认为下面 AlBeebe 的回答是正确的。
                • 请注意,这在 IOS8 测试版中不起作用。但可能是测试版中的一个错误。如果不是,则需要 CTTelephonyNetworkInfo 检查。
                • 在 iOS8GM 上也不起作用,所以看起来不是 beta 中的错误。
                • 这在我运行 iOS 8.1 的 iPad2 上返回 TRUE。但是,它在我的 iPad2 8.1 模拟器上返回 FALSE(正确行为)。所以不幸的是它不起作用,它很重要......
                【解决方案9】:

                我认为您的方法不可靠,因为设备名称将来可能会更改。如果您担心阻止应用程序在非 iPhone 设备上运行,您可以将“电话”添加到 Info.plist 中的 UIRequiredDeviceCapabilities 字典中。这将禁止 iPhone 以外的设备从 App Store 下载您的应用。

                或者,如果您需要在特定时刻检查 3G 连接,您可以使用 Apple 的 Reachability 实用程序类来询问当前的 3G/WIFI 连接状态。

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 2013-06-25
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多