由于项目测试当中需要外网测试人员连到内网进行测试,有时候因为测试人员大意,没有连接到VPN环境,导致反馈过来的测试结果不正确,因此需要在打包测试安装包的时候先判断是否已经连接上VPN。
网上找到的blog都是判断当前网络状态,但是判断的结果却不准确,满足不了需求。在一次跟 @黄二百万 聊天中获得灵感,可以根据状态栏中的的图标进行判断,判断当前的状态栏是否有VPN标志。
</br>
</br>方案一:起初想通获取状态栏UIStatusBar的方式,将UIView转成UIImage,然后通过图片文字识别,是否包含“VPN”字样,但是系统的UIStatusBar“直接”获取是获取不到的,该方案行不通。(勘误:可以通过方案三中的方式得到)
</br>
</br>方案二:将整个屏幕截图包括状态栏,然后截取
[UIApplication sharedApplication].statusBarFrame
这个size下的context再转成UIImage,然后通过图片文字识别,是否包含“VPN”字样。但是通过代码截图的方式获取不到带状态栏的截图,因此该方案也行不通(如果谁知道如何获取带状态栏的截图,麻烦留言区告知,谢谢!!!)
</br>
</br> 方案三:偶然看到一篇博客里面可以通过UIApplication的:
- (nullable id)valueForKey:(NSString *)key;
的方式获取到 UIStatusBar!
将手机连上VPN, 尝试打印:
UIApplication *app = [UIApplication sharedApplication];
UIView *statusView = [app valueForKey:@"statusBar"];
NSArray *subViews = [[statusView valueForKey:@"foregroundView"] subviews];
NSLog(@"%@",subViews);
结果如下是:
Printing description of subViews:
<__NSArrayM 0x170258780>(
<UIStatusBarSignalStrengthItemView: 0x100306110; frame = (6 0; 35 20); userInteractionEnabled = NO; layer = <CALayer: 0x17403a0e0>> [Item = <UIStatusBarItem: 0x17403a0c0> [UIStatusBarSignalStrengthItemView (Left)]],
<UIStatusBarServiceItemView: 0x1002015d0; frame = (44 0; 50 20); userInteractionEnabled = NO; layer = <CALayer: 0x17003e520>> [Item = <UIStatusBarItem: 0x17003e560> [UIStatusBarServiceItemView (Left)]],
<UIStatusBarDataNetworkItemView: 0x100209210; frame = (99 0; 13 20); userInteractionEnabled = NO; layer = <CALayer: 0x17003e180>> [Item = <UIStatusBarItem: 0x17003e2e0> [UIStatusBarDataNetworkItemView (Left)]],
<UIStatusBarIndicatorItemView: 0x1002099b0; frame = (118 0; 20 20); userInteractionEnabled = NO; layer = <CALayer: 0x1702204e0>> [Item = <UIStatusBarItem: 0x170220500> [UIStatusBarIndicatorItemView:VPN (Left/Right)]],
<UIStatusBarBatteryItemView: 0x10020a140; frame = (337 0; 33 20); userInteractionEnabled = NO; layer = <CALayer: 0x170220320>> [Item = <UIStatusBarItem: 0x170220580> [UIStatusBarBatteryItemView (Right)]],
<UIStatusBarBatteryPercentItemView: 0x10020bbd0; frame = (303 0; 31 20); userInteractionEnabled = NO; layer = <CALayer: 0x170220c20>> [Item = <UIStatusBarItem: 0x170220560> [UIStatusBarBatteryPercentItemView (Right)]],
<UIStatusBarIndicatorItemView: 0x100209420; frame = (287 0; 10 20); userInteractionEnabled = NO; layer = <CALayer: 0x170220c60>> [Item = <UIStatusBarItem: 0x170220540> [UIStatusBarIndicatorItemView:Alarm (Right)]],
<UIStatusBarIndicatorItemView: 0x10020aaf0; frame = (261 0; 20 20); alpha = 0; userInteractionEnabled = NO; layer = <CALayer: 0x170220d80>> [Item = <UIStatusBarItem: 0x170220500> [UIStatusBarIndicatorItemView:VPN (Left/Right)]],
<UIStatusBarIndicatorItemView: 0x10020a370; frame = (269 0; 12 20); userInteractionEnabled = NO; layer = <CALayer: 0x170220d00>> [Item = <UIStatusBarItem: 0x170220520> [UIStatusBarIndicatorItemView:RotationLock (Right)]],
<UIStatusBarTimeItemView: 0x100204470; frame = (161 0; 56 20); userInteractionEnabled = NO; layer = <CALayer: 0x170220f40>> [Item = <UIStatusBarItem: 0x17403a0a0> [UIStatusBarTimeItemView (Center)]]
)
可以看到description打印结果中有暴露“VPN”相关的信息,证明通过访问私有属性是可以做到的。
方法一:因此可以通过遍历UIStatusBar的子view,打印子view的description,通过判断description中是否包含“VPN”这个子字符串的方式达到文章开头提到的目的!
上代码:
- (BOOL)isVPNConnected {
UIApplication *app = [UIApplication sharedApplication];
UIView *statusView = [app valueForKey:@"statusBar"];
NSArray *subViews = [[statusView valueForKey:@"foregroundView"] subviews];
Class StatusBarIndicatorItemViewClass = NSClassFromString(@"UIStatusBarIndicatorItemView");
for (UIView *subView in subViews) {
Class SubStatusBarIndicatorItemViewClass = [subView class];
if ([SubStatusBarIndicatorItemViewClass isSubclassOfClass:StatusBarIndicatorItemViewClass]) {
return [[subView description] containsString:@"VPN"];
}
}
return NO;
}
方法二:访问UIStatusBarIndicatorItemView的私有属性_visible判断是否开启了VPN
上代码:
- (BOOL)isVPNConnected {
UIApplication *app = [UIApplication sharedApplication];
UIView *statusView = [app valueForKey:@"statusBar"];
NSArray *subViews = [[statusView valueForKey:@"foregroundView"] subviews];
Class StatusBarIndicatorItemViewClass = NSClassFromString(@"UIStatusBarIndicatorItemView");
for (UIView *subView in subViews) {
Class SubStatusBarIndicatorItemViewClass = [subView class];
if ([SubStatusBarIndicatorItemViewClass isSubclassOfClass:StatusBarIndicatorItemViewClass]) {
return [[subView valueForKey:@"_visible"] boolValue];
}
}
return NO;
}
网友评论
CFDictionaryRef dicRef = CFNetworkCopySystemProxySettings();
const CFStringRef proxyCFstr = (const CFStringRef)CFDictionaryGetValue(dicRef,
(const void*)kCFNetworkProxiesHTTPProxy);
NSString* proxy = (__bridge NSString *)proxyCFstr;
if (proxy != nil) {
return YES;
}else if ( proxy != nil || proxy == NULL) {
return NO;
}
return NO;
}
用这个方法来判断是否使用了代理,效果一样的