|
发表于 2017-5-19 02:42:29
|
显示全部楼层
以前iOS9上只有蜂窝访问权限,不过默认都是允许访问,可以自行去设置里面关闭。
而iOS10针对国行手机多了一个无线和蜂窝访问权限的选择。许多应用在第一次安装的时候会自动弹出一个alertview询问用户是否允许应用使用包括无线和蜂窝的数据。但也有部分是不会弹出的(iOS10系统bug,解决办法可自行百度)。注意这个弹窗只会在该手机第一个安装该应用的时候才会弹出,卸载重装也不会弹,类似keychain机制。
所以为了防止用户在第一次弹窗的时候点了不允许而后面不能正常连接网络的情况,做出了相应的处理。(由于苹果并没有给出相应的api,无法获知用户在第一次是否点了允许还是不允许,所以通过间接的方式去判断,有误判,不过都是极少情况的概率出现)
所有因为我们应用有引导页,所以在引导处自己写了一个请求百度HEAD的方法(为了去弹出系统网络弹窗,如果没有请求不会弹出,写HEAD请求也是为了节省流量)。然后在过渡到登陆页面的时候用AF去判断当前的网络状态,如果是AFNetworkReachabilityStatusNotReachable,即表示当前网络不可用。
然后在对此情况做出两种判断:
wifi:
- (NSDictionary *)fetchSSIDInfo {
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 info;
}
如果获取到的info不为nil,则当前是wifi情况下没有网络连接。
蜂窝:
获取运营商信息
- (NSString *)fetchMobileInfo {
CTTelephonyNetworkInfo *info = [[CTTelephonyNetworkInfo alloc] init];
return info.currentRadioAccessTechnology;
}
可以去判断是否为2G,2G情况下我是直接排除判断范围,因为2G环境下有可能会出现发生了网络请求,但是系统没有弹窗。
然后用了一个ios9的api去判断当前设置的蜂窝允许状态:(用户第一次弹窗选择了不允许,是指蜂窝和无线都不允许,那么可以通过这个蜂窝的状态间接去判断)
- (void)startValidateNetworkAuthorization NetworkAuthorizationStatus)block {
CTCellularData *cellularData = [[CTCellularData alloc]init];
cellularData.cellularDataRestrictionDidUpdateNotifier = ^(CTCellularDataRestrictedState state){
//获取联网状态
block(state);
switch (state) {
case kCTCellularDataRestricted:
CDLogDebug(@"Restricrted");
break;
case kCTCellularDataNotRestricted:
CDLogDebug(@"Not Restricted");
break;
case kCTCellularDataRestrictedStateUnknown:
CDLogDebug(@"Unknown");
break;
default:
break;
};
};
}
通过上面的判断最后可以得出在wifi情况下/蜂窝非2G情况下到登陆页面无网络连接,并且蜂窝状态是被拒绝的状态,就这样得出用户在第一次弹窗的时候点了不允许。
判断条件是iOS10以上,然后再通过keychain保存了一个值,只在第一次安装的时候才去判断,其他时候不用管。
存在误判情况:
1、完全无网模式下进入应用,包括关闭wifi、蜂窝,或者是直接飞行模式进入,当然这种情况下比较少。
2、有wifi但是wifi是不能联网的,也是比较少见。
所以通过这种方式可以减少误判范围,最主要的原因苹果只针对国行才有这个权限,没有给出相应的api。
有一种方式可以判断是否是飞行模式下进入应用:
- (void)checkNetworkConnectTest {
// 创建零地址,0.0.0.0的地址表示查询本机的网络连接状态
struct sockaddr_in zeroAddress;//sockaddr_in是与sockaddr等价的数据结构
bzero(&zeroAddress, sizeof(zeroAddress));
zeroAddress.sin_len = sizeof(zeroAddress);
zeroAddress.sin_family = AF_INET;//sin_family是地址家族,一般都是“AF_xxx”的形式。通常大多用的是都是AF_INET,代表TCP/IP协议族
/**
* SCNetworkReachabilityRef: 用来保存创建测试连接返回的引用
*
* SCNetworkReachabilityCreateWithAddress: 根据传入的地址测试连接.
* 第一个参数可以为NULL或kCFAllocatorDefault
* 第二个参数为需要测试连接的IP地址,当为0.0.0.0时则可以查询本机的网络连接状态.
* 同时返回一个引用必须在用完后释放.
* PS: SCNetworkReachabilityCreateWithName: 这个是根据传入的网址测试连接,
* 第二个参数比如为"www.apple.com",其他和上一个一样.
*
* SCNetworkReachabilityGetFlags: 这个函数用来获得测试连接的状态,
* 第一个参数为之前建立的测试连接的引用,
* 第二个参数用来保存获得的状态,
* 如果能获得状态则返回TRUE,否则返回FALSE
*
*/
SCNetworkReachabilityRef defaultRouteReachability = SCNetworkReachabilityCreateWithAddress(NULL, (struct sockaddr *)&zeroAddress); //创建测试连接的引用:
SCNetworkReachabilityFlags flags;
BOOL didRetrieveFlags = SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags);
CFRelease(defaultRouteReachability);
if (didRetrieveFlags && flags == 0) {
//当前是没有打开网络情况进入,不应该获取网络权限之后弹窗
CDLogDebug(@"%u",flags);
}
}
如果获取到的flags是0,就是相当于关闭蜂窝和无线,或者飞行模式进入,在这里我没有用,毕竟觉得占少数可以不用去考虑。 |
|