AFN 3.0框架示意图:
图片来自网络.png
AFN 3.x模块划分
- 网络通信模块(AFURLSessionManger)
AFURLSessionManger.h
AFURLSessionManger.m/** The managed session.管理session对象 */ @property (readonly, nonatomic, strong) NSURLSession *session; /** The operation queue on which delegate callbacks are run. 代理返回的NSOperationQueue(队列) */ @property (readonly, nonatomic, strong)NSOperationQueue *operationQueue; /* 解析网络返回的数据对象,遵循AFURLResponseSerialization协议*/ @property (nonatomic, strong) id <AFURLResponseSerialization> responseSerializer; /* 用于处理网络链接安全策略的AFSecurityPolicy对象 */ @property (nonatomic, strong) AFSecurityPolicy * securityPolicy; /* 用于检测网络数据的AFNetworkReachabilityManager的对象 */ @property (readwrite, nonatomic, strong) AFNetworkReachabilityManager *reachabilityManager /** 当前数据tasks会话 **/ @property (readonly, nonatomic, strong) NSArray <NSURLSessionDataTask *> *dataTasks /** 当前上传tasks会话 **/ @property (readonly, nonatomic, strong) NSArray <NSURLSessionDataTask *> *uploadTasks /** 当前下载tasks会话 **/ @property (readonly, nonatomic, strong) NSArray <NSURLSessionDataTask *> *downloadTasks /** 1 设置Session的Call Back(回调函数:就是那些会被主线程挂起来的代码。异步任务必须指定回调函数,当主线程开始执行异步任务,就是执行对应的回调函数)队列 2 completionQueue:设置completion block队列,默认是main block 3 completionGroup: 设置completion group队列组 4 nullable:对象可以为NULL或nil,和swift中optional类型中的!活?类似 **/ @property (nonatomic, strong, nullable) dispatch_queue_t completionQueue; @property (nonatomic, strong, nullable) dispatch_queue_t completionGroup /** 在创建后台任务上传时,有时候会返回nil,遵循苹果的建议,在创建失败的时候,会重新创建联系,次数默认为3次,如果有需要的话设置该属性为YES **/ @property (nonatomic, assign) BOOL attemptsToRecreateUploadTasksForBackgroundSessions; NS_DESIGNATED_INITIALIZER:警告开发者需要实现 这个初始化 /** 默认会话 defaultSessionConfiguration:工作模式类似与NSURLConnection,使用磁盘缓存策略,使用用户 keychain中保存证书认证和授权 瞬时会话模式ephemeralSessionConfirguration:改模式不会使用磁盘保存任何数据,所有的会话,证书,cookie都保持在RAM中,当程序会话消失后,这些缓存数据就会被清空 backgorundSessionConfigureation:后台会话模式,一般 用户后台上传和下载 **/ NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration]; //TODO set the default HTTP headers /** 客户端接受服务端发来的cookie */ configuration.HTTPShouldSetCookies = YES; /** 如果设置成YES,则允许不必等到response,就可以发送一个请求,这会大大提高网络请求效率,但是也有问题,因为客户端无法正确匹配请求和响应,所以这依赖于服务器必须保证和客户端响应请求顺序一致,如果保证不了这点,就会请求和响应混乱 */ configuration.HTTPShouldUsePipelining = NO; configuration.requestCachePolicy = NSURLRequestUseProtocolCachePolicy; /** allowsCellularAccess: 是否允许使用蜂窝链接 discretionary:是否当前程序在后台运行时由系统自己的最佳网络配置,可以节省蜂窝链接的宽带,会把wifi和电源可用性考虑在内,建议使用discretionary属性. */ configuration.allowsCellularAccess = YES; configuration.discretionary = YES configuration.timeoutIntervalForRequest = 60.0; configuration.URLCache = [AFImageDownloader defaultURLCache] - (instancetype)initWithSessionConfiguration:(nullable NSURLSessionConfiguration *)configuration NS_DESIGNATED_INITIALIZER /** NSURLSessionDataTask:是抽象类 NSURLSessionTask的子类,主要是用来获取数据,可以胜任上传和下载的任务 **/ - (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject, NSError * _Nullable error))completionHandle /** 根据ileURL创建reqeust 在ios7中,有时候创建NSURLSessionUploadTask task会失败,Apple建议,可重新尝试连接,尝试次数默认为3次 **/ - (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request fromFile:(NSURL *)fileURL progress:(void (^)(NSProgress *uploadProgress)) uploadProgressBlock completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler
- (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)configuration {
self = [super init];
if (!self) {
return nil;
}
if (!configuration) {
configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
}
self.sessionConfiguration = configuration;
self.operationQueue = [[NSOperationQueue alloc] init];
self.operationQueue.maxConcurrentOperationCount = 1;
self.session = [NSURLSession sessionWithConfiguration:self.sessionConfiguration delegate:self delegateQueue:self.operationQueue];
/** 各种响应转码 */
self.responseSerializer = [AFJSONResponseSerializer serializer];
/** 默认安全策略**/
self.securityPolicy = [AFSecurityPolicy defaultPolicy];
#if !TARGET_OS_WATCH
self.reachabilityManager = [AFNetworkReachabilityManager sharedManager];
#endif
self.mutableTaskDelegatesKeyedByTaskIdentifier = [[NSMutableDictionary alloc] init];
/** NSLock用于协调多个多线程操作锁 ,是一种同步机制,防止在多任务的情况下对共享资源的脏读和脏写 ,执行多线程时用于强行限制资源访问的同步机制 */
self.lock = [[NSLock alloc] init];
self.lock.name = AFURLSessionManagerLockName;
/** 异步获取当前session所有未完成的task */
[self.session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) {
for (NSURLSessionDataTask *task in dataTasks) {
[self addDelegateForDataTask:task uploadProgress:nil downloadProgress:nil completionHandler:nil];
}
for (NSURLSessionUploadTask *uploadTask in uploadTasks) {
[self addDelegateForUploadTask:uploadTask progress:nil completionHandler:nil];
}
for (NSURLSessionDownloadTask *downloadTask in downloadTasks) {
[self addDelegateForDownloadTask:downloadTask progress:nil destination:nil completionHandler:nil];
}
}];
return self;
}
/**
只要地址为https,则执行这个协议方法,告诉系统,是否信任证书
NSURLAuthenticationChallenge:认证认证
NSURLSessionAuthChallengeDisposition:
1 NSURLSessionAuthChallengeUserCrednetial 使用证书
2 NSURLSessionAuthChallengeDefaultHanding 忽略证书
3 NSURLSessionAuthChallengeCancelAuthenticationChallenge 忽略证书,并拒绝请求这次请求
4 NSURLSessionAuthChallengeRejectProtectionSpace 拒绝当前请求,下一次在询问
*/
- (void)URLSession:(NSURLSession *)session
didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler
{
NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling;
__block NSURLCredential *credential = nil;
if (self.sessionDidReceiveAuthenticationChallenge) {
disposition = self.sessionDidReceiveAuthenticationChallenge(session, challenge, &credential);
} else {
/** 判断证书是否信任 */
if
([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
if ([self.securityPolicy evaluateServerTrust:challenge.protectionSpace.serverTrust forDomain:challenge.protectionSpace.host]) {
credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
if (credential) {
disposition = NSURLSessionAuthChallengeUseCredential;
} else {
disposition = NSURLSessionAuthChallengePerformDefaultHandling;
}
} else {
disposition = NSURLSessionAuthChallengeRejectProtectionSpace;
}
} else {
disposition = NSURLSessionAuthChallengePerformDefaultHandling;
}
}
/** 告诉系统,认证情况*/
if (completionHandler) {
completionHandler(disposition, credential);
}
}
-(NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request
uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgressBlock
downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgressBlock
completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject, NSError * _Nullable error))completionHandler {
__block NSURLSessionDataTask *dataTask = nil;
/**
创建task
url_session_manager_create_task_safely:这个函数主要是解决iOS8之前的bug,在这个函数中用到了NSFoundationVersionNumber:比较Foundation框架版本号,iOS升级时Foundation也会提高
*/
url_session_manager_create_task_safely(^{
dataTask = [self.session dataTaskWithRequest:request];
});
/** NSURLSessionDataTask添加一个delegate:AFURLSessionManagerTaskDelegate */
[self addDelegateForDataTask:dataTask uploadProgress:uploadProgressBlock downloadProgress:downloadProgressBlock completionHandler:completionHandler];
return dataTask;
}
/**
设置代理
**/
- (AFURLSessionManagerTaskDelegate *)delegateForTask:(NSURLSessionTask *)task {
NSParameterAssert(task);
AFURLSessionManagerTaskDelegate *delegate = nil;
/** 防止线程被脏写 */
[self.lock lock];
delegate = self.mutableTaskDelegatesKeyedByTaskIdentifier[@(task.taskIdentifier)];
[self.lock unlock];
return delegate;
}
AFHTTPSessionManger.h
/**
GET 请求
*/
- (nullable NSURLSessionDataTask *)GET:(NSString *)URLString
parameters:(nullable id)parameters
progress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgress
success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure
/**
HEAD请求
用来获取报文首部,和GET差不多,只是响应不会返回主体内容
**/
- (nullable NSURLSessionDataTask *)HEAD:(NSString *)URLString
parameters:(nullable id)parameters
success:(nullable void (^)(NSURLSessionDataTask *task))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure
AFHTTPSessionManger.m
- (NSURLSessionDataTask *)GET:(NSString *)URLString
parameters:(id)parameters
progress:(void (^)(NSProgress * _Nonnull))downloadProgress
success:(void (^)(NSURLSessionDataTask * _Nonnull, id _Nullable))success
failure:(void (^)(NSURLSessionDataTask * _Nullable, NSError * _Nonnull))failure
{
/**
生成一个task
网络安全策略验证解析失败,直接返回task=nil ,网络请求失败
*/
NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"GET"
URLString:URLString
parameters:parameters
uploadProgress:nil
downloadProgress:downloadProgress
success:success
failure:failure];
[dataTask resume];
return dataTask;
}
- 网路通讯安全策略模块(AFSecuityPolicy)
AFSecuityPolicy.h
typedef NS_ENUM(NSUInteger, AFSSLPinningMode) {
/** 无条件信任证书 */
AFSSLPinningModeNone,
/** 对服务端返回的PublicKey(公钥)进行验证 */
AFSSLPinningModePublicKey,
/** 对服务端返回的证书和本地证书进行校验 */
AFSSLPinningModeCertificate,
};
/**
返回SSL Pinning类型 默认`AFSSLPinningModeNone`.
*/
@property (readonly, nonatomic, assign) AFSSLPinningMode SSLPinningMode;
/**
保存所有可用做校验证书集合,AFN默认搜索工程中所以.cer证书,如果定制某些证书,可使用certificatesInBundle在目录下加载证书,然后调用policyWithPinnngMode:withPinnedCertificates创建一个类对象
*/
@property (nonatomic, strong, nullable) NSSet <NSData *> *pinnedCertificates;
/**
是否使用过期或无效证书,默认为 `NO`.
*/
@property (nonatomic, assign) BOOL allowInvalidCertificates;
/**
是否校验证书中的域名domain
*/
@property (nonatomic, assign) BOOL validatesDomainName;
/**
返回指定的的bundle证书,必须实现这个方法,并使用policyWithPinningMode:withPinnedCertificates方法创建实例对象
*/
+ (NSSet <NSData *> *)certificatesInBundle:(NSBundle *)bundle;
/**
默认的实例对象
1 不允许无效或者过期的证书
2 验证域名
3 不对证书和公钥进行校验
*/
+ (instancetype)defaultPolicy;
/**
创建SSL认证实例
@param pinningMode SSL Pinning类型
*/
+ (instancetype)policyWithPinningMode:(AFSSLPinningMode)pinningMode;
/**
创建SSL认证实例
@param pinningMode SSL Pinning类型.
@param pinnedCertificates :可用做校验证书集合
*/
+ (instancetype)policyWithPinningMode:(AFSSLPinningMode)pinningMode withPinnedCertificates:(NSSet <NSData *> *)pinnedCertificates;
/**
核心证书校验方法
**/
- (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust
forDomain:(nullable NSString *)domain
AFSecuityPolicy.m
/**
获取二进制公钥:NSdata ----> CFDataRef ----> SecCertificateCreateWithData----->SecTrustCopyPublicKey(SecTrustRef)
*/
static id AFPublicKeyForCertificate(NSData *certificate) {
id allowedPublicKey = nil;
SecCertificateRef allowedCertificate;
SecCertificateRef allowedCertificates[1];
CFArrayRef tempCertificates = nil;
SecPolicyRef policy = nil;
SecTrustRef allowedTrust = nil;
SecTrustResultType result;
/** 根据二进制certificate生成 SecCertificateRef类型证书*/
allowedCertificate = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certificate);
/**
如果allowedCertificate为空,则执行标记_out后面的代码
__Require_Quiet:这个宏定义usr/include/AssertMacros,当返回为false,执行标记后面的代码
**/
__Require_Quiet(allowedCertificate != NULL, _out);
/**
给allowedCertificates赋值
*/
allowedCertificates[0] = allowedCertificate;
/**
新建CFArrayCreate tempCertificates
*/
tempCertificates = CFArrayCreate(NULL, (const void **)allowedCertificates, 1, NULL);
/**
新建policy为X5.09
*/
policy = SecPolicyCreateBasicX509();
/**
创建SecTrustRef对象,如果错误则跳到_out标记处
__Require_noErr_Quiet:若抛出异常则执行标记后面代码
**/
__Require_noErr_Quiet(SecTrustCreateWithCertificates(tempCertificates, policy, &allowedTrust), _out);
/**
证书校验,如失败则跳到_out处
**/
__Require_noErr_Quiet(SecTrustEvaluate(allowedTrust, &result), _out);
/** 在SecTrustRef获取公钥 */
allowedPublicKey = (__bridge_transfer id)SecTrustCopyPublicKey(allowedTrust);
_out:
if (allowedTrust) {
CFRelease(allowedTrust);
}
if (policy) {
CFRelease(policy);
}
if (tempCertificates) {
CFRelease(tempCertificates);
}
if (allowedCertificate) {
CFRelease(allowedCertificate);
}
return allowedPublicKey;
}
/**
返回服务端是否可信任
**/
static BOOL AFServerTrustIsValid(SecTrustRef serverTrust) {
BOOL isValid = NO;
SecTrustResultType result;
__Require_noErr_Quiet(SecTrustEvaluate(serverTrust, &result), _out);
/**
kSecTrustResultUnspecified :不是自己设的证书就通过
kSecTrustResultProceed:用户自己生成证书通过,比如信任弹框
*/
isValid = (result == kSecTrustResultUnspecified || result == kSecTrustResultProceed);
_out:
return isValid;
}
-
网络监听模块(AFNnetworkReachablityManger)
typedef NS_ENUM(NSInteger, AFNetworkReachabilityStatus) { AFNetworkReachabilityStatusUnknown = -1,//未知网路 AFNetworkReachabilityStatusNotReachable = 0,//网络不可达到 AFNetworkReachabilityStatusReachableViaWWAN = 1,//蜂窝网络 AFNetworkReachabilityStatusReachableViaWiFi = 2, };
AFNnetworkReachablityManger提供了许多监听的实例方法,最常用的是
sharedManger
,还可以用调用mangerForAddress
或者mangerForDomain
方法来监控套接地址和域名地址.
/**
监听结果回调,调用starMonitoring变开始监听,调用stopMonitoring关闭监听
*/
- (void)setReachabilityStatusChangeBlock:(nullable void (^)(AFNetworkReachabilityStatus status))block
-
网络通讯信息序列化/反序列化模块(AFURLResponseSerialization)
-
UIKit扩展模块
网友评论