上篇文章AFNewworking3.1源码解读<三>主要学习了Response Serialization相关部分,着篇主要来学习Reachability和Security。
Reachability
监听网络
reachability主要是基于底层框架SCNetworkReachability实现的,在startMonitoring中设置了网络状态变化时的回调函数,以及最重要的把reachability添加到了MainRunLoop中的kCFRunLoopCommonModes,这样就实现了监听事件一直存活(添加入MainRunLoop,reability相当于一个source),并且当网络状态发生变化时及时响应(设置了事件回调)。相关代码如下:
//设置callback
SCNetworkReachabilitySetCallback(self.networkReachability, AFNetworkReachabilityCallback, &context);
//添加入RunLoop SCNetworkReachabilityScheduleWithRunLoop(self.networkReachability, CFRunLoopGetMain(), kCFRunLoopCommonModes);
网络状态获取
- 直接获取reachable(有网)、reachableViaWWAN(移动网络)、reachableViaWiFi(Wi-Fi网络)属性。
- 监听
AFNetworkingReachabilityDidChangeNotification通知,ReachabilityManager会在网路状态发生变化时主动发送通知。 - 设置网络状态发生变化时的block,setReachabilityStatusChangeBlock:在网络发生变化时也会回调。
- KVO reachable、reachableViaWWAN、reachableViaWiFi,当网络网络状态变化时Reability会主动更新这些属性值,所以如果KVO了这些属性就能实时获取到网络状态了。这三个属性的值都依赖网路状态属性,所以AFNetworkReachabilityManager实现了keyPathsForValuesAffectingValueForKey方法,相关代码如下:
1 | + (NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key { if ([key isEqualToString:@"reachable"] || [key isEqualToString:@"reachableViaWWAN"] || [key isEqualToString:@"reachableViaWiFi"]) { return [NSSet setWithObject:@"networkReachabilityStatus"]; } return [super keyPathsForValuesAffectingValueForKey:key]; } |
停止监听网络
停止监听网络非常简单,只需把reability事件从MainRunloop中删除即可,相关代码如下:
- (void)stopMonitoring {
if (!self.networkReachability) {
return;
}
SCNetworkReachabilityUnscheduleFromRunLoop(self.networkReachability, CFRunLoopGetMain(), kCFRunLoopCommonModes);
}
Security
AFNetworking支持3种Security policy,分别为AFSSLPinningModeNone、AFSSLPinningModePublicKey、AFSSLPinningModeCertificate。当Security policy为AFSSLPinningModeNone时只校验服务器发送的证书是否合法;当Security policy为AFSSLPinningModePublicKey时则通过校验本地certificate中public key和服务器发送的certificate中public key来验证合法性;当Security policy为AFSSLPinningModeCertificate时校验本地certificate和服务器发送的certificate来验证合法性。
certificate获取
AFNetworking会默认获取编译工程中.cer文件,而.cer就是certificate,pinnedCertificates属性中存放着这些.cer文件内容。相关代码如下:
+ (NSSet *)certificatesInBundle:(NSBundle *)bundle {
NSArray *paths = [bundle pathsForResourcesOfType:@"cer" inDirectory:@"."];
NSMutableSet *certificates = [NSMutableSet setWithCapacity:[paths count]];
for (NSString *path in paths) {
NSData *certificateData = [NSData dataWithContentsOfFile:path];
[certificates addObject:certificateData];
}
return [NSSet setWithSet:certificates];
}
public key 获取
certificate中存放有public key、证书主体、数字签名等,所以public key就是从上面certificate文件中取出,主要用到的API是Security framework。
校验入口
当收到NSURLSessionTaskDelegate的
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * __nullable credential))completionHandler;
接口时就需要客户端校验服务器发送的证书了,具体校验规则就3种,校验内容也在开头说过了,具体校验代码都是基于Security framework,这儿就不粘贴代码了,详细请看接口:
- (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust
forDomain:(NSString *)domain