iOS 网络异常情况提示的处理方式

最近做了一个在 iOS 平台下提示用户网络异常的功能,许久没有做 iOS 原生需求了,接手这个需求后感觉 iOS 的坑也越来越多了。

这种需求很常见,首先分析一下这里指的网络异常包括,飞行模式、Wi-Fi 和蜂窝网络都被关闭、Wi-Fi 连接状态下应用的 Wi-Fi 权限被关闭,只有蜂窝连接的情况下应用蜂窝权限被关闭。

对这些情况的处理里程图如下:

下面把整个流程中的实现方法和需要注意的坑讲一下。

判断是否飞行模式

1
2
3
4
5
6
7
8
9
10
#import <CoreTelephony/CTTelephonyNetworkInfo.h>

/*
判断是否飞行模式
*/
+ (BOOL)isAirPlaneMode
{
CTTelephonyNetworkInfo *networkInfo = [[CTTelephonyNetworkInfo alloc] init];
return (BOOL)!networkInfo.currentRadioAccessTechnology;
}

如果 networkInfo.currentRadioAccessTechnology 返回 nil 则可以判断处于飞行模式。

判断 Wi-Fi 是否打开

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#import <ifaddrs.h>
#import <net/if.h>

/*
Wifi开关是否打开
*/
+ (BOOL) isWiFiEnabled {
NSString *const WIFI_INTERFACE_NAME = @"awdl0";
NSCountedSet * cset = [NSCountedSet new];
struct ifaddrs *interfaces;
if(!getifaddrs(&interfaces)) {
for( struct ifaddrs *interface = interfaces; interface; interface = interface->ifa_next) {
if ( (interface->ifa_flags & IFF_UP) == IFF_UP ) {
[cset addObject:[NSString stringWithUTF8String:interface->ifa_name]];
}
}
}
return [cset countForObject:WIFI_INTERFACE_NAME] > 1 ? YES : NO;
}

awdl0 是 wifi interface 的名称,判断是否有这个名称的 interface 就知道是否有打开 wifi 开关。

判断是否有 Wi-Fi 权限

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#import <SystemConfiguration/CaptiveNetwork.h>

/*
判断是否禁用了 Wi-Fi 权限
*/
+ (BOOL) isWifiNetWorkRestricted
{
NSArray *ifs = (__bridge_transfer NSArray *)CNCopySupportedInterfaces();
if (!ifs) {
return nil;
}

NSDictionary *info = nil;
for (NSString *ifnam in ifs) {
info = (__bridge_transfer NSDictionary *)CNCopyCurrentNetworkInfo((__bridge CFStringRef)ifnam);
if (info && [info count]) { break; }
}
return (BOOL)info;
}

如果 Wi-Fi 开关已经打开且 info 是 nil 那么就可以判断没有 Wi-Fi 权限。

判断是否有蜂窝网络权限

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#import <CoreTelephony/CTCellularData.h>

if ([GlobalUtils systemVersion] >= 9.0) { // iOS系统版本 >= 9.0
CTCellularData *cellularData = [[CTCellularData alloc] init];
cellularData.cellularDataRestrictionDidUpdateNotifier = ^(CTCellularDataRestrictedState state){
//获取联网状态
switch (state) {
case kCTCellularDataRestricted:
// 蜂窝网络受限,提示用户
...
break;
case kCTCellularDataNotRestricted:
// 有访问蜂窝网络的权限,说明蜂窝数据的开关被关闭了
...
break;
case kCTCellularDataRestrictedStateUnknown: // 从来没有过网络访问的时候会是这个状态
// 异常情况
...
break;
default:
break;
};
};
} else {
// 异常情况
}

  1. 国行版本的 iPhone 存在 Wi-Fi 权限的开关但是其他版本的 iPhone 不存在这个开关。
  2. iOS 10 以上版本的操作系统不允许第三方 App 跳转到系统设置页面,只允许他们跳转到 App 自己的设置页。
  3. 国行版本的 iPhone 在蜂窝和 Wi-Fi 关闭的情况下可以设置应用的 Wi-Fi 和蜂窝的权限,而其他版本不可以。
  4. 无法知道蜂窝开关是否打开,只能知道有无权限,非国行版本的 iPhone 在蜂窝被关闭的情况下无法打开蜂窝权限,所以要特殊处理,iOS10.0 以下的版本跳转到系统的蜂窝移动网络设置页面,10.0 以上的版本不做跳转。

参见

iOS中判断网络的状态的几种方法
iOS,利用URL Schemes跳转到设置wifi、蜂窝移动网络页面
iOS Settings URL Scheme