到了 AFNetworking 的最后一篇了。网络状态变更和安全策略是比较独立的两块东西。因此把他们放在最后看完。
网络状态
AFNetworkReachabilityManager
类提供了对于网络状态变化的监听。AF 预定义了四种网络状态:
1 | typedef NS_ENUM(NSInteger, AFNetworkReachabilityStatus) { |
设置监听
网络状态的监听是一个逻辑很清晰的过程。对于网络状态的改变,我们必须要通过系统的 API 进行。那么在 AFNetworkReachabilityStatusForFlags
中就提供了这样的一个方法实施监听:
1 | - (void)startMonitoring { |
可以看到,通过系统 API 创建了一个上下文 SCNetworkReachabilityContext
实例,一个监听回调的 AFNetworkReachabilityStatusBlock
实例,以及一个句柄 networkReachability
。既然是句柄,那么就可以通过它来结束监听:
1 | - (void)stopMonitoring { |
networkReachability
在初始化监听类对象的时候创建:
1 | + (instancetype)sharedManager { |
初始化方法比较长,主要分为了两种方式监听,一种是监听域名,一种是监听 socket。同时通过系统 API 创建 networkReachability
。
监听回调
设置好监听那么就设置监听回调以处理网络状态变化信息咯。我们来查看上文中注册的 AFNetworkReachabilityCallback
回调是怎样的:
1 | static void AFNetworkReachabilityCallback(SCNetworkReachabilityRef __unused target, SCNetworkReachabilityFlags flags, void *info) { |
当网络状态变更的时候,通过 AFNetworkReachabilityStatusForFlags()
方法进行基本状况的处理:
1 |
|
处理完成后的结果,可以通过两种方式拿到。一种是通过回调函数,这个回调函数就是上文中在 startMonitoring()
中创建 SCNetworkReachabilityContext
传入的 callback,可以自己将 block 设置给监听类的单例对象。还有一种就是通过通知,提前注册以下两种通知,可以获取到改变时间以及改变的情况:
1 |
|
以上就是网络监听相关的方法。
安全策略
AFSecurityPolicy
类提供了对于 HTTPS 通信过程中证书的校验,可以有效防止中间人攻击。它的校验模式分一下三种:
1 |
|
创建 AFSecurityPolicy
初始化
AFSecurityPolicy
并不是一个单例对象,每个 AFEscurityPolicy
实例都可以保存自己的验证模式,校验证书集合,以及一些配置属性。它的初始化方法如下:
1 | + (instancetype)policyWithPinningMode:(AFSSLPinningMode)pinningMode { |
设置校验证书
上面的代码中,通过 [self defaultPinnedCertificates]
拿到证书列表,并且再 set 给 AFSecurityPolicy
的过程如下:
1 |
|
获取证书的过程就是从 bundle 中加载 .cer
文件的过程。设置证书给实例的时候做了一个操作,会到证书中获取到公钥信息:
1 |
|
执行校验
1 | - (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust |
以上是校验的逻辑,其中涉及到好几个方法:
1 |
|
总的概括一下就是:
- 如果只验证证书的合法性的话,就直接通过苹果预置的根证书校验。
- 如果要校验证书是否是特定的证书,就要
- 把服务端返回的证书的签发证书放在 native 中
- 把 native 中的证书设置为服务端返回证书的锚点证书
- 取出服务端的证书的信任链上的所有证书并和 native 中的证书做比较。如果相等就说明可以用 native 中保存的证书对服务端的证书解密,即是要信任的证书。如果没有,就说明收到的证书不是服务端签发的,不可信
- 如果要校验证书中的公钥,则是在上一步的基础上,取出证书中的公钥信息,进行比较。
为什么AF3.0不需要常驻子线程了?
首先,请求最好不要在主线程中做,因为这样可能会影响主线程效率。并且子线程需要保活,使其能够在后续的 NSURLConnection 的 delegate 中接收回调。因此, AF2.0 需要创建一个常驻子线程,在子线程中执行网络请求即可。
AF3.0 使用 NSURLSession,不再需要在当前线程进行 delegate 回调