ios信号从4g变成无服务器,iOS获取设备的网络状态(已适配iOS13,iOS14无变化)

前言

小编最近在项目中遇到了一个问题,除刘海屏以外的iOS设备可以正常的搜索到硬件设备,但是刘海屏就不行。因此,小编花了一点时间研究了一下iOS设备获取当前设备的网络状态。

实现

因为iOS的系统是封闭的,所以是没有直接的APi去获取当前的网络状态。但是道高一尺,魔高一尺。开发者总会有办法获取自己想要的东西。

1.网络状态获取

获取当前的网络类型

获取当前的网络类型是通过获取状态栏,然后遍历状态栏的视图完成的。

先导入头文件,如下:

#import "AppDelegate.h"

实现方法如下:

+ (NSString *)getNetworkType

{

UIApplication *app = [UIApplication sharedApplication];

id statusBar = nil;

// 判断是否是iOS 13

NSString *network = @"";

if (@available(iOS 13.0, *)) {

UIStatusBarManager *statusBarManager = [UIApplication sharedApplication].keyWindow.windowScene.statusBarManager;

#pragma clang diagnostic push

#pragma clang diagnostic ignored "-Wundeclared-selector"

if ([statusBarManager respondsToSelector:@selector(createLocalStatusBar)]) {

UIView *localStatusBar = [statusBarManager performSelector:@selector(createLocalStatusBar)];

if ([localStatusBar respondsToSelector:@selector(statusBar)]) {

statusBar = [localStatusBar performSelector:@selector(statusBar)];

}

}

#pragma clang diagnostic pop

if (statusBar) {

// UIStatusBarDataCellularEntry

id currentData = [[statusBar valueForKeyPath:@"_statusBar"] valueForKeyPath:@"currentData"];

id _wifiEntry = [currentData valueForKeyPath:@"wifiEntry"];

id _cellularEntry = [currentData valueForKeyPath:@"cellularEntry"];

if (_wifiEntry && [[_wifiEntry valueForKeyPath:@"isEnabled"] boolValue]) {

// If wifiEntry is enabled, is WiFi.

network = @"WIFI";

} else if (_cellularEntry && [[_cellularEntry valueForKeyPath:@"isEnabled"] boolValue]) {

NSNumber *type = [_cellularEntry valueForKeyPath:@"type"];

if (type) {

switch (type.integerValue) {

case 0:

// 无sim卡

network = @"NONE";

break;

case 1:

network = @"1G";

break;

case 4:

network = @"3G";

break;

case 5:

network = @"4G";

break;

default:

// 默认WWAN类型

network = @"WWAN";

break;

}

}

}

}

}else {

statusBar = [app valueForKeyPath:@"statusBar"];

if ([[[self alloc]init]isLiuHaiScreen]) {

// 刘海屏

id statusBarView = [statusBar valueForKeyPath:@"statusBar"];

UIView *foregroundView = [statusBarView valueForKeyPath:@"foregroundView"];

NSArray *subviews = [[foregroundView subviews][2] subviews];

if (subviews.count == 0) {

// iOS 12

id currentData = [statusBarView valueForKeyPath:@"currentData"];

id wifiEntry = [currentData valueForKey:@"wifiEntry"];

if ([[wifiEntry valueForKey:@"_enabled"] boolValue]) {

network = @"WIFI";

}else {

// 卡1:

id cellularEntry = [currentData valueForKey:@"cellularEntry"];

// 卡2:

id secondaryCellularEntry = [currentData valueForKey:@"secondaryCellularEntry"];

if (([[cellularEntry valueForKey:@"_enabled"] boolValue]|[[secondaryCellularEntry valueForKey:@"_enabled"] boolValue]) == NO) {

// 无卡情况

network = @"NONE";

}else {

// 判断卡1还是卡2

BOOL isCardOne = [[cellularEntry valueForKey:@"_enabled"] boolValue];

int networkType = isCardOne ? [[cellularEntry valueForKey:@"type"] intValue] : [[secondaryCellularEntry valueForKey:@"type"] intValue];

switch (networkType) {

case 0://无服务

network = [NSString stringWithFormat:@"%@-%@", isCardOne ? @"Card 1" : @"Card 2", @"NONE"];

break;

case 3:

network = [NSString stringWithFormat:@"%@-%@", isCardOne ? @"Card 1" : @"Card 2", @"2G/E"];

break;

case 4:

network = [NSString stringWithFormat:@"%@-%@", isCardOne ? @"Card 1" : @"Card 2", @"3G"];

break;

case 5:

network = [NSString stringWithFormat:@"%@-%@", isCardOne ? @"Card 1" : @"Card 2", @"4G"];

break;

default:

break;

}

}

}

}else {

for (id subview in subviews) {

if ([subview isKindOfClass:NSClassFromString(@"_UIStatusBarWifiSignalView")]) {

network = @"WIFI";

}else if ([subview isKindOfClass:NSClassFromString(@"_UIStatusBarStringView")]) {

network = [subview valueForKeyPath:@"originalText"];

}

}

}

}else {

// 非刘海屏

UIView *foregroundView = [statusBar valueForKeyPath:@"foregroundView"];

NSArray *subviews = [foregroundView subviews];

for (id subview in subviews) {

if ([subview isKindOfClass:NSClassFromString(@"UIStatusBarDataNetworkItemView")]) {

int networkType = [[subview valueForKeyPath:@"dataNetworkType"] intValue];

switch (networkType) {

case 0:

network = @"NONE";

break;

case 1:

network = @"2G";

break;

case 2:

network = @"3G";

break;

case 3:

network = @"4G";

break;

case 5:

network = @"WIFI";

break;

default:

break;

}

}

}

}

}

if ([network isEqualToString:@""]) {

network = @"NO DISPLAY";

}

return network;

}

获取当前的Wifi信息

获取当前的Wifi信息需要借助系统的SystemConfiguration这个库。

先导入头文件,如下:

#import

实现方法如下:

#pragma mark 获取Wifi信息

+ (id)fetchSSIDInfo

{

NSArray *ifs = (__bridge_transfer id)CNCopySupportedInterfaces();

id info = nil;

for (NSString *ifnam in ifs) {

info = (__bridge_transfer id)CNCopyCurrentNetworkInfo((__bridge CFStringRef)ifnam);

if (info && [info count]) {

break;

}

}

return info;

}

#pragma mark 获取WIFI名字

+ (NSString *)getWifiSSID

{

return (NSString *)[self fetchSSIDInfo][@"SSID"];

}

#pragma mark 获取WIFI的MAC地址

+ (NSString *)getWifiBSSID

{

return (NSString *)[self fetchSSIDInfo][@"BSSID"];

}

获取当前的Wifi信号强度

获取信号强度与获取网络状态有点类似,通过遍历状态栏,从而获取WIFI图标的信号强度。在获取前需注意当前状态是否为WIFI。如下:

+ (int)getWifiSignalStrength{

int signalStrength = 0;

// 判断类型是否为WIFI

if ([[self getNetworkType]isEqualToString:@"WIFI"]) {

// 判断是否为iOS 13

if (@available(iOS 13.0, *)) {

UIStatusBarManager *statusBarManager = [UIApplication sharedApplication].keyWindow.windowScene.statusBarManager;

id statusBar = nil;

#pragma clang diagnostic push

#pragma clang diagnostic ignored "-Wundeclared-selector"

if ([statusBarManager respondsToSelector:@selector(createLocalStatusBar)]) {

UIView *localStatusBar = [statusBarManager performSelector:@selector(createLocalStatusBar)];

if ([localStatusBar respondsToSelector:@selector(statusBar)]) {

statusBar = [localStatusBar performSelector:@selector(statusBar)];

}

}

#pragma clang diagnostic pop

if (statusBar) {

id currentData = [[statusBar valueForKeyPath:@"_statusBar"] valueForKeyPath:@"currentData"];

id wifiEntry = [currentData valueForKeyPath:@"wifiEntry"];

if ([wifiEntry isKindOfClass:NSClassFromString(@"_UIStatusBarDataIntegerEntry")]) {

// 层级:_UIStatusBarDataNetworkEntry、_UIStatusBarDataIntegerEntry、_UIStatusBarDataEntry

signalStrength = [[wifiEntry valueForKey:@"displayValue"] intValue];

}

}

}else {

UIApplication *app = [UIApplication sharedApplication];

id statusBar = [app valueForKey:@"statusBar"];

if ([[[self alloc]init]isLiuHaiScreen]) {

// 刘海屏

id statusBarView = [statusBar valueForKeyPath:@"statusBar"];

UIView *foregroundView = [statusBarView valueForKeyPath:@"foregroundView"];

NSArray *subviews = [[foregroundView subviews][2] subviews];

if (subviews.count == 0) {

// iOS 12

id currentData = [statusBarView valueForKeyPath:@"currentData"];

id wifiEntry = [currentData valueForKey:@"wifiEntry"];

signalStrength = [[wifiEntry valueForKey:@"displayValue"] intValue];

// dBm

// int rawValue = [[wifiEntry valueForKey:@"rawValue"] intValue];

}else {

for (id subview in subviews) {

if ([subview isKindOfClass:NSClassFromString(@"_UIStatusBarWifiSignalView")]) {

signalStrength = [[subview valueForKey:@"_numberOfActiveBars"] intValue];

}

}

}

}else {

// 非刘海屏

UIView *foregroundView = [statusBar valueForKey:@"foregroundView"];

NSArray *subviews = [foregroundView subviews];

NSString *dataNetworkItemView = nil;

for (id subview in subviews) {

if([subview isKindOfClass:[NSClassFromString(@"UIStatusBarDataNetworkItemView") class]]) {

dataNetworkItemView = subview;

break;

}

}

signalStrength = [[dataNetworkItemView valueForKey:@"_wifiStrengthBars"] intValue];

return signalStrength;

}

}

}

return signalStrength;

}

2.Reachability的使用

下载开源类Reachability,然后根据文档使用即可(该类把移动网络统称为WWAN):

+ (NSString *)getNetworkTypeByReachability

{

NSString *network = @"";

switch ([[Reachability reachabilityForInternetConnection]currentReachabilityStatus]) {

case NotReachable:

network = @"NONE";

break;

case ReachableViaWiFi:

network = @"WIFI";

break;

case ReachableViaWWAN:

network = @"WWAN";

break;

default:

break;

}

if ([network isEqualToString:@""]) {

network = @"NO DISPLAY";

}

return network;

}

上次发布了这篇文章之后,有人问我,怎么才能获取设备的IP地址呢?在这里,小编附上获取iP地址的方法。

先导入头文件,如下:

#import

#import

实现方法,如下:

#pragma mark 获取设备IP地址

+ (NSString *)getIPAddress

{

NSString *address = @"error";

struct ifaddrs *interfaces = NULL;

struct ifaddrs *temp_addr = NULL;

int success = 0;

// 检索当前接口,在成功时,返回0

success = getifaddrs(&interfaces);

if (success == 0) {

// 循环链表的接口

temp_addr = interfaces;

while(temp_addr != NULL) {

// 开热点时本机的IP地址

if ([[NSString stringWithUTF8String:temp_addr->ifa_name] isEqualToString:@"bridge100"]

) {

address = [NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_addr)->sin_addr)];

}

if(temp_addr->ifa_addr->sa_family == AF_INET) {

// 检查接口是否en0 wifi连接在iPhone上

if([[NSString stringWithUTF8String:temp_addr->ifa_name] isEqualToString:@"en0"]) {

// 得到NSString从C字符串

address = [NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_addr)->sin_addr)];

}

}

temp_addr = temp_addr->ifa_next;

}

}

// 释放内存

freeifaddrs(interfaces);

return address;

}

3.iOS 12下的补充

在iOS 12下xcode需要打开权限才可以正常操作,如下:

247262b80f5f

4.iOS 13下的补充

在iOS 13下xcode需要打开权限才可以正常操作,如下:

247262b80f5f

247262b80f5f

并且,在iOS 13下,若要获取SSID和BSSID,需要添加定位权限

247262b80f5f

#import

@interface ViewController ()

@property (strong, nonatomic) CLLocationManager *locationManager;

@end

@implementation ViewController

- (void)viewDidLoad {

[super viewDidLoad];

// Do any additional setup after loading the view, typically from a nib.

if (@available(iOS 13.0, *)) {

// 如果是iOS13 未开启地理位置权限 需要提示一下

if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined) {

self.locationManager = [[CLLocationManager alloc] init];

[self.locationManager requestWhenInUseAuthorization];

}

}

}

到这里为止,这篇文章就结束了。在这里提醒一下各位看官,横屏时请注意不要把状态栏去掉。有说明不足的地方欢迎评论,这里附上Demo下载地址:Demo。最后,希望这篇文章对各位看官们有所帮助。对支持小编的看官们表示感谢。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值