Commit b8790e38 by GuoJianPeng

update

parent 436a318d
......@@ -58,14 +58,16 @@
-(UILabel *)titleLabel{
if(!_titleLabel){
_titleLabel = [[UILabel alloc] init];
_titleLabel.textColor = [UIColor colorWithRed:51/254.0 green:51/254.0 blue:51/254.0 alpha:1];
_titleLabel.textColor = [UIColor colorWithRed:54/255.0 green:54/255.0 blue:54/255.0 alpha:1];
_titleLabel.font = [UIFont systemFontOfSize:13];
_titleLabel.translatesAutoresizingMaskIntoConstraints = false;
}return _titleLabel;
}
-(UILabel *)createRightLabel:(BOOL)pass{
UILabel * label = [[UILabel alloc] init];
label.textColor = pass ? UIColor.greenColor : UIColor.redColor;
UIColor * greenColor = [UIColor colorWithRed:92/255.0 green:201/255.0 blue:148/255.0 alpha:1];
UIColor * redColor = [UIColor colorWithRed:223/255.0 green:94/255.0 blue:84/255.0 alpha:1];
label.textColor = pass ? greenColor :redColor;
label.font = [UIFont systemFontOfSize:12];
label.translatesAutoresizingMaskIntoConstraints = false;
return label;
......
......@@ -6,10 +6,7 @@
//
#import <Foundation/Foundation.h>
#import <ASNetwork/ASReachability.h>
#import <ASNetwork/ASCellularNet.h>
#import <ASNetwork/ASPingService.h>
#import <ASNetwork/ASInterfaceService.h>
#import <ASNetwork/ASNetwork.h>
NS_ASSUME_NONNULL_BEGIN
......@@ -22,10 +19,19 @@ typedef NS_ENUM(NSInteger,CRMNetSignalStrength)
};
@protocol CRMNetDetectServiceDelegate <NSObject>
//连接情况和信号强度一并返回
- (void)didGotNetworkStatus:(ASReachabilityStatus)status signalStrength:(CRMNetSignalStrength)strength;
- (void)didGotIPState:(BOOL)isNormal ;//Wifi下非自有IP则正常,蜂窝下有IP则正常
- (void)didGotBusinessServiceState:(BOOL)isNormal host:(NSString*)host millionSeconds:(NSTimeInterval)millionSeconds;
- (void)didFinishedBusinessService:(BOOL)isNormal;//正常数小于总数,则显示异常
//ping www.baidu.com,能收到回调表示外网访问正常,IP状态视为正常,否则为异常.
- (void)didGotIPState:(BOOL)isNormal ;
//单个业务服务检测回调
- (void)didGotBusinessServiceState:(BOOL)isNormal
host:(NSString*)host
hostIndex:(NSInteger)hostIndex millionSeconds:(NSTimeInterval)millionSeconds;
//完成所有业务服务检测回调
- (void)didFinishedBusinessService:(BOOL)isNormal;
@end
@interface CRMNetDetectService : NSObject
......@@ -41,10 +47,9 @@ typedef NS_ENUM(NSInteger,CRMNetSignalStrength)
**/
- (void)stopDetecting;
@property(nonatomic,strong,nullable)NSArray<NSString*>*businessHostList;
@property(nonatomic,assign,readonly)BOOL isDetecting;
@property(nonatomic,strong,nullable)NSArray<NSString*>*businessHostList;
@property(nonatomic,weak,readonly)id<CRMNetDetectServiceDelegate>delegate;
@property(nonatomic,assign,readonly)BOOL isAllFinished;
@end
NS_ASSUME_NONNULL_END
......@@ -10,17 +10,14 @@
@interface CRMNetDetectService()<ASPingServiceDelegate,ASReachabilityDelegate>
{
NSInteger _successPingHostCount;
}
@end
@implementation CRMNetDetectService
{
ASReachability *_reachability;
ASInterfaceService *_interfaceService;
ASPingService *_pingService;
NSMutableArray <NSString*>*_pingingHostList;
BOOL _isReachabilityFinished;
}
@end
@implementation CRMNetDetectService
-(void)dealloc
{
[self stopDetecting];
......@@ -35,78 +32,67 @@
{
if(_isDetecting){return;}
_isDetecting = true;
if([_businessHostList count]){
_pingingHostList = _businessHostList.mutableCopy;
_pingService = [[ASPingService alloc] initWithDelegate:self];
[self _readHostAndPing];
}
//先检测网络态,再检测具体业务域名
[self _startReachabilityService];
}
-(void)stopDetecting
{
_isDetecting = false;
[self _stopPingService];
[self _stopReachabilityService];
_isAllFinished = false;
_interfaceService = nil;
_isReachabilityFinished = false;
[self _stopPingService];
_successPingHostCount = 0;
}
#pragma mark - ASPingServiceDelegate
- (void)pingService:(ASPingService*)service pingingWithDuration:(NSTimeInterval)millionSeconds seq:(uint16_t)seq
-(void)pingService:(ASPingService *)service singlePing:(uint16_t)seq finishedWithDuration:(NSTimeInterval)millionSeconds
{
[self.delegate didGotBusinessServiceState:true host:_pingingHostList.firstObject millionSeconds:millionSeconds];
}
- (void)pingService:(ASPingService*)service pingTimeout:(uint16_t)seq
{
if(!_businessHostList){return;}
NSInteger index = [_businessHostList indexOfObject:service.targetHost];
if(index==NSNotFound){
return;//在处理www.baidu.com
}
[self.delegate didGotBusinessServiceState:true host:service.targetHost hostIndex:index millionSeconds:millionSeconds];
[_pingingHostList removeObject:service.targetHost];
}
- (void)pingService:(ASPingService*)service tmporaryErrorHappens:(NSError*)error seq:(uint16_t)seq
-(void)pingService:(ASPingService *)service singlePingTimeout:(uint16_t)seq
{
if(!_businessHostList){return;}
NSInteger index = [_businessHostList indexOfObject:service.targetHost];
if(index==NSNotFound){
return;//在处理www.baidu.com
}
[_pingingHostList removeObject:service.targetHost];
[self.delegate didGotBusinessServiceState:false host:service.targetHost hostIndex:index millionSeconds:0];
}
- (void)pingService:(ASPingService*)service failedToStartWithError:(NSError*)error
-(void)pingService:(ASPingService *)service singlePing:(uint16_t)seq tmporaryErrorHappens:(NSError *)error
{
[_pingingHostList removeObjectAtIndex:0];
[self _readHostAndPing];
if(!_businessHostList){return;}
NSInteger index = [_businessHostList indexOfObject:service.targetHost];
if(index==NSNotFound){
return;//在处理www.baidu.com
}
[_pingingHostList removeObject:service.targetHost];
[self.delegate didGotBusinessServiceState:false host:service.targetHost hostIndex:index millionSeconds:0];
}
- (void)pingService:(ASPingService*)service stopWithError:(NSError*_Nullable)error successPingCount:(NSInteger)successPingCount
{
if(!error){
_successPingHostCount++;
}else{
[self.delegate didGotBusinessServiceState:false host:_pingingHostList.firstObject millionSeconds:0];
if([service.targetHost isEqualToString:@"www.baidu.com"]){
[self.delegate didGotIPState:successPingCount>0];
//开始业务ping
_pingingHostList = _businessHostList.mutableCopy;
_pingService.pingCount = 1;
}
[self _readHostAndPing];
}
#pragma mark - ASReachabilityDelegate
- (void)reachabilityBecomesNotReachable:(ASReachability*)ability
{
_isReachabilityFinished = true;
[self.delegate didGotNetworkStatus:ability.status signalStrength:CRMNetSignalStrengthNone];
[self.delegate didGotIPState:false];
}
- (void)reachabilityChangedToWiFi:(ASReachability*)ability
{
_isReachabilityFinished = true;
[self.delegate didGotNetworkStatus:ability.status signalStrength:CRMNetSignalStrengthStrong];
[self _startIPService];
[self.delegate didGotIPState:[self _isWifiIPNormal]];
}
- (void)reachabilityChangedToWWAN:(ASReachability*)ability
type:(ASCellularNetType)type signalStrength:(ASCelluarSignalStrength)strength
{
_isReachabilityFinished = true;
[self.delegate didGotNetworkStatus:ability.status signalStrength:strength == ASCelluarSignalStrengthStrong?CRMNetSignalStrengthStrong:CRMNetSignalStrengthWeak];
[self _startIPService];
[self.delegate didGotIPState:[self _isCelluarIPNormal]];
}
#pragma mark - Ping
- (void)_readHostAndPing
{
if(!_pingService){return;}
else if (!_pingingHostList.count){
if(!_pingService){
_pingService = [[ASPingService alloc] initWithDelegate:self];
}
if (!_pingingHostList.count){
[self.delegate didFinishedBusinessService:_successPingHostCount == _businessHostList.count];
[self stopDetecting];
return;
}
_pingService.targetHost = _pingingHostList.firstObject;
......@@ -133,20 +119,10 @@
[_reachability stopObserving];
}
}
- (void)_startIPService
{
if(!_interfaceService){
_interfaceService = [[ASInterfaceService alloc] init];
}
[_interfaceService refreshAvailableInterfaces];
}
- (void)stopIPService
{
_interfaceService = nil;
}
- (BOOL)_isWifiIPNormal
{
NSArray<NSString *> *wifiIPs = _interfaceService.getWiFiIP;
ASNetworkInterfaceInfo * info = [[ASNetworkInterfaceInfo alloc] init];
NSArray<NSString *> *wifiIPs = [info getWiFiIPAndOnlyIPV4:true];
if(!wifiIPs.count){
return false;
}
......@@ -157,7 +133,8 @@
}
- (BOOL)_isCelluarIPNormal
{
NSArray<NSString *> *cellularIps = _interfaceService.getCelluarIP;
ASNetworkInterfaceInfo * info = [[ASNetworkInterfaceInfo alloc] init];
NSArray<NSString *> *cellularIps = [info getCelluarIPAndOnlyIPV:true];
if(!cellularIps.count){
return false;
}
......@@ -166,4 +143,27 @@
}
return true;
}
#pragma mark - ASReachabilityDelegate
- (void)reachabilityStatusDidChanged:(ASReachabilityStatus)status statusDesc:(nonnull NSString *)desc {
NSLog(@"reachability status desc:%@",desc);
if(status == ASReachabilityStatusNotReachable){
[self.delegate didGotNetworkStatus:status signalStrength:CRMNetSignalStrengthNone];
}else if (status == ASReachabilityStatusWifi){
[self.delegate didGotNetworkStatus:status signalStrength:CRMNetSignalStrengthStrong];
}else if (status == ASReachabilityStatusWWAN){
ASCellularNet * celluarNet = [[ASCellularNet alloc] init];
CRMNetSignalStrength strength = CRMNetSignalStrengthNone;
if(celluarNet){
strength = (celluarNet.signalStrength==ASCelluarSignalStrengthStrong?CRMNetSignalStrengthStrong:CRMNetSignalStrengthWeak);
}
[self.delegate didGotNetworkStatus:status signalStrength:strength];
}else{
//preserved
}
[self _stopReachabilityService];
_pingService = [[ASPingService alloc] initWithDelegate:self];
_pingService.targetHost = @"www.baidu.com";
_pingService.pingCount = 3;
[_pingService starts];
}
@end
......@@ -23,13 +23,14 @@
@implementation CRMNetDetectView
{
CRMNetDetectService * _service;
NSArray<NSDictionary*>*_businessHostInfo;
}
-(instancetype)initWithFrame:(CGRect)frame{
if(self = [super initWithFrame:frame]){
[self _initBaseCellData];
_service = [[CRMNetDetectService alloc] initWithDelegate:self];
_tableView = [[UITableView alloc] initWithFrame:frame];
_tableView.backgroundColor = UIColor.groupTableViewBackgroundColor;
_tableView.backgroundColor = [UIColor colorWithRed:243/255.0 green:243/255.0 blue:243/255.0 alpha:1];
_tableView.dataSource = self;
_tableView.rowHeight = 44;
_tableView.tableFooterView = [self _footView];
......@@ -72,10 +73,12 @@
#pragma mark - Interface
-(void)startsChecking
{
[self setBusinessHosts:_businessHostInfo];
[_service startsDetecting];
}
-(void)setBusinessHosts:(NSArray<NSDictionary *> *)hosts
{
_businessHostInfo = hosts;
if(_cellDatas.count){
[self _initBaseCellData];
}
......@@ -92,24 +95,36 @@
data.leftTitle = name;
[_cellDatas addObject:data];
}
[self.tableView reloadData];
_service.businessHostList = hostList;
}
#pragma mark -CRMNetDetectServiceDelegate
- (void)didGotNetworkStatus:(ASReachabilityStatus)status signalStrength:(CRMNetSignalStrength)strength
{
_reachabilityData.state = (status == ASReachabilityStatusWifi ||(status == ASReachabilityStatusWWAN))?CRMNetDetectCellStateNormal:CRMNetDetectCellStateNotNormal;
_signalStrengthData.state = (strength==CRMNetSignalStrengthNone)?CRMNetDetectCellStateNotNormal:CRMNetDetectCellStateNormal;
if(status == ASReachabilityStatusNotReachable){
_signalStrengthData.rightText = @"无";
}else{
_signalStrengthData.rightText =(strength==CRMNetSignalStrengthStrong)?@"强":@"弱";
}
[self.tableView reloadData];
}
- (void)didGotIPState:(BOOL)isNormal
{
_ipData.state = isNormal ? CRMNetDetectCellStateNormal :CRMNetDetectCellStateNotNormal;
[self.tableView reloadData];
}
- (void)didGotBusinessServiceState:(BOOL)isNormal host:(NSString*)host millionSeconds:(NSTimeInterval)millionSeconds
- (void)didGotBusinessServiceState:(BOOL)isNormal host:(nonnull NSString *)host hostIndex:(NSInteger)hostIndex millionSeconds:(NSTimeInterval)millionSeconds
{
CRMNetDetectCellData * data = _cellDatas[hostIndex+_staticCellDataCount];
data.state = isNormal? CRMNetDetectCellStateNormal :CRMNetDetectCellStateNotNormal;
data.rightText = isNormal ? [NSString stringWithFormat:@"正常 %ld ms",(NSInteger)millionSeconds] : @"异常";
[self.tableView reloadData];
}
- (void)didFinishedBusinessService:(BOOL)isNormal
{
_serverConnectData.state =isNormal? CRMNetDetectCellStateNormal :CRMNetDetectCellStateNotNormal;
[self.tableView reloadData];
}
#pragma mark - Getters
-(UIButton *)checkButton
......@@ -117,7 +132,7 @@
if(!_checkButton){
_checkButton = [[UIButton alloc] init];
_checkButton.layer.cornerRadius = 3;
_checkButton.backgroundColor = UIColor.orangeColor;
_checkButton.backgroundColor = [UIColor colorWithRed:238/255.0 green:131/255.0 blue:68/255.0 alpha:1];
[_checkButton setTitle:@"重新检测" forState:UIControlStateNormal];
[_checkButton setTitleColor:UIColor.whiteColor forState:UIControlStateNormal];
[_checkButton.titleLabel setFont:[UIFont systemFontOfSize:14]];
......@@ -139,12 +154,12 @@
{
CGFloat marginTop = 20;
CGFloat marginBottom = 30;
CGFloat btnHeight = 60;
CGFloat btnHeight = 100;
CGFloat seperateHeight = 15;
UIView * view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.bounds.size.width, marginTop+marginBottom+btnHeight)];
UIView * view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.bounds.size.width, marginTop+marginBottom+btnHeight+seperateHeight)];
view.backgroundColor = UIColor.whiteColor;
UIView * seperateView = [[UIView alloc] initWithFrame:CGRectMake(0, view.bounds.size.height-seperateHeight, view.bounds.size.width, seperateHeight)];
seperateView.backgroundColor = UIColor.groupTableViewBackgroundColor;
seperateView.backgroundColor = [UIColor colorWithRed:243/255.0 green:243/255.0 blue:243/255.0 alpha:1];
[view addSubview:seperateView];
return view;
}
......
PODS:
- ASNetwork (1.0.0)
- ASNetwork (1.0.2)
- CRMNetDetect (0.1.0):
- ASNetwork
......@@ -15,7 +15,7 @@ EXTERNAL SOURCES:
:path: "../"
SPEC CHECKSUMS:
ASNetwork: a1bdef0d07fc5c4c78cb01a380baaa812ee9944e
ASNetwork: 3beefd29932096032e386d1a949cb9255eda7d54
CRMNetDetect: 30b81d339ea6293c8cd2cee10d31197a4da7b16c
PODFILE CHECKSUM: f5247f2e9f0505f8db1736cd0e5716b42c1a2390
......
......@@ -26,17 +26,17 @@ typedef NS_ENUM(NSInteger,ASCelluarSignalStrength){
};
@interface ASCellularNet : NSObject
/**
* @brief 更新当前蜂窝流量接入情况,包括接入类型,信号强度等;网络变化等情形时,需主动查询刷新状态.
* @brief 当前蜂窝网接入信息,若无蜂窝接入信息则返回nil.
**/
- (void)updateNetworkInfo;
- (nullable instancetype)init;
/**
* @brief 接入网络类型系统描述,包括CTRadioAccessTechnologyEdge等;若用户不启用蜂窝流量,会返回nil
* @brief 接入网络类型系统描述,包括CTRadioAccessTechnologyEdge等
**/
@property(nonatomic,copy,nullable,readonly)NSString * accessNetValue;
@property(nonatomic,copy,readonly)NSString * typeValue;
/**
* @brief accessNetValue的枚举映射.
**/
@property(nonatomic,assign,readonly)ASCellularNetType accessNet;
@property(nonatomic,assign,readonly)ASCellularNetType type;
/**
* @brief 信号强度。基于accessNet的一个估算,默认4G/5G为strong,其余为weak;
* 若想检测相应域名连接是否稳定、快速(强弱网),你应当使用icmp/http进行检测RTT等耗时
......
......@@ -13,6 +13,11 @@
ASCellularNetType _accessType;
ASCelluarSignalStrength _signalStrength;
}
-(instancetype)init{
if(self = [super init]){
[self updateNetworkInfo];
}return _accessTypeValue ? self : nil;
}
-(void)updateNetworkInfo
{
CTTelephonyNetworkInfo *networkInfo = [[CTTelephonyNetworkInfo alloc] init];
......@@ -29,11 +34,11 @@
_accessType = [self _parsedAccessType];
_signalStrength = [self _mapSignalStrengthEvaluatedForType:_accessType];
}
-(NSString *)accessNetValue
-(NSString *)typeValue
{
return _accessTypeValue;
}
-(ASCellularNetType)accessNet
-(ASCellularNetType)type
{
return _accessType;
}
......@@ -45,7 +50,7 @@
-(ASCellularNetType)_parsedAccessType
{
ASCellularNetType type = ASCellularTypeUnknown;
NSString * value = [self accessNetValue];
NSString * value = [self typeValue];
NSArray * secondGValues = @[
CTRadioAccessTechnologyEdge,CTRadioAccessTechnologyGPRS
];
......
//
// ASNetwork.h
// ASNetwork
//
// Created by 坚鹏 on 2024/10/18.
//
#ifndef ASNetwork_h
#define ASNetwork_h
#import <ASNetwork/ASReachability.h>
#import <ASNetwork/ASNetworkInterfaceInfo.h>
#import <ASNetwork/ASPingService.h>
#import <ASNetwork/ASCellularNet.h>
#endif /* ASNetwork_h */
......@@ -31,10 +31,10 @@ typedef NS_ENUM(NSInteger,ASIPType)
/**
* @class 静态查询当前已连接的接口,包括wifi或蜂窝ip等.
**/
@interface ASInterfaceService : NSObject
@interface ASNetworkInterfaceInfo : NSObject
/**
* @brief 刷新可用接口,需主动调用.
* @brief 刷新可用接口
**/
- (void)refreshAvailableInterfaces;
......@@ -45,13 +45,15 @@ typedef NS_ENUM(NSInteger,ASIPType)
/**
* @return 获取WIFI对应ip列表,当ipv4+ipv6同时启用时会返回多个.
* @param onlyIPv4 只返回ipv4的地址.
**/
- (NSArray<NSString*>* _Nullable)getWiFiIP;
- (NSArray<NSString*>* _Nullable)getWiFiIPAndOnlyIPV4:(BOOL)onlyIPv4;
/**
* @return 查询蜂窝IP,当多种sim卡启用或ipv6启用时也可能返回多个
* @param onlyIPv4 只返回ipv4的地址.
**/
- (NSArray<NSString*>*_Nullable)getCelluarIP;
- (NSArray<NSString*>*_Nullable)getCelluarIPAndOnlyIPV:(BOOL)onlyIPv4;
/**
* @property 可用的接口IP列表
......
......@@ -5,15 +5,19 @@
// Created by 坚鹏 on 2024/10/15.
//
#import "ASInterfaceService.h"
#import "ASNetworkInterfaceInfo.h"
#include <ifaddrs.h>
#include <arpa/inet.h>
#include <net/if.h>
@interface ASIPEntity()
- (instancetype)initWithInterfaceName:(NSString*)name ip:(NSString*)ip isIpv6:(BOOL)isIpv6;
@end
@implementation ASInterfaceService
@implementation ASNetworkInterfaceInfo
-(instancetype)init{
if(self = [super init]){
[self refreshAvailableInterfaces];
}return self;
}
-(void)refreshAvailableInterfaces
{
struct ifaddrs *interfaces = NULL;
......@@ -48,22 +52,22 @@
freeifaddrs(interfaces);
_availableIPList = newIPList;
}
-(NSArray<NSString *> *)getWiFiIP
-(NSArray<NSString *> *)getWiFiIPAndOnlyIPV4:(BOOL)onlyIPv4
{
NSMutableArray * list;
for (ASIPEntity * ipEntity in _availableIPList) {
if(ipEntity.type == ASIPTypeWiFi){
if(ipEntity.type == ASIPTypeWiFi && (!onlyIPv4 || ipEntity.isIpv4)){
if(!list){list = @[].mutableCopy;}
[list addObject:ipEntity.value];
}
}
return list;
}
-(NSArray<NSString *> *)getCelluarIP
-(NSArray<NSString *> *)getCelluarIPAndOnlyIPV:(BOOL)onlyIPv4
{
NSMutableArray * list;
for (ASIPEntity * ipEntity in _availableIPList) {
if(ipEntity.type == ASIPTypeCelluar){
if(ipEntity.type == ASIPTypeCelluar&& (!onlyIPv4 || ipEntity.isIpv4)){
if(!list){list = @[].mutableCopy;}
[list addObject:ipEntity.value];
}
......@@ -104,6 +108,7 @@
}
-(BOOL)isPrivateIP:(NSString*)value
{
if([value isKindOfClass:NSString.class] == false){return false;}
if(_isIpv6){
return [self isIPv6PrivateAddress:value];
}
......@@ -120,12 +125,12 @@
}
// 判断 IPv6 地址是否为 Link-Local 地址
- (BOOL)isIPv6LinkLocalAddress:(NSString *)ipAddress {
return [ipAddress hasPrefix:@"fe80"];
return [ipAddress isKindOfClass:NSString.class]&&[ipAddress hasPrefix:@"fe80"];
}
// 判断 IPv6 地址是否为私有 IP 地址(Unique Local Address, ULA)
- (BOOL)isIPv6PrivateAddress:(NSString *)ipAddress {
return [ipAddress hasPrefix:@"fc00"] || [ipAddress hasPrefix:@"fd00"];
return [ipAddress isKindOfClass:NSString.class] && ([ipAddress hasPrefix:@"fc00"] || [ipAddress hasPrefix:@"fd00"]);
}
-(NSString *)description
{
......
......@@ -11,13 +11,13 @@ NS_ASSUME_NONNULL_BEGIN
@class ASPingService;
@protocol ASPingServiceDelegate <NSObject>
- (void)pingService:(ASPingService*)service pingingWithDuration:(NSTimeInterval)millionSeconds seq:(uint16_t)seq;//正常收到回调
- (void)pingService:(ASPingService*)service pingTimeout:(uint16_t)seq;//ping超时,可能来自自身控制,也可能来自icmp通知,这里不做区分
- (void)pingService:(ASPingService*)service tmporaryErrorHappens:(NSError*)error seq:(uint16_t)seq;//可恢复的错误,后续会继续ping
//单次ping回调:成功、超时、出错.
- (void)pingService:(ASPingService*)service singlePing:(uint16_t)seq finishedWithDuration:(NSTimeInterval)millionSeconds;
- (void)pingService:(ASPingService*)service singlePingTimeout:(uint16_t)seq;
- (void)pingService:(ASPingService*)service singlePing:(uint16_t)seq tmporaryErrorHappens:(NSError*)error;
@optional
- (void)pingingServiceDidStart:(ASPingService*)service;//[调用starts]成功
- (void)pingService:(ASPingService*)service failedToStartWithError:(NSError*)error;//调用[starts]失败
- (void)pingService:(ASPingService*)service stopWithError:(NSError*_Nullable)error successPingCount:(NSInteger)successPingCount;//ping终止,error为空时则为正常终止,若successPingCount为0,你可以考虑使用http替代进行网络检测
@end
@interface ASPingService : NSObject
......@@ -29,11 +29,14 @@ NS_ASSUME_NONNULL_BEGIN
- (void)stops;
@property(nonatomic,assign)BOOL usingICMPv6;//大陆的v6支持有限,一般不建议开启.
@property(nonatomic,assign,readonly)BOOL isPinging;//判断是否在ping中.
@property(nonatomic,copy)NSString * targetHost;//ping目标路径,不能为空.
@property(nonatomic,assign)NSInteger pingCount;//默认为1即只ping一次.
/**
* @property timeoutSeconds 单次Ping耗时,默认为2s,超出2s收不到当次ping回调按超时处理;必须大于等于1,小于1则忽略.
**/
@property(nonatomic,assign)NSTimeInterval timeoutSeconds;
@property(nonatomic,weak,readonly)id<ASPingServiceDelegate>delegate;
@property(nonatomic,assign,readonly)BOOL isPinging;
@property(nonatomic,copy)NSString * targetHost;
@property(nonatomic,assign)NSInteger pingCount;//默认为1即只ping一次。
@property(nonatomic,assign)NSTimeInterval timeoutSeconds;//默认为2s,超出2s收不到当次ping回调,则取消当次ping,就算后续收到回调也ignore;不建议设置过低.
@end
NS_ASSUME_NONNULL_END
......@@ -19,6 +19,7 @@ static uint16_t KASPingNotStartedSeq = -1;
NSTimeInterval _startPingTime;
uint16_t _pingingSeq;
NSInteger _successPingCount;
NSMutableArray<NSNumber*>*_pingDurationList;
}
-(instancetype)initWithDelegate:(id<ASPingServiceDelegate>)delegate{
if (self = [super init]) {
......@@ -32,15 +33,13 @@ static uint16_t KASPingNotStartedSeq = -1;
-(void)starts
{
if(_isPinging){
if([self.delegate respondsToSelector:@selector(pingService:failedToStartWithError:)]){
[self.delegate pingService:self failedToStartWithError:[self _createErrorWithMsg:@"Pinging Aready!"]];
}
return;
}
NSAssert(_targetHost, @"target host could not be nil.");
NSAssert(_pingCount >=1, @"Ping count could not smaller than 1");
NSAssert(_timeoutSeconds >=1, @"Ping timeout could not smaller than 1");
_isPinging = true;
_pingDurationList = @[].mutableCopy;
_samplePing = [[ASSimplePing alloc] initWithHostName:_targetHost];
_samplePing.delegate = self;
_samplePing.addressStyle = _usingICMPv6?ASSimplePingAddressStyleICMPv6:ASSimplePingAddressStyleICMPv4;
......@@ -72,9 +71,10 @@ static uint16_t KASPingNotStartedSeq = -1;
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(_gotManulyTimeoutNotification) object:nil];
_pingingSeq ++;
if(_pingingSeq >= _pingCount){
NSInteger successCount = _successPingCount;
[self stops];
if([self.delegate respondsToSelector:@selector(pingService:stopWithError: successPingCount:)]){
[self.delegate pingService:self stopWithError:nil successPingCount:_successPingCount];
[self.delegate pingService:self stopWithError:nil successPingCount:successCount];
}
return;
}
......@@ -86,8 +86,8 @@ static uint16_t KASPingNotStartedSeq = -1;
{
NSLog(@"Request timeout for icmp_seq %hu",_pingingSeq);
//当次ping超时
if([self.delegate respondsToSelector:@selector(pingService:pingTimeout:)]){
[self.delegate pingService:self pingTimeout:_pingingSeq];
if([self.delegate respondsToSelector:@selector(pingService:singlePingTimeout:)]){
[self.delegate pingService:self singlePingTimeout:_pingingSeq];
}
//开启下次ping
[self _sendPingOnce];
......@@ -106,6 +106,14 @@ static uint16_t KASPingNotStartedSeq = -1;
}
return (now - _startPingTime)/1000;
}
#pragma mark - Setter
-(void)setTimeoutSeconds:(NSTimeInterval)timeoutSeconds
{
if(timeoutSeconds<1){
return;
}
_timeoutSeconds = timeoutSeconds;
}
#pragma mark - ASSimplePingDelegate
- (void)simplePing:(ASSimplePing *)pinger didStartWithAddress:(NSData *)address
{
......@@ -130,8 +138,8 @@ static uint16_t KASPingNotStartedSeq = -1;
- (void)simplePing:(ASSimplePing *)pinger didFailToSendPacket:(NSData *)packet sequenceNumber:(uint16_t)sequenceNumber error:(NSError *)error
{
NSLog(@"did failed to send ping");
if([self.delegate respondsToSelector:@selector(pingService:tmporaryErrorHappens:seq:)]){
[self.delegate pingService:self tmporaryErrorHappens:error seq:_pingingSeq];
if([self.delegate respondsToSelector:@selector(pingService:singlePing:tmporaryErrorHappens:)]){
[self.delegate pingService:self singlePing:_pingingSeq tmporaryErrorHappens:error];
}
[self _sendPingOnce];//resend again.
}
......@@ -140,8 +148,9 @@ static uint16_t KASPingNotStartedSeq = -1;
if(sequenceNumber == _pingingSeq){
NSTimeInterval duration = [self _getPingTimePastMicroSeconds];
NSLog(@"%ld bytes from %@: icmp_seq=%hu time=%.3f ms",packet.length,_targetHost,sequenceNumber,duration);
[self.delegate pingService:self pingingWithDuration:duration seq:sequenceNumber];
[self.delegate pingService:self singlePing:sequenceNumber finishedWithDuration:duration];
_successPingCount++;
[_pingDurationList addObject:@(duration)];
[self _sendPingOnce];
}else{
NSLog(@"got outdate sequenceNumber:%hu",sequenceNumber);
......@@ -150,8 +159,8 @@ static uint16_t KASPingNotStartedSeq = -1;
- (void)simplePing:(ASSimplePing *)pinger didReceiveUnexpectedPacket:(NSData *)packet
{
NSLog(@"did failed to send ping");
if([self.delegate respondsToSelector:@selector(pingService:tmporaryErrorHappens:seq:)]){
[self.delegate pingService:self tmporaryErrorHappens:[self _createErrorWithMsg:@"ReceiveUnexpectedPacket"] seq:_pingingSeq];
if([self.delegate respondsToSelector:@selector(pingService:singlePing:tmporaryErrorHappens:)]){
[self.delegate pingService:self singlePing:_pingingSeq tmporaryErrorHappens:[self _createErrorWithMsg:@"ReceiveUnexpectedPacket"]];
}
[self _sendPingOnce];//ignore,send again.
}
......
......@@ -6,7 +6,6 @@
//
#import <Foundation/Foundation.h>
#import <ASNetwork/ASCellularNet.h>
NS_ASSUME_NONNULL_BEGIN
......@@ -18,17 +17,10 @@ typedef NS_ENUM(NSInteger,ASReachabilityStatus){
};
@class ASReachability;
@protocol ASReachabilityDelegate <NSObject>
- (void)reachabilityBecomesNotReachable:(ASReachability*)ability;
/**
* @brief 使用Wifi时回调;可考虑使用ASInterfaceService.getWiFiIP进一步获取对应IP
**/
- (void)reachabilityChangedToWiFi:(ASReachability*)ability;
/**
* @brief 使用蜂窝时回调;可考虑使用ASInterfaceService.getCelluarIP进一步获取对应IP
* @brief 网络接入状态监听;当status为WWAN时可以考虑使用ASCellularNet获取更详细的信息
**/
- (void)reachabilityChangedToWWAN:(ASReachability*)ability
type:(ASCellularNetType)type signalStrength:(ASCelluarSignalStrength)strength;
- (void)reachabilityStatusDidChanged:(ASReachabilityStatus)status statusDesc:(NSString*)desc;
@end
/**
* @class 当前activate network探测.
......@@ -55,6 +47,7 @@ typedef NS_ENUM(NSInteger,ASReachabilityStatus){
* @property status 当前activate network的状态.
**/
@property(nonatomic,assign,readonly)ASReachabilityStatus status;
@property(nonatomic,copy,nullable,readonly)NSString * statusDesc;
@property(nonatomic,weak,readonly)id<ASReachabilityDelegate>delegate;
@end
......
......@@ -10,10 +10,7 @@
#import <netinet/in.h>
@interface ASReachability()
{
SCNetworkReachabilityFlags _reachabilityFlags;
}
@property(nonatomic,strong,nullable)ASCellularNet * celluarService;
@property (nonatomic) SCNetworkReachabilityRef reachabilityRef;
@end
@implementation ASReachability
......@@ -34,7 +31,18 @@ static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReach
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(checkCurrentNetworkStatus) name:UIApplicationDidBecomeActiveNotification object:nil];
}return self;
}
-(NSString *)statusDesc{
switch (_status) {
case ASReachabilityStatusWWAN:
return @"蜂窝网络";
case ASReachabilityStatusWifi:
return @"WiFi";
case ASReachabilityStatusNotReachable:
return @"无网络";
default:
return @"未知";
}
}
-(void)startsObserving
{
if(_reachabilityRef){
......@@ -47,23 +55,26 @@ static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReach
}
// 初始化时检查网络状态
[self checkCurrentNetworkStatus];
if(!_reachabilityRef){
return;//maybe stop after first check
}
SCNetworkReachabilityContext context = {0, (__bridge void *)(self), NULL, NULL, NULL};
SCNetworkReachabilitySetCallback(self.reachabilityRef, ReachabilityCallback, &context);
SCNetworkReachabilityScheduleWithRunLoop(self.reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
SCNetworkReachabilityScheduleWithRunLoop(self.reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
}
-(void)stopObserving
{
if (_reachabilityRef) {
SCNetworkReachabilityUnscheduleFromRunLoop(_reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
SCNetworkReachabilityUnscheduleFromRunLoop(_reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
CFRelease(_reachabilityRef);
_reachabilityRef = NULL;
}
}
- (void)checkCurrentNetworkStatus {
if(!_reachabilityRef){return;}
SCNetworkReachabilityFlags flags;
if (SCNetworkReachabilityGetFlags(self.reachabilityRef, &flags)) {
if (SCNetworkReachabilityGetFlags(_reachabilityRef, &flags)) {
[self handleNetworkChangeWithFlags:flags];
} else {
NSLog(@"Failed to retrieve network status");
......@@ -71,13 +82,9 @@ static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReach
}
// 处理网络状态变化
- (void)handleNetworkChangeWithFlags:(SCNetworkReachabilityFlags)flags {
if(_reachabilityFlags == flags){
return;
}
BOOL isReachable = (flags & kSCNetworkReachabilityFlagsReachable);
BOOL needsConnection = (flags & kSCNetworkReachabilityFlagsConnectionRequired);
if (isReachable && !needsConnection) {
NSLog(@"Network is reachable");
// 进一步检查网络类型
[self detectConnectionTypeWithFlags:flags];
} else {
......@@ -89,32 +96,29 @@ static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReach
} else if (isReachable && isTransient) {
NSLog(@"Network connection is transient (e.g., dial-up or other temporary connection)");
} else {
NSLog(@"Network is not reachable");
}
_status = ASReachabilityStatusNotReachable;
[self.delegate reachabilityBecomesNotReachable:self];
[self _notifyStatusChanged:ASReachabilityStatusNotReachable];
}
}
// 检测当前的网络连接类型(Wi-Fi 或 蜂窝)
- (void)detectConnectionTypeWithFlags:(SCNetworkReachabilityFlags)flags {
if ((flags & kSCNetworkReachabilityFlagsIsWWAN) != 0) {
// 通过蜂窝网络连接
if(!_celluarService){_celluarService = [ASCellularNet new];}
[_celluarService updateNetworkInfo];
ASCellularNetType type = _celluarService.accessNet;
NSLog(@"Connected via Cellular of %ld",type);
_status = ASReachabilityStatusWifi;
[self.delegate reachabilityChangedToWWAN:self type:type signalStrength:_celluarService.signalStrength];
[self _notifyStatusChanged:ASReachabilityStatusWWAN];
} else {
// 通过Wi-Fi或其他网络连接
NSLog(@"Connected via Wi-Fi");
_status = ASReachabilityStatusWWAN;
[self.delegate reachabilityChangedToWiFi:self];
[self _notifyStatusChanged:ASReachabilityStatusWifi];
}
}
#pragma mark - Privates
- (void)_notifyStatusChanged:(ASReachabilityStatus)newStatus
{
if(_status == newStatus){return;}
_status = newStatus;
[self.delegate reachabilityStatusDidChanged:newStatus statusDesc:self.statusDesc];
}
- (SCNetworkReachabilityRef _Nullable)_createHostReachabilityRef
{
return _host ? SCNetworkReachabilityCreateWithName(NULL, _host.UTF8String) : nil;
......
PODS:
- ASNetwork (1.0.0)
- ASNetwork (1.0.2)
- CRMNetDetect (0.1.0):
- ASNetwork
......@@ -15,7 +15,7 @@ EXTERNAL SOURCES:
:path: "../"
SPEC CHECKSUMS:
ASNetwork: a1bdef0d07fc5c4c78cb01a380baaa812ee9944e
ASNetwork: 3beefd29932096032e386d1a949cb9255eda7d54
CRMNetDetect: 30b81d339ea6293c8cd2cee10d31197a4da7b16c
PODFILE CHECKSUM: f5247f2e9f0505f8db1736cd0e5716b42c1a2390
......
......@@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0.0</string>
<string>1.0.2</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
......
......@@ -11,7 +11,8 @@
#endif
#import "ASCellularNet.h"
#import "ASInterfaceService.h"
#import "ASNetwork.h"
#import "ASNetworkInterfaceInfo.h"
#import "ASPingService.h"
#import "ASReachability.h"
#import "ASSimplePing.h"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment