白水

iOS 框架详解—「Security 网络通信安全策略」

引导


AFNetWorking 基本是 iOS 开发中使用网络通信框架的标配,这个框架本身比较庞大,也很复杂,但是使用起来非常非常简单。极大地提高开发效率,让我们更加专注于业务逻辑实现。

SourceCodeToolsClassPublic-Codeidea

本篇文章主要从【AFNetworkReachabilityManager 网络状态监听模块】学习总结,该模块学习将续更 ~
在「时间 & 知识 」有限内,总结的文章难免有「未全、不足 」的地方,还望各位好友指出,可留言指正或是补充,以提高文章质量@CoderLN著;

Source Code【源码学习】


AFNetworkReachabilityManager是用来监测网络状态,网络状态管理的类,他可以通过设置状态改变回调来获得当前网络状态。

对于该类,我们结合着看 .h.m 来说。

1
2
3
4
5
6
7
// 网络的状态值有以下四种
typedef NS_ENUM(NSInteger, AFNetworkReachabilityStatus) {
AFNetworkReachabilityStatusUnknown = -1, // 未知
AFNetworkReachabilityStatusNotReachable = 0, // 无网络
AFNetworkReachabilityStatusReachableViaWWAN = 1, // 蜂窝网络
AFNetworkReachabilityStatusReachableViaWiFi = 2, // WIFI
};

首先看到的是4个属性,其意思 都已经注释上了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
The current network reachability status.
*/
// 当前网络的状态,就是枚举中的类型
@property (readonly, nonatomic, assign) AFNetworkReachabilityStatus networkReachabilityStatus;

/**
Whether or not the network is currently reachable.
*/
// 网络是不是当前可用的
@property (readonly, nonatomic, assign, getter = isReachable) BOOL reachable;

/**
Whether or not the network is currently reachable via WWAN.
*/
// 通过WWAN连接的网络是不是当前可用的
@property (readonly, nonatomic, assign, getter = isReachableViaWWAN) BOOL reachableViaWWAN;

/**
Whether or not the network is currently reachable via WiFi.
*/
// 通过WIFI连接的网络是不是当前可用的
@property (readonly, nonatomic, assign, getter = isReachableViaWiFi) BOOL reachableViaWiFi;

@name Initialization【初始化】

AFNetworkReachabilityManager提供了五种初始化的方法,下面一一介绍:
1、可以通过单例方法初始化

1
2
3
4
5
6
7
8
9
10
+ (instancetype)sharedManager {
static AFNetworkReachabilityManager *_sharedManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{// 通过dispatch_once_t保证只执行一次,单线程。
// 调用+ manager初始化方法
_sharedManager = [self manager];
});

return _sharedManager;
}

2、在第一种方法,单例里面调用了第二种通过默认的socket地址初始化方法,返回一个manager对象,sin_family表示协议族,AF_INET表示TCP/IP协议族的地址。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
+ (instancetype)manager
{
#if (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 90000) || (defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101100)
// 声明sockaddr_in结构体
struct sockaddr_in6 address;
// address清零
bzero(&address, sizeof(address));
// address赋值
address.sin6_len = sizeof(address);
address.sin6_family = AF_INET6;
#else
struct sockaddr_in address;
bzero(&address, sizeof(address));
address.sin_len = sizeof(address);
address.sin_family = AF_INET;
#endif
// 调用+ [managerForAddress:]方法
return [self managerForAddress:&address];
}

3、在第二种方法,里面又调用了第三种通过传入一个socket地址来初始化。

1
2
3
4
5
6
7
8
9
10
+ (instancetype)managerForAddress:(const void *)address {
// 生成SCNetworkReachabilityRef
SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr *)address);
// 调用- [initWithReachability:]方法
AFNetworkReachabilityManager *manager = [[self alloc] initWithReachability:reachability];

CFRelease(reachability);

return manager;
}

4、在第三种方法,又调用了第四种初始化方法,因为该方法的后缀里面有NS_DESIGNATED_INITIALIZER,所以最终都会调到它,这里就是做了初始化的工作,将起始的网络状态定为Unknown。

1
2
3
4
5
6
7
8
9
10
11
- (instancetype)initWithReachability:(SCNetworkReachabilityRef)reachability {
self = [super init];
if (!self) {
return nil;
}

_networkReachability = CFRetain(reachability);
self.networkReachabilityStatus = AFNetworkReachabilityStatusUnknown;

return self;
}

5、第五种方法,就是可以根据特定的域来初始化。

1
2
3
4
5
6
7
8
9
+ (instancetype)managerForDomain:(NSString *)domain {
SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(kCFAllocatorDefault, [domain UTF8String]);

AFNetworkReachabilityManager *manager = [[self alloc] initWithReachability:reachability];

CFRelease(reachability);

return manager;
}

1
2
3
4
5
#pragma mark -
// 初始化结束后,需要设置网络状态改变的回调,在开启监听之后,会将网络状态回调给外部。
- (void)setReachabilityStatusChangeBlock:(void (^)(AFNetworkReachabilityStatus status))block {
self.networkReachabilityStatusBlock = block;
}

初始化相关方法介绍之后,介绍一下监听相关方法
开启监听方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#pragma mark -
- (void)startMonitoring {
// 停止监听
[self stopMonitoring];

if (!self.networkReachability) {
return;
}
// 收到callback调用后,将status通过networkReachabilityStatusBlock回调出去
__weak __typeof(self)weakSelf = self;
AFNetworkReachabilityStatusBlock callback = ^(AFNetworkReachabilityStatus status) {
__strong __typeof(weakSelf)strongSelf = weakSelf;

strongSelf.networkReachabilityStatus = status;
if (strongSelf.networkReachabilityStatusBlock) {
strongSelf.networkReachabilityStatusBlock(status);
}

};
// 声明SCNetworkReachabilityContext结构体
SCNetworkReachabilityContext context = {0, (__bridge void *)callback, AFNetworkReachabilityRetainCallback, AFNetworkReachabilityReleaseCallback, NULL};
// 设置回调
SCNetworkReachabilitySetCallback(self.networkReachability, AFNetworkReachabilityCallback, &context);
// 加到Main runloop里面对其进行监测
SCNetworkReachabilityScheduleWithRunLoop(self.networkReachability, CFRunLoopGetMain(), kCFRunLoopCommonModes);
// 获取当前的网络状态,调用callback
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0),^{
SCNetworkReachabilityFlags flags;
if (SCNetworkReachabilityGetFlags(self.networkReachability, &flags)) {
AFPostReachabilityStatusChange(flags, callback);
}
});
}

如果没有设置回调的话,也可以通过注册通知的方式,收到网络状态的变化。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
static void AFPostReachabilityStatusChange(SCNetworkReachabilityFlags flags, AFNetworkReachabilityStatusBlock block) {
// 获取当前的status
AFNetworkReachabilityStatus status = AFNetworkReachabilityStatusForFlags(flags);
dispatch_async(dispatch_get_main_queue(), ^{
// 返回status值
if (block) {
block(status);
}
// 同时会发送一个通知
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
NSDictionary *userInfo = @{ AFNetworkingReachabilityNotificationStatusItem: @(status) };
[notificationCenter postNotificationName:AFNetworkingReachabilityDidChangeNotification object:nil userInfo:userInfo];
});
}

下面就是停止监听方法,停止监听就是取消在Main Runloop当中的监听。

1
2
3
4
5
6
7
8
// 停止监听就是取消在Main Runloop当中的监听。
- (void)stopMonitoring {
if (!self.networkReachability) {
return;
}

SCNetworkReachabilityUnscheduleFromRunLoop(self.networkReachability, CFRunLoopGetMain(), kCFRunLoopCommonModes);
}

Examples 【AFN 检测网络状态使用】


使用 AFN 框架 来检测网络状态的改变;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// 1.创建检测网络状态管理者
AFNetworkReachabilityManager *manager = [AFNetworkReachabilityManager manager];

// 2.检测网络状态改变
/**
AFNetworkReachabilityStatusUnknown = -1, 未知
AFNetworkReachabilityStatusNotReachable = 0, 无网络
AFNetworkReachabilityStatusReachableViaWWAN = 1, 蜂窝网络
AFNetworkReachabilityStatusReachableViaWiFi = 2, WIFI
*/
[manager setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
switch (status) {
case AFNetworkReachabilityStatusReachableViaWWAN:
NSLog(@"蜂窝网络");
break;
case AFNetworkReachabilityStatusReachableViaWiFi:
NSLog(@"WIFI");
break;
case AFNetworkReachabilityStatusNotReachable:
NSLog(@"没有网络");
break;
case AFNetworkReachabilityStatusUnknown:
NSLog(@"未知");
break;
default:
break;
}
}];

// 3.开始检测
[manager startMonitoring];

Reading


  • 如果在阅读过程中遇到 Error || New ideas,希望你能 issue 我,我会及时补充谢谢。
  • 熬夜写者不易,喜欢可 赞赏 or Star 一波;点击左上角关注 或 『Public:Codeidea』,在 Demo | 文章 | Rss 更新时收到提醒通知,便捷阅读。
既然阅读完了    就在下面留言吧!

标题:iOS 框架详解—「Security 网络通信安全策略」

作者:白水

链接:http://githubidea.github.io/SourceAnnotations/AFN3.0+SourceCode-Security.html

版权声明: 署名-非商业性使用-禁止演绎 4.0 国际 本博客文章除特别声明外均为原创,如需转载请务必保留原链接(可点击进入的链接)和 作者出处。