iOS

AFN 3.x的学习

2018-10-25  本文已影响19人  Hunter琼

AFN 3.0框架示意图:


图片来自网络.png

AFN 3.x模块划分

   - (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;
}
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;
}
/**
  监听结果回调,调用starMonitoring变开始监听,调用stopMonitoring关闭监听
*/
- (void)setReachabilityStatusChangeBlock:(nullable void (^)(AFNetworkReachabilityStatus status))block
上一篇下一篇

猜你喜欢

热点阅读