iOS实时网络监测

网络监测和信号质量

920 发布: 2020/8/19 14:10 本文总阅读量

网络监测

RKNetMonitor.h
#import <Foundation/Foundation.h>

@interface RKNetConnect: NSObject

@property(nonatomic,strong)NSString *oBytes;            //上行流量
@property(nonatomic,strong)NSString *oBytesOfRate;
@property(nonatomic,strong)NSString *iBytes;            //下行流量
@property(nonatomic,strong)NSString *iBytesOfRate;

+(instancetype)shareInstance;

@end

@interface RKNetMonitor : NSObject

@property(nonatomic,strong)RKNetConnect *connectObj;

+(instancetype)shareInstance;
- (RKNetConnect *)getInterfaceBytes:(int)interval;

@end
RKNetMonitor.m
#import "RKNetMonitor.h"

#include <ifaddrs.h>
#include <arpa/inet.h>
#include <net/if.h>

#import "AppDelegate.h"

@implementation RKNetConnect

static RKNetConnect *_connect = nil;

+(instancetype)shareInstance {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _connect = [[super allocWithZone:NULL]init];
    });
    return _connect;
}
+ (instancetype)allocWithZone:(struct _NSZone *)zone {
    return [self shareInstance];;
}

@end

@interface RKNetMonitor()

@property (nonatomic, assign)long long int lastoBytes;  //上一次上行
@property (nonatomic, assign)long long int lastiBytes;  //上一次下行

@end

@implementation RKNetMonitor

static RKNetMonitor *_monitor = nil;

+(instancetype)shareInstance {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _monitor = [[super allocWithZone:NULL]init];
    });
    return _monitor;
}
+ (instancetype)allocWithZone:(struct _NSZone *)zone{
    return [self shareInstance];;
}

- (RKNetConnect *)getInterfaceBytes:(int)interval {
    if (!interval) {
        interval = 1;
    }
    _connectObj = [RKNetConnect shareInstance];
    
    struct ifaddrs *ifa_list = 0, *ifa;
    if (getifaddrs(&ifa_list) == -1) {
        _connect.oBytes = 0;
        _connect.iBytes = 0;
        return 0;
    }
    
    uint32_t iBytes = 0;//下行
    uint32_t oBytes = 0;//上行
    
    for (ifa = ifa_list; ifa; ifa = ifa->ifa_next){
        
        if (AF_LINK != ifa->ifa_addr->sa_family)
            continue;
        if (!(ifa->ifa_flags & IFF_UP) && !(ifa->ifa_flags & IFF_RUNNING))
            continue;
        if (ifa->ifa_data == 0)
            continue;
        /* Not a loopback device. */
        if (strncmp(ifa->ifa_name, "lo", 2)){
            struct if_data *if_data = (struct if_data *)ifa->ifa_data;
            iBytes += if_data->ifi_ibytes;
            oBytes += if_data->ifi_obytes;
        }
    }
    
    //计算
    long long int rateOfoBytes = 0;     //上行速率
    long long int rateOfiBytes = 0;     //下行速率
   
    if (self.lastoBytes) {
        //用当前的上行总流量 减去 上次的上行流量 达到上行速录
        rateOfoBytes = oBytes - self.lastoBytes;
    }
    if(self.lastiBytes) {
        rateOfiBytes = iBytes - self.lastiBytes;
    }
    
    //保存上一秒的
    self.lastoBytes = oBytes;
    self.lastiBytes = iBytes;
    
    NSLog(@"\n[getInterfaceBytes-Total]%d,%d",iBytes,oBytes);
    _connectObj.oBytes = [self formatNetWork:oBytes];
    _connectObj.iBytes = [self formatNetWork:iBytes];
    _connectObj.oBytesOfRate = [self formatNetWork:(rateOfoBytes/interval)];
    _connectObj.iBytesOfRate = [self formatNetWork:(rateOfiBytes/interval)];
    
    freeifaddrs(ifa_list);
    
    return _connectObj;
}
- (NSString*)formatNetWork:(long long int)rate {
    if(rate <1024) {
        return[NSString stringWithFormat:@"%lldB", rate];
    }else if(rate >=1024&& rate <1024*1024) {
        return[NSString stringWithFormat:@"%.1fKB", (double)rate /1024];
    }else if(rate >=1024*1024 && rate <1024*1024*1024){
        return[NSString stringWithFormat:@"%.2fMB", (double)rate / (1024*1024)];
    }else{
        return@"10Kb";
    };
}
@end
外部调用

[[RKNetMonitor shareInstance] getInterfaceBytes:5];
NSString *rateShowStr = [NSString stringWithFormat:@"上:%@ R:%@/S\n下:%@ R:%@/S",[RKNetMonitor shareInstance].connectObj.oBytes,[RKNetMonitor shareInstance].connectObj.oBytesOfRate,[RKNetMonitor shareInstance].connectObj.iBytes,[RKNetMonitor shareInstance].connectObj.iBytesOfRate];
//_rateBtn显示网速的 按钮
[_rateBtn setTitle:rateShowStr forState:0];

手机型号

手机型号对照表


+ (NSInteger)getDeviceType;{
    struct utsname systemInfo;
    uname(&systemInfo);
    NSString *platform = [NSString stringWithCString:systemInfo.machine encoding:NSUTF8StringEncoding];
    NSArray *symbols = [platform componentsSeparatedByString:@","];
    NSInteger number = 0;
    if (symbols.count > 0){
        NSCharacterSet *characterSet = [[NSCharacterSet decimalDigitCharacterSet] invertedSet];
        number = [[[symbols[0] componentsSeparatedByCharactersInSet:characterSet] componentsJoinedByString:@""] integerValue];
    }
    return number;
}

网络类型


+ (NSString *)getNetworkType {
    UIApplication *app = [UIApplication sharedApplication];
    id statusBar = nil;
    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 (IS_IPHONE_X== 1) {
                //刘海屏
                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;
}

信号质量


+ (int)getSignalStrength {
    int signalStrength = 0;
    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"];
            id _cellularEntry = [currentData valueForKeyPath:@"cellularEntry"];
            if (_wifiEntry && [[_wifiEntry valueForKeyPath:@"isEnabled"] boolValue]) {
                // If wifiEntry is enabled, is WiFi.
                if ([_wifiEntry isKindOfClass:NSClassFromString(@"_UIStatusBarDataIntegerEntry")]) {
                // 层级:_UIStatusBarDataNetworkEntry、_UIStatusBarDataIntegerEntry、_UIStatusBarDataEntry
                    signalStrength = [[_wifiEntry valueForKey:@"displayValue"] intValue];
                }
            } else if (_cellularEntry && [[_cellularEntry valueForKeyPath:@"isEnabled"] boolValue]) {
                if ([_cellularEntry isKindOfClass:NSClassFromString(@"_UIStatusBarDataIntegerEntry")]) {
                // 层级:_UIStatusBarDataNetworkEntry、_UIStatusBarDataIntegerEntry、_UIStatusBarDataEntry
                    signalStrength = [[_cellularEntry valueForKey:@"displayValue"] intValue];
                }
            }
        }
    }else {
        if (IS_IPHONE_X == 1) {
            id statusBar = [[UIApplication sharedApplication] valueForKeyPath:@"statusBar"];
            id statusBarView = [statusBar valueForKeyPath:@"statusBar"];
            UIView *foregroundView = [statusBarView valueForKeyPath:@"foregroundView"];
            int signalStrength = 0;
            
            NSArray *subviews = [[foregroundView subviews][2] subviews];
            
            for (id subview in subviews) {
                if ([subview isKindOfClass:NSClassFromString(@"_UIStatusBarWifiSignalView")]) {
                    signalStrength = [[subview valueForKey:@"numberOfActiveBars"] intValue];
                    break;
                }else if ([subview isKindOfClass:NSClassFromString(@"_UIStatusBarPersistentAnimationView")]) {//_UIStatusBarStringView
                    signalStrength = [[subview valueForKey:@"numberOfActiveBars"] intValue];
                    break;
                }
            }
            return signalStrength;
        } else {
            
            UIApplication *app = [UIApplication sharedApplication];
            NSArray *subviews = [[[app valueForKey:@"statusBar"] valueForKey:@"foregroundView"] subviews];
            NSString *dataNetworkItemView = nil;
            int signalStrength = 0;

            for (id subview in subviews) {
                
                if([subview isKindOfClass:[NSClassFromString(@"UIStatusBarDataNetworkItemView") class]] && [[self getNetworkType] isEqualToString:@"WIFI"] && ![[self getNetworkType] isEqualToString:@"NONE"]) {
                    dataNetworkItemView = subview;
                    signalStrength = [[dataNetworkItemView valueForKey:@"_wifiStrengthBars"] intValue];
                    break;
                }
                if ([subview isKindOfClass:[NSClassFromString(@"UIStatusBarSignalStrengthItemView") class]] && ![[self getNetworkType] isEqualToString:@"WIFI"] && ![[self getNetworkType] isEqualToString:@"NONE"]) {
                    dataNetworkItemView = subview;
                    //signalStrength = [[dataNetworkItemView valueForKey:@"_signalStrengthRaw"] intValue];
                    signalStrength = [[dataNetworkItemView valueForKey:@"_signalStrengthBars"] intValue];
                    break;
                }
            }
            return signalStrength;
        }
    }
    return signalStrength;
}