了解如何判断iOS设备是否具有蜂窝数据功能

32

我在我的应用程序中有一个"仅在WiFi下下载"的开关。然而,对于iPod touch或WiFi版iPad来说,该切换是无用的。

在代码中是否有一种方法可以知道设备是否具有蜂窝数据功能?最好是一些未来也能适用的方法(比如iPod touch第五代带3G版问世)。


我为此提交了一个错误报告:http://openradar.appspot.com/9974175。 - gcamp
为什么不编辑您的info.plist文件并在UIRequiredDeviceCapabilities中添加“3g”呢? - Zhao Xiang
2
@Zhao 这不是必需的,只是想为仅使用WiFi的用户隐藏一个切换按钮。 - gcamp
抱歉,我没有真正理解你的问题。我查看了苹果的文档,UIRequiredDeviceCapabilities 中没有 3gcellular radio 这个键。 - Zhao Xiang
8个回答

37

嗨,你应该能够检查它是否具有pdp_ip0接口

#import <ifaddrs.h>

- (bool) hasCellular {
    struct ifaddrs * addrs;
    const struct ifaddrs * cursor;
    bool found = false;
    if (getifaddrs(&addrs) == 0) {
        cursor = addrs;
        while (cursor != NULL) {
            NSString *name = [NSString stringWithUTF8String:cursor->ifa_name];
            if ([name isEqualToString:@"pdp_ip0"]) {
                found = true;
                break;
            }
            cursor = cursor->ifa_next;
        }
        freeifaddrs(addrs);
    }
    return found;
}

这不使用任何私有API。


我在这里发现了一个相似的答案(https://dev59.com/5nM_5IYBdhLWcg3wRw51#1480867),它看起来非常健壮。思维敏锐! - user244343
代码示例中有几个错误,但是思路是正确的。我在编辑中提供了更正。 - isoiphone
1
@DTs 已经被纠正了。请确保您导入了 #import <ifaddrs.h>。 - bentech

17

3G本身似乎很难找到。您可以使用{{link1:[[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:“tel://”]]}}来查看设备是否可以打电话。您可以使用Reachability代码检查设备是否可以访问互联网(以及当前可以使用哪种方法):

NetworkStatus currentStatus = [[Reachability reachabilityForInternetConnection] 
                               currentReachabilityStatus];

if(currentStatus == kReachableViaWWAN) // 3G

else if(currentStatus == kReachableViaWifi) // ...wifi

else if(currentStatus == kNotReachable) // no connection currently possible

..但除此之外,我认为你无法检查设备中是否存在3G调制解调器。***** 如果它不能打电话,并且当前没有开启蜂窝数据和关闭wifi,那么你将无法确定它是否支持3G。

另一种方法(不过不向前兼容,所以你可能不想这样做)是将设备的型号与详尽的列表进行比较,知道哪些设备中有3G调制解调器,如此处所示。

***** 根据bentech的答案,如果你想要深入挖掘设备名称(如果苹果决定更改3g接口名称,则可能会在没有预先警告的情况下停止工作),请调用getifaddrs并检查pdp_ip0接口。


1
我了解你列出的所有内容...前两个都不可接受: 不是因为你不能打电话或者你当前在WiFi上就不能使用蜂窝数据。第三个不具备未来性... - gcamp
8
我非常清楚,这就是为什么我的答案是“不,没有办法只检查3G”的原因。 - user244343
2
你应该选择第三个选项,将默认设置为“是的,它有3G”,然后随着新设备的推出进行更新。如果在没有3G的设备上切换不起作用,那么对于未来的设备来说是无害的(并且您仍然有一定的时间窗口在它们之前进行更新)。 - MaxGabriel

7

@bentech 的回答中使用的 Swift 3.0 (UIDevice+Extension)

请将以下代码添加到您的 BridgingHeader.h 文件中:

#import <ifaddrs.h>

其他地方:

extension UIDevice {
    /// A Boolean value indicating whether the device has cellular data capabilities (true) or not (false).
    var hasCellularCapabilites: Bool {
        var addrs: UnsafeMutablePointer<ifaddrs>?
        var cursor: UnsafeMutablePointer<ifaddrs>?

        defer { freeifaddrs(addrs) }

        guard getifaddrs(&addrs) == 0 else { return false }
        cursor = addrs

        while cursor != nil {
            guard
                let utf8String = cursor?.pointee.ifa_name,
                let name = NSString(utf8String: utf8String),
                name == "pdp_ip0"
                else {
                    cursor = cursor?.pointee.ifa_next
                    continue
            }
            return true
        }
        return false
    }
}

这对我有用。在iPod(没有蜂窝网络)和手机上测试过。我所做的唯一更改是在无法确定蜂窝网络(由于错误或任何原因)时返回nil: "guard getifaddrs(&addrs)== 0 else {return nil}"(并使返回类型为可选)。 - GK100
仍然适用于iOS 16,您不再需要桥接头文件或NSString - pommy

4
在iOS 6.1中,我已经成功使用Core Telephony来检查移动基带功能的存在。这适用于我测试的所有iPad:已激活和未激活服务的Verizon,当前停用服务但插入和拔出SIM卡的AT&T以及仅支持Wi-Fi的iPad。
我使用的代码如下:
CTTelephonyNetworkInfo* ctInfo = [[CTTelephonyNetworkInfo alloc] init];
CTCarrier* carrier = ctInfo.subscriberCellularProvider;
self.hasWWANCapability = carrier != nil;

对于所有具有蜂窝基带硬件的iPad,carrier不为nil。对于仅支持Wi-Fi的iPad,carrier为nil。


3
如果没有蜂窝数据连接,即使你的设备支持蜂窝数据功能,也会得到空值。这是不正确的。(在使用iOS5.1.1的第一代iPad上进行过测试) - Laszlo

2
我认为你应该能够使用CoreTelephony Framework

它确实指出这是供运营商使用的,所以我不确定访问它是否违反了服务条款。

运营商可以使用此信息编写仅为其自己的订阅者提供服务的应用程序


我没有看到任何说明它只能由运营商使用;它似乎是为了解决运营商的需求而提供的,但是文本中的措辞并没有表明它只能由运营商使用。 - Rick

1

一种方法是要求用户提供其位置。当位置尽可能准确时,您将知道设备是否具有GPS。所有具有GPS的设备都将拥有3G。而那些没有GPS的设备则不会有3G。


你用什么进行比较来做出这个决定? - CuriousRabbit
这也是一个获取该信息非常漫长且昂贵的过程。此外,当在室内时,大多数 GPS 设备都会使用 WiFi,因为在这些条件下精度更高。 - gcamp

0

这里提供了苹果的代码。 https://developer.apple.com/library/ios/samplecode/Reachability/Introduction/Intro.html

您应该将 Reachability.h 和 Reachability.m 复制到您的项目中,并在您的类中导入 Reachability.h。

Reachability *networkReachability = [Reachability reachabilityForInternetConnection];
NetworkStatus networkStatus = [networkReachability currentReachabilityStatus];

while (networkStatus==NotReachable) {
    NSLog(@"not reachable");
//no  internet connection 
    return;
}
while (networkStatus==ReachableViaWWAN) {
    NSLog(@" ReachableViaWWAN ");
}

while (networkStatus==ReachableViaWiFi) {
    NSLog(@"ReachableViaWiFi");
}

2
这是为了了解当前的互联网连接情况,而不是设备的能力。 - gcamp

-3
另一种方法是通过扩展https://github.com/monospacecollective/UIDevice-Hardware/blob/master/UIDevice-Hardware.m来实现。
-(bool) hasCellular:(NSString*)modelIdentifier {
    if ([modelIdentifier hasPrefix:@"iPhone"]) return YES;
    if ([modelIdentifier hasPrefix:@"iPod"]) return NO;

    if ([modelIdentifier isEqualToString:@"iPad1,1"])      return NO;
    if ([modelIdentifier isEqualToString:@"iPad2,1"])      return NO;
    if ([modelIdentifier isEqualToString:@"iPad2,2"])      return YES;
    if ([modelIdentifier isEqualToString:@"iPad2,3"])      return YES;
    if ([modelIdentifier isEqualToString:@"iPad2,4"])      return NO;
    if ([modelIdentifier isEqualToString:@"iPad2,5"])      return NO;
    if ([modelIdentifier isEqualToString:@"iPad2,6"])      return YES;
    if ([modelIdentifier isEqualToString:@"iPad2,7"])      return YES;
    if ([modelIdentifier isEqualToString:@"iPad3,1"])      return NO;
    if ([modelIdentifier isEqualToString:@"iPad3,2"])      return YES;
    if ([modelIdentifier isEqualToString:@"iPad3,3"])      return YES;
    if ([modelIdentifier isEqualToString:@"iPad3,4"])      return NO;
    if ([modelIdentifier isEqualToString:@"iPad3,5"])      return YES;
    if ([modelIdentifier isEqualToString:@"iPad3,6"])      return YES;
    if ([modelIdentifier isEqualToString:@"iPad4,1"])      return NO;
    if ([modelIdentifier isEqualToString:@"iPad4,2"])      return YES;
    if ([modelIdentifier isEqualToString:@"iPad2,5"])      return NO;
    if ([modelIdentifier isEqualToString:@"iPad2,6"])      return YES;
    if ([modelIdentifier isEqualToString:@"iPad2,7"])      return YES;
    if ([modelIdentifier isEqualToString:@"iPad4,4"])      return NO;
    if ([modelIdentifier isEqualToString:@"iPad4,5"])      return YES;

    if ([modelIdentifier isEqualToString:@"i386"])         return NO;
    if ([modelIdentifier isEqualToString:@"x86_64"])       return NO;

return YES;

}

(显然,它可以被编辑成只删除NO或YES中的一个,具体取决于您希望在出现新模型时如何出错...)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接