美文网首页iOS
AFN 3.x的学习

AFN 3.x的学习

作者: Hunter琼 | 来源:发表于2018-10-25 13:14 被阅读19次

    AFN 3.0框架示意图:


    图片来自网络.png

    AFN 3.x模块划分

    • 网络通信模块(AFURLSessionManger)
      AFURLSessionManger.h
      /**
      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
      
      
      AFURLSessionManger.m
       - (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扩展模块

    相关文章

      网友评论

        本文标题:AFN 3.x的学习

        本文链接:https://www.haomeiwen.com/subject/pqjmnftx.html