Repository: QianKun-HanLin/HLNetworking Branch: master Commit: 62d3a7ff6f0e Files: 78 Total size: 317.4 KB Directory structure: gitextract_diowpqpv/ ├── .gitignore ├── HLNetworking/ │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Assets.xcassets/ │ │ └── AppIcon.appiconset/ │ │ └── Contents.json │ ├── Base.lproj/ │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ ├── HLAPICenter+home.h │ ├── HLAPICenter+home.m │ ├── Info.plist │ ├── Source/ │ │ ├── Center/ │ │ │ ├── HLAPICenter.h │ │ │ ├── HLAPICenter.m │ │ │ ├── HLAPIMacro.h │ │ │ ├── HLBaseObjReformer.h │ │ │ └── HLBaseObjReformer.m │ │ ├── Config/ │ │ │ ├── HLFormDataConfig.h │ │ │ ├── HLFormDataConfig.m │ │ │ ├── HLNetworkConfig.h │ │ │ ├── HLNetworkConfig.m │ │ │ ├── HLNetworkConst.h │ │ │ ├── HLNetworkMacro.h │ │ │ ├── HLNetworkPolicyConfig.h │ │ │ ├── HLNetworkPolicyConfig.m │ │ │ ├── HLNetworkRequestConfig.h │ │ │ ├── HLNetworkRequestConfig.m │ │ │ ├── HLNetworkTipsConfig.h │ │ │ ├── HLNetworkTipsConfig.m │ │ │ ├── HLSecurityPolicyConfig.h │ │ │ └── HLSecurityPolicyConfig.m │ │ ├── Engine/ │ │ │ ├── HLNetworkEngine.h │ │ │ └── HLNetworkEngine.m │ │ ├── Generator/ │ │ │ ├── Request/ │ │ │ │ ├── API/ │ │ │ │ │ ├── HLAPIRequest.h │ │ │ │ │ ├── HLAPIRequest.m │ │ │ │ │ └── HLAPIRequest_InternalParams.h │ │ │ │ ├── Base/ │ │ │ │ │ ├── HLURLRequest.h │ │ │ │ │ ├── HLURLRequest.m │ │ │ │ │ └── HLURLRequest_InternalParams.h │ │ │ │ ├── Group/ │ │ │ │ │ ├── HLRequestGroup.h │ │ │ │ │ └── HLRequestGroup.m │ │ │ │ └── Task/ │ │ │ │ ├── HLTaskRequest.h │ │ │ │ ├── HLTaskRequest.m │ │ │ │ └── HLTaskRequest_InternalParams.h │ │ │ ├── Response/ │ │ │ │ ├── HLURLResponse.h │ │ │ │ └── HLURLResponse.m │ │ │ └── Result/ │ │ │ ├── HLURLResult.h │ │ │ └── HLURLResult.m │ │ ├── HLNetworking.h │ │ ├── Logger/ │ │ │ ├── HLDebugMessage.h │ │ │ ├── HLDebugMessage.m │ │ │ ├── HLNetworkLogger.h │ │ │ ├── HLNetworkLogger.m │ │ │ ├── HLNetworkLoggerConfig.h │ │ │ ├── HLNetworkLoggerConfig.m │ │ │ ├── NSNull+ToDictionary.h │ │ │ ├── NSNull+ToDictionary.m │ │ │ ├── UIDevice+deviceInfo.h │ │ │ ├── UIDevice+deviceInfo.m │ │ │ └── iPhoneTypeDefine.plist │ │ └── Manager/ │ │ ├── HLNetworkManager.h │ │ └── HLNetworkManager.m │ ├── ViewController.h │ ├── ViewController.m │ └── main.m ├── HLNetworking.podspec ├── HLNetworking.xcodeproj/ │ ├── project.pbxproj │ ├── project.xcworkspace/ │ │ └── contents.xcworkspacedata │ └── xcshareddata/ │ └── xcschemes/ │ └── HLNetworking.xcscheme ├── HLNetworkingTests/ │ ├── HLAPIRequestTest.m │ ├── HLManagerTests.m │ ├── HLRequestGroupTests.m │ ├── HLTaskRequestTest.m │ ├── HLTestCase.h │ ├── HLTestCase.m │ ├── Info.plist │ └── httpbin.org.cer ├── LICENSE ├── Podfile ├── README.md └── README_old.md ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ HLNetworking.xcodeproj/xcuserdata/ HLNetworking.xcworkspace/ Pods/ *.swp Podfile.lock .DS_Store HLNetworking.xcodeproj/project.xcworkspace/xcuserdata/ ================================================ FILE: HLNetworking/AppDelegate.h ================================================ // // AppDelegate.h // HLNetworking // // Created by wangshiyu13 on 2016/9/22. // Copyright © 2016年 wangshiyu13. All rights reserved. // #import @interface AppDelegate : UIResponder @property (strong, nonatomic) UIWindow *window; @end ================================================ FILE: HLNetworking/AppDelegate.m ================================================ // // AppDelegate.m // HLNetworking // // Created by wangshiyu13 on 2016/9/22. // Copyright © 2016年 wangshiyu13. All rights reserved. // #import "AppDelegate.h" @interface AppDelegate () @end @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // Override point for customization after application launch. return YES; } - (void)applicationWillResignActive:(UIApplication *)application { // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. } - (void)applicationDidEnterBackground:(UIApplication *)application { // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. } - (void)applicationWillEnterForeground:(UIApplication *)application { // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. } - (void)applicationDidBecomeActive:(UIApplication *)application { // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. } - (void)applicationWillTerminate:(UIApplication *)application { // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. } @end ================================================ FILE: HLNetworking/Assets.xcassets/AppIcon.appiconset/Contents.json ================================================ { "images" : [ { "idiom" : "iphone", "size" : "29x29", "scale" : "2x" }, { "idiom" : "iphone", "size" : "29x29", "scale" : "3x" }, { "idiom" : "iphone", "size" : "40x40", "scale" : "2x" }, { "idiom" : "iphone", "size" : "40x40", "scale" : "3x" }, { "idiom" : "iphone", "size" : "60x60", "scale" : "2x" }, { "idiom" : "iphone", "size" : "60x60", "scale" : "3x" }, { "idiom" : "ipad", "size" : "29x29", "scale" : "1x" }, { "idiom" : "ipad", "size" : "29x29", "scale" : "2x" }, { "idiom" : "ipad", "size" : "40x40", "scale" : "1x" }, { "idiom" : "ipad", "size" : "40x40", "scale" : "2x" }, { "idiom" : "ipad", "size" : "76x76", "scale" : "1x" }, { "idiom" : "ipad", "size" : "76x76", "scale" : "2x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: HLNetworking/Base.lproj/LaunchScreen.storyboard ================================================ ================================================ FILE: HLNetworking/Base.lproj/Main.storyboard ================================================ ================================================ FILE: HLNetworking/HLAPICenter+home.h ================================================ // // HLAPICenter+home.h // HLNetworking // // Created by wangshiyu13 on 2017/1/2. // Copyright © 2017年 wangshiyu13. All rights reserved. // #import "HLAPICenter.h" @interface HLAPICenter (home) HLStrongProperty(home) @end ================================================ FILE: HLNetworking/HLAPICenter+home.m ================================================ // // HLAPICenter+home.m // HLNetworking // // Created by wangshiyu13 on 2017/1/2. // Copyright © 2017年 wangshiyu13. All rights reserved. // #import "HLAPICenter+home.h" @implementation HLAPICenter (home) HLStrongSynthesize(home, [HLAPIRequest request] .setMethod(GET) .setCustomURL(@"get") .setObjReformerDelegate(self.defaultReformer)) @end ================================================ FILE: HLNetworking/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleDisplayName HLNetworking CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType APPL CFBundleShortVersionString 1.3.0 CFBundleURLTypes CFBundleTypeRole Editor CFBundleURLSchemes abc CFBundleVersion 31 LSRequiresIPhoneOS UIBackgroundModes fetch UILaunchStoryboardName LaunchScreen UIMainStoryboardFile Main UIRequiredDeviceCapabilities armv7 UISupportedInterfaceOrientations UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UISupportedInterfaceOrientations~ipad UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight ================================================ FILE: HLNetworking/Source/Center/HLAPICenter.h ================================================ // // HLAPICenter.h // HLNetworking+Lovek12 // // Created by wangshiyu13 on 2016/12/9. // Copyright © 2016年 mykj. All rights reserved. // #import #import "HLBaseObjReformer.h" #import "HLAPIMacro.h" @interface HLAPICenter : NSObject + (instancetype)defaultCenter; @property (nonatomic, strong) HLBaseObjReformer *defaultReformer; @end ================================================ FILE: HLNetworking/Source/Center/HLAPICenter.m ================================================ // // HLAPICenter.m // HLNetworking+Lovek12 // // Created by wangshiyu13 on 2016/12/9. // Copyright © 2016年 mykj. All rights reserved. // #import "HLAPICenter.h" static HLAPICenter *shared = nil; @implementation HLAPICenter - (HLBaseObjReformer *)defaultReformer { if (!_defaultReformer) { _defaultReformer = [[HLBaseObjReformer alloc] init]; } return _defaultReformer; } + (instancetype)defaultCenter { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ if(shared == nil) { shared = [[self alloc] init]; } }); return shared; } + (instancetype)allocWithZone:(struct _NSZone *)zone { static dispatch_once_t token; dispatch_once(&token, ^{ if(shared == nil) { shared = [super allocWithZone:zone]; } }); return shared; } - (id)copy { return self; } - (id)mutableCopy { return self; } @end ================================================ FILE: HLNetworking/Source/Center/HLAPIMacro.h ================================================ // // HLAPIMacro.h // HLNetworking+Lovek12 // // Created by wangshiyu13 on 2016/12/10. // Copyright © 2016年 mykj. All rights reserved. // #ifndef HLAPIMacro_h #define HLAPIMacro_h #import #define metamacro_concat(A, B) \ metamacro_concat_(A, B) #define metamacro_concat_(A, B) A ## B #define HLStrongProperty(name) \ @property (nonatomic, strong, setter=set__nonuse__##name:, getter=__nonuse__##name) HLAPIRequest *name; \ + (HLAPIRequest *)name; #define HLStrongSynthesize(name, api) \ static void *name##AssociatedKey = #name "associated"; \ - (void)set__nonuse__##name:(HLAPIRequest *)name { \ objc_setAssociatedObject(self, name##AssociatedKey, name, OBJC_ASSOCIATION_RETAIN_NONATOMIC); \ } \ \ - (HLAPIRequest *)__nonuse__##name { \ id _##name = objc_getAssociatedObject(self, name##AssociatedKey); \ if (!_##name) { \ _##name = api; \ } \ return _##name; \ } \ + (HLAPIRequest *)name { \ return [[self defaultCenter] __nonuse__##name];\ } #endif /* HLAPIMacro_h */ ================================================ FILE: HLNetworking/Source/Center/HLBaseObjReformer.h ================================================ // // HLBaseObjReformer.h // HLNetworking+Lovek12 // // Created by wangshiyu13 on 2016/12/9. // Copyright © 2016年 mykj. All rights reserved. // #import #import "HLAPIRequest.h" @interface HLBaseObjReformer : NSObject @end ================================================ FILE: HLNetworking/Source/Center/HLBaseObjReformer.m ================================================ // // HLBaseObjReformer.m // HLNetworking+Lovek12 // // Created by wangshiyu13 on 2016/12/9. // Copyright © 2016年 mykj. All rights reserved. // #import "HLBaseObjReformer.h" #import @implementation HLBaseObjReformer - (id)reformerObject:(id)responseObject andError:(NSError *)error atRequest:(HLAPIRequest *)api { if (api.objClz && ![NSStringFromClass(api.objClz) isEqualToString:@"NSObject"]) { if (responseObject) { return [api.objClz yy_modelWithJSON:responseObject]; } } #if DEBUG NSLog(@"该对象无法转换,api = %@", api); #endif return nil; } @end ================================================ FILE: HLNetworking/Source/Config/HLFormDataConfig.h ================================================ // // HLFormDataConfig.h // HLNetworking // // Created by wangshiyu13 on 2016/9/23. // Copyright © 2016年 wangshiyu13. All rights reserved. // #import NS_ASSUME_NONNULL_BEGIN #pragma mark - 用于拼接formData的协议 @protocol HLMultipartFormDataProtocol - (BOOL)appendPartWithFileURL:(NSURL *)fileURL name:(NSString *)name error:(NSError * __nullable __autoreleasing *)error; - (BOOL)appendPartWithFileURL:(NSURL *)fileURL name:(NSString *)name fileName:(NSString *)fileName mimeType:(NSString *)mimeType error:(NSError * __nullable __autoreleasing *)error; - (void)appendPartWithInputStream:(nullable NSInputStream *)inputStream name:(NSString *)name fileName:(NSString *)fileName length:(int64_t)length mimeType:(NSString *)mimeType; - (void)appendPartWithFileData:(NSData *)data name:(NSString *)name fileName:(NSString *)fileName mimeType:(NSString *)mimeType; - (void)appendPartWithFormData:(NSData *)data name:(NSString *)name; - (void)appendPartWithHeaders:(nullable NSDictionary *)headers body:(NSData *)body; - (void)throttleBandwidthWithPacketSize:(NSUInteger)numberOfBytes delay:(NSTimeInterval)delay; @end @interface HLFormDataConfig : NSObject // 用于二进制数据的formData拼接 + (void (^)(id))configWithData:(NSData *)data name:(NSString *)name fileName:(NSString *)fileName mimeType:(NSString *)mimeType; // 用于图片数据的formData拼接 + (void (^)(id))configWithImage:(UIImage *)image name:(NSString *)name fileName:(NSString *)fileName quality:(CGFloat)quality; // 用于url所在数据的formData拼接 + (void (^)(id))configWithFileURL:(NSURL *)fileURL name:(NSString *)name fileName:(NSString *)fileName mimeType:(NSString *)mimeType error:(NSError * __nullable __autoreleasing *)error; // 用于NSInputStream获取数据的formData拼接 + (void (^)(id))configWithInputStream:(nullable NSInputStream *)inputStream name:(NSString *)name fileName:(NSString *)fileName length:(int64_t)length mimeType:(NSString *)mimeType; @end NS_ASSUME_NONNULL_END ================================================ FILE: HLNetworking/Source/Config/HLFormDataConfig.m ================================================ // // HLFormDataConfig.m // HLNetworking // // Created by wangshiyu13 on 2016/9/23. // Copyright © 2016年 wangshiyu13. All rights reserved. // #import "HLFormDataConfig.h" @implementation HLFormDataConfig + (void (^)(id))configWithData:(NSData *)data name:(NSString *)name fileName:(NSString *)fileName mimeType:(NSString *)mimeType { return ^(id formData) { [formData appendPartWithFileData:data name:name fileName:fileName mimeType:mimeType]; }; } + (void (^)(id))configWithImage:(UIImage *)image name:(NSString *)name fileName:(NSString *)fileName quality:(CGFloat)quality { return ^(id formData) { NSData *data; NSString *mimeType; if (UIImagePNGRepresentation(image) == nil) { data = UIImageJPEGRepresentation(image, quality); mimeType = @"image/jpeg"; }else { data = UIImagePNGRepresentation(image); mimeType = @"image/png"; } [formData appendPartWithFileData:data name:name fileName:fileName mimeType:mimeType]; }; } + (void (^)(id))configWithFileURL:(NSURL *)fileURL name:(NSString *)name fileName:(NSString *)fileName mimeType:(NSString *)mimeType error:(NSError * __nullable __autoreleasing *)error { return ^(id formData) { [formData appendPartWithFileURL:fileURL name:name fileName:fileName mimeType:mimeType error:error]; }; } + (void (^)(id))configWithInputStream:(nullable NSInputStream *)inputStream name:(NSString *)name fileName:(NSString *)fileName length:(int64_t)length mimeType:(NSString *)mimeType { return ^(id formData) { [formData appendPartWithInputStream:inputStream name:name fileName:fileName length:length mimeType:mimeType]; }; } @end ================================================ FILE: HLNetworking/Source/Config/HLNetworkConfig.h ================================================ // // HLNetworkConfig.h // HLPPShop // // Created by wangshiyu13 on 2016/9/19. // Copyright © 2016年 wangshiyu13. All rights reserved. // #import #import "HLSecurityPolicyConfig.h" #import "HLNetworkTipsConfig.h" #import "HLNetworkRequestConfig.h" #import "HLNetworkPolicyConfig.h" NS_ASSUME_NONNULL_BEGIN DISPATCH_EXPORT void dispatch_async_main(dispatch_queue_t queue, dispatch_block_t block); @interface HLNetworkConfig : NSObject // 提示相关参数 @property (nonatomic, strong) HLNetworkTipsConfig *tips; // 请求相关参数 @property (nonatomic, strong) HLNetworkRequestConfig *request; // 网络策略相关参数 @property (nonatomic, strong) HLNetworkPolicyConfig *policy; // 安全策略相关参数 @property (nonatomic, strong) HLSecurityPolicyConfig *defaultSecurityPolicy; // 是否启用reachability,baseURL为domain @property (nonatomic, assign) BOOL enableReachability; // 是否开启网络debug日志,该选项会在控制台输出所有网络回调日志,并且在Release模式下无效 @property (nonatomic, assign) BOOL enableGlobalLog; // 快速构建config + (HLNetworkConfig *)config; // 请使用config - (instancetype)init NS_UNAVAILABLE; + (instancetype)new NS_UNAVAILABLE; @end NS_ASSUME_NONNULL_END ================================================ FILE: HLNetworking/Source/Config/HLNetworkConfig.m ================================================ // // HLNetworkConfig.m // HLPPShop // // Created by wangshiyu13 on 2016/9/19. // Copyright © 2016年 wangshiyu13. All rights reserved. // #import "HLNetworkConfig.h" inline void dispatch_async_main(dispatch_queue_t queue, dispatch_block_t block) { if (queue) { dispatch_async(queue, block); } else { if (![NSThread isMainThread]) { dispatch_async(dispatch_get_main_queue(), block); } else { block(); } } } @implementation HLNetworkConfig - (instancetype)init { self = [super init]; if (self) { _tips = [HLNetworkTipsConfig config]; _request = [HLNetworkRequestConfig config]; _policy = [HLNetworkPolicyConfig config]; _enableReachability = NO; _enableGlobalLog = NO; _defaultSecurityPolicy = [HLSecurityPolicyConfig policyWithPinningMode:HLSSLPinningModeNone]; } return self; } + (HLNetworkConfig *)config { return [[self alloc] init]; } - (id)copyWithZone:(NSZone *)zone { HLNetworkConfig *config = [[[self class] alloc] init]; if (config) { config.tips = [_tips copyWithZone:zone]; config.request = [_request copyWithZone:zone]; config.policy = [_policy copyWithZone:zone]; config.defaultSecurityPolicy = [_defaultSecurityPolicy copyWithZone:zone]; config.enableReachability = _enableReachability; config.defaultSecurityPolicy = _defaultSecurityPolicy; } return config; } @end ================================================ FILE: HLNetworking/Source/Config/HLNetworkConst.h ================================================ // // HLNetworkConst.h // HLNetworking // // Created by wangshiyu13 on 2017/1/22. // Copyright © 2017年 wangshiyu13. All rights reserved. // #ifndef HLNetworkConst_h #define HLNetworkConst_h @protocol HLMultipartFormDataProtocol; @class HLDebugMessage; // 网络请求类型 typedef NS_ENUM(NSUInteger, HLRequestTaskType) { Upload = 16, Download = 17 }; // 网络请求类型 typedef NS_ENUM(NSUInteger, HLRequestMethodType) { GET = 10, POST = 11, HEAD = 12, PUT = 13, PATCH = 14, DELETE = 15 }; // 请求的序列化格式 typedef NS_ENUM(NSUInteger, HLRequestSerializerType) { // Content-Type = application/x-www-form-urlencoded RequestHTTP = 100, // Content-Type = application/json RequestJSON = 101, // Content-Type = application/x-plist RequestPlist = 102 }; // 请求返回的序列化格式 typedef NS_ENUM(NSUInteger, HLResponseSerializerType) { // 默认的Response序列化方式(不处理) ResponseHTTP = 200, // 使用NSJSONSerialization解析Response Data ResponseJSON = 201, // 使用NSPropertyListSerialization解析Response Data ResponsePlist = 202, // 使用NSXMLParser解析Response Data ResponseXML = 203 }; // reachability的状态 typedef NS_ENUM(NSUInteger, HLReachabilityStatus) { HLReachabilityStatusUnknown, HLReachabilityStatusNotReachable, HLReachabilityStatusReachableViaWWAN, HLReachabilityStatusReachableViaWiFi }; // 定义的Block // 请求结果回调 typedef void(^HLSuccessBlock)(id __nullable responseObj); // 请求失败回调 typedef void(^HLFailureBlock)(NSError * __nullable error); // 请求进度回调 typedef void(^HLProgressBlock)(NSProgress * __nullable progress); // formData拼接回调 typedef void(^HLRequestConstructingBodyBlock)(id __nullable formData); // debug回调 typedef void(^HLDebugBlock)(HLDebugMessage * __nonnull debugMessage); // reachability回调 typedef void(^HLReachabilityBlock)(HLReachabilityStatus status); // 桥接回调 typedef void(^HLCallbackBlock)(id __nonnull request, id __nullable responseObject, NSError * __nullable error); #endif /* HLNetworkConst_h */ ================================================ FILE: HLNetworking/Source/Config/HLNetworkMacro.h ================================================ // // HLNetworkMacro.h // HLNetworking // // Created by wangshiyu13 on 24/11/2016. // Copyright © 2016 wangshiyu13. All rights reserved. // #ifndef HLNetworkMacro_h #define HLNetworkMacro_h static inline BOOL IsEmptyValue(id thing) { return thing == nil || ([thing respondsToSelector:@selector(length)] && [(NSData *)thing length] == 0) || ([thing respondsToSelector:@selector(count)] && [(NSArray *)thing count] == 0) || ([thing isKindOfClass:[NSNull class]]); } #if DEBUG #define HLNetLog(...) NSLog(__VA_ARGS__) #else #define HLNetLog(...) {} #endif #define HL_SAFE_BLOCK(BlockName, ...) ({ !BlockName ? nil : BlockName(__VA_ARGS__); }) #define HLLock() dispatch_semaphore_wait(self->_lock, DISPATCH_TIME_FOREVER) #define HLUnlock() dispatch_semaphore_signal(self->_lock) #pragma mark - weakify strongify #if DEBUG #define hl_keywordify autoreleasepool {} #else #define hl_keywordify try {} @catch (...) {} #endif #define hl_weakify_(INDEX, CONTEXT, VAR) \ CONTEXT __typeof__(VAR) hl_metamacro_concat(VAR, _weak_) = (VAR); #define hl_strongify_(INDEX, VAR) \ __strong __typeof__(VAR) VAR = hl_metamacro_concat(VAR, _weak_); #define hl_weakify(...) \ hl_keywordify \ hl_metamacro_foreach_cxt(hl_weakify_,, __weak, __VA_ARGS__) #define hl_strongify(...) \ hl_keywordify \ _Pragma("clang diagnostic push") \ _Pragma("clang diagnostic ignored \"-Wshadow\"") \ hl_metamacro_foreach(hl_strongify_,, __VA_ARGS__) \ _Pragma("clang diagnostic pop") /** * Executes one or more expressions (which may have a void type, such as a call * to a function that returns no value) and always returns true. */ #define hl_metamacro_exprify(...) \ ((__VA_ARGS__), true) /** * Returns a string representation of VALUE after full macro expansion. */ #define hl_metamacro_stringify(VALUE) \ hl_metamacro_stringify_(VALUE) /** * Returns A and B concatenated after full macro expansion. */ #define hl_metamacro_concat(A, B) \ hl_metamacro_concat_(A, B) /** * Returns the Nth variadic argument (starting from zero). At least * N + 1 variadic arguments must be given. N must be between zero and twenty, * inclusive. */ #define hl_metamacro_at(N, ...) \ hl_metamacro_concat(hl_metamacro_at, N)(__VA_ARGS__) /** * Returns the number of arguments (up to twenty) provided to the macro. At * least one argument must be provided. * * Inspired by P99: http://p99.gforge.inria.fr */ #define hl_metamacro_argcount(...) \ hl_metamacro_at(20, __VA_ARGS__, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1) /** * Identical to #hl_metamacro_foreach_cxt, except that no CONTEXT argument is * given. Only the index and current argument will thus be passed to MACRO. */ #define hl_metamacro_foreach(MACRO, SEP, ...) \ hl_metamacro_foreach_cxt(hl_metamacro_foreach_iter, SEP, MACRO, __VA_ARGS__) /** * For each consecutive variadic argument (up to twenty), MACRO is passed the * zero-based index of the current argument, CONTEXT, and then the argument * itself. The results of adjoining invocations of MACRO are then separated by * SEP. * * Inspired by P99: http://p99.gforge.inria.fr */ #define hl_metamacro_foreach_cxt(MACRO, SEP, CONTEXT, ...) \ hl_metamacro_concat(hl_metamacro_foreach_cxt, hl_metamacro_argcount(__VA_ARGS__))(MACRO, SEP, CONTEXT, __VA_ARGS__) /** * Identical to #hl_metamacro_foreach_cxt. This can be used when the former would * fail due to recursive macro expansion. */ #define hl_metamacro_foreach_cxt_recursive(MACRO, SEP, CONTEXT, ...) \ hl_metamacro_concat(hl_metamacro_foreach_cxt_recursive, hl_metamacro_argcount(__VA_ARGS__))(MACRO, SEP, CONTEXT, __VA_ARGS__) /** * In consecutive order, appends each variadic argument (up to twenty) onto * BASE. The resulting concatenations are then separated by SEP. * * This is primarily useful to manipulate a list of macro invocations into instead * invoking a different, possibly related macro. */ #define hl_hl_metamacro_foreach_concat(BASE, SEP, ...) \ hl_metamacro_foreach_cxt(hl_metamacro_foreach_concat_iter, SEP, BASE, __VA_ARGS__) /** * Iterates COUNT times, each time invoking MACRO with the current index * (starting at zero) and CONTEXT. The results of adjoining invocations of MACRO * are then separated by SEP. * * COUNT must be an integer between zero and twenty, inclusive. */ #define hl_metamacro_for_cxt(COUNT, MACRO, SEP, CONTEXT) \ hl_metamacro_concat(hl_metamacro_for_cxt, COUNT)(MACRO, SEP, CONTEXT) /** * Returns the first argument given. At least one argument must be provided. * * This is useful when implementing a variadic macro, where you may have only * one variadic argument, but no way to retrieve it (for example, because \c ... * always needs to match at least one argument). * * @code #define varmacro(...) \ hl_metamacro_head(__VA_ARGS__) * @endcode */ #define hl_metamacro_head(...) \ hl_metamacro_head_(__VA_ARGS__, 0) /** * Returns every argument except the first. At least two arguments must be * provided. */ #define hl_metamacro_tail(...) \ hl_metamacro_tail_(__VA_ARGS__) /** * Returns the first N (up to twenty) variadic arguments as a new argument list. * At least N variadic arguments must be provided. */ #define hl_metamacro_take(N, ...) \ hl_metamacro_concat(hl_metamacro_take, N)(__VA_ARGS__) /** * Removes the first N (up to twenty) variadic arguments from the given argument * list. At least N variadic arguments must be provided. */ #define hl_metamacro_drop(N, ...) \ hl_metamacro_concat(hl_metamacro_drop, N)(__VA_ARGS__) /** * Decrements VAL, which must be a number between zero and twenty, inclusive. * * This is primarily useful when dealing with indexes and counts in * metaprogramming. */ #define hl_metamacro_dec(VAL) \ hl_metamacro_at(VAL, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19) /** * Increments VAL, which must be a number between zero and twenty, inclusive. * * This is primarily useful when dealing with indexes and counts in * metaprogramming. */ #define hl_metamacro_inc(VAL) \ hl_metamacro_at(VAL, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21) /** * If A is equal to B, the next argument list is expanded; otherwise, the * argument list after that is expanded. A and B must be numbers between zero * and twenty, inclusive. Additionally, B must be greater than or equal to A. * * @code // expands to true hl_metamacro_if_eq(0, 0)(true)(false) // expands to false hl_metamacro_if_eq(0, 1)(true)(false) * @endcode * * This is primarily useful when dealing with indexes and counts in * metaprogramming. */ #define hl_metamacro_if_eq(A, B) \ hl_metamacro_concat(hl_metamacro_if_eq, A)(B) /** * Identical to #hl_metamacro_if_eq. This can be used when the former would fail * due to recursive macro expansion. */ #define hl_metamacro_if_eq_recursive(A, B) \ hl_metamacro_concat(hl_metamacro_if_eq_recursive, A)(B) /** * Returns 1 if N is an even number, or 0 otherwise. N must be between zero and * twenty, inclusive. * * For the purposes of this test, zero is considered even. */ #define hl_metamacro_is_even(N) \ hl_metamacro_at(N, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1) /** * Returns the logical NOT of B, which must be the number zero or one. */ #define hl_metamacro_not(B) \ hl_metamacro_at(B, 1, 0) // IMPLEMENTATION DETAILS FOLLOW! // Do not write code that depends on anything below this line. #define hl_metamacro_stringify_(VALUE) # VALUE #define hl_metamacro_concat_(A, B) A ## B #define hl_metamacro_foreach_iter(INDEX, MACRO, ARG) MACRO(INDEX, ARG) #define hl_metamacro_head_(FIRST, ...) FIRST #define hl_metamacro_tail_(FIRST, ...) __VA_ARGS__ #define hl_metamacro_consume_(...) #define hl_metamacro_expand_(...) __VA_ARGS__ // implemented from scratch so that hl_metamacro_concat() doesn't end up nesting #define hl_metamacro_foreach_concat_iter(INDEX, BASE, ARG) hl_metamacro_foreach_concat_iter_(BASE, ARG) #define hl_metamacro_foreach_concat_iter_(BASE, ARG) BASE ## ARG // hl_metamacro_at expansions #define hl_metamacro_at0(...) hl_metamacro_head(__VA_ARGS__) #define hl_metamacro_at1(_0, ...) hl_metamacro_head(__VA_ARGS__) #define hl_metamacro_at2(_0, _1, ...) hl_metamacro_head(__VA_ARGS__) #define hl_metamacro_at3(_0, _1, _2, ...) hl_metamacro_head(__VA_ARGS__) #define hl_metamacro_at4(_0, _1, _2, _3, ...) hl_metamacro_head(__VA_ARGS__) #define hl_metamacro_at5(_0, _1, _2, _3, _4, ...) hl_metamacro_head(__VA_ARGS__) #define hl_metamacro_at6(_0, _1, _2, _3, _4, _5, ...) hl_metamacro_head(__VA_ARGS__) #define hl_metamacro_at7(_0, _1, _2, _3, _4, _5, _6, ...) hl_metamacro_head(__VA_ARGS__) #define hl_metamacro_at8(_0, _1, _2, _3, _4, _5, _6, _7, ...) hl_metamacro_head(__VA_ARGS__) #define hl_metamacro_at9(_0, _1, _2, _3, _4, _5, _6, _7, _8, ...) hl_metamacro_head(__VA_ARGS__) #define hl_metamacro_at10(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, ...) hl_metamacro_head(__VA_ARGS__) #define hl_metamacro_at11(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, ...) hl_metamacro_head(__VA_ARGS__) #define hl_metamacro_at12(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, ...) hl_metamacro_head(__VA_ARGS__) #define hl_metamacro_at13(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, ...) hl_metamacro_head(__VA_ARGS__) #define hl_metamacro_at14(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, ...) hl_metamacro_head(__VA_ARGS__) #define hl_metamacro_at15(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, ...) hl_metamacro_head(__VA_ARGS__) #define hl_metamacro_at16(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, ...) hl_metamacro_head(__VA_ARGS__) #define hl_metamacro_at17(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, ...) hl_metamacro_head(__VA_ARGS__) #define hl_metamacro_at18(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, ...) hl_metamacro_head(__VA_ARGS__) #define hl_metamacro_at19(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, ...) hl_metamacro_head(__VA_ARGS__) #define hl_metamacro_at20(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, ...) hl_metamacro_head(__VA_ARGS__) // hl_metamacro_foreach_cxt expansions #define hl_metamacro_foreach_cxt0(MACRO, SEP, CONTEXT) #define hl_metamacro_foreach_cxt1(MACRO, SEP, CONTEXT, _0) MACRO(0, CONTEXT, _0) #define hl_metamacro_foreach_cxt2(MACRO, SEP, CONTEXT, _0, _1) \ hl_metamacro_foreach_cxt1(MACRO, SEP, CONTEXT, _0) \ SEP \ MACRO(1, CONTEXT, _1) #define hl_metamacro_foreach_cxt3(MACRO, SEP, CONTEXT, _0, _1, _2) \ hl_metamacro_foreach_cxt2(MACRO, SEP, CONTEXT, _0, _1) \ SEP \ MACRO(2, CONTEXT, _2) #define hl_metamacro_foreach_cxt4(MACRO, SEP, CONTEXT, _0, _1, _2, _3) \ hl_metamacro_foreach_cxt3(MACRO, SEP, CONTEXT, _0, _1, _2) \ SEP \ MACRO(3, CONTEXT, _3) #define hl_metamacro_foreach_cxt5(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4) \ hl_metamacro_foreach_cxt4(MACRO, SEP, CONTEXT, _0, _1, _2, _3) \ SEP \ MACRO(4, CONTEXT, _4) #define hl_metamacro_foreach_cxt6(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5) \ hl_metamacro_foreach_cxt5(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4) \ SEP \ MACRO(5, CONTEXT, _5) #define hl_metamacro_foreach_cxt7(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6) \ hl_metamacro_foreach_cxt6(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5) \ SEP \ MACRO(6, CONTEXT, _6) #define hl_metamacro_foreach_cxt8(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7) \ hl_metamacro_foreach_cxt7(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6) \ SEP \ MACRO(7, CONTEXT, _7) #define hl_metamacro_foreach_cxt9(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8) \ hl_metamacro_foreach_cxt8(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7) \ SEP \ MACRO(8, CONTEXT, _8) #define hl_metamacro_foreach_cxt10(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9) \ hl_metamacro_foreach_cxt9(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8) \ SEP \ MACRO(9, CONTEXT, _9) #define hl_metamacro_foreach_cxt11(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) \ hl_metamacro_foreach_cxt10(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9) \ SEP \ MACRO(10, CONTEXT, _10) #define hl_metamacro_foreach_cxt12(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11) \ hl_metamacro_foreach_cxt11(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) \ SEP \ MACRO(11, CONTEXT, _11) #define hl_metamacro_foreach_cxt13(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12) \ hl_metamacro_foreach_cxt12(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11) \ SEP \ MACRO(12, CONTEXT, _12) #define hl_metamacro_foreach_cxt14(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13) \ hl_metamacro_foreach_cxt13(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12) \ SEP \ MACRO(13, CONTEXT, _13) #define hl_metamacro_foreach_cxt15(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14) \ hl_metamacro_foreach_cxt14(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13) \ SEP \ MACRO(14, CONTEXT, _14) #define hl_metamacro_foreach_cxt16(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15) \ hl_metamacro_foreach_cxt15(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14) \ SEP \ MACRO(15, CONTEXT, _15) #define hl_metamacro_foreach_cxt17(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16) \ hl_metamacro_foreach_cxt16(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15) \ SEP \ MACRO(16, CONTEXT, _16) #define hl_metamacro_foreach_cxt18(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17) \ hl_metamacro_foreach_cxt17(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16) \ SEP \ MACRO(17, CONTEXT, _17) #define hl_metamacro_foreach_cxt19(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18) \ hl_metamacro_foreach_cxt18(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17) \ SEP \ MACRO(18, CONTEXT, _18) #define hl_metamacro_foreach_cxt20(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19) \ hl_metamacro_foreach_cxt19(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18) \ SEP \ MACRO(19, CONTEXT, _19) // hl_metamacro_foreach_cxt_recursive expansions #define hl_metamacro_foreach_cxt_recursive0(MACRO, SEP, CONTEXT) #define hl_metamacro_foreach_cxt_recursive1(MACRO, SEP, CONTEXT, _0) MACRO(0, CONTEXT, _0) #define hl_metamacro_foreach_cxt_recursive2(MACRO, SEP, CONTEXT, _0, _1) \ hl_metamacro_foreach_cxt_recursive1(MACRO, SEP, CONTEXT, _0) \ SEP \ MACRO(1, CONTEXT, _1) #define hl_metamacro_foreach_cxt_recursive3(MACRO, SEP, CONTEXT, _0, _1, _2) \ hl_metamacro_foreach_cxt_recursive2(MACRO, SEP, CONTEXT, _0, _1) \ SEP \ MACRO(2, CONTEXT, _2) #define hl_metamacro_foreach_cxt_recursive4(MACRO, SEP, CONTEXT, _0, _1, _2, _3) \ hl_metamacro_foreach_cxt_recursive3(MACRO, SEP, CONTEXT, _0, _1, _2) \ SEP \ MACRO(3, CONTEXT, _3) #define hl_metamacro_foreach_cxt_recursive5(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4) \ hl_metamacro_foreach_cxt_recursive4(MACRO, SEP, CONTEXT, _0, _1, _2, _3) \ SEP \ MACRO(4, CONTEXT, _4) #define hl_metamacro_foreach_cxt_recursive6(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5) \ hl_metamacro_foreach_cxt_recursive5(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4) \ SEP \ MACRO(5, CONTEXT, _5) #define hl_metamacro_foreach_cxt_recursive7(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6) \ hl_metamacro_foreach_cxt_recursive6(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5) \ SEP \ MACRO(6, CONTEXT, _6) #define hl_metamacro_foreach_cxt_recursive8(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7) \ hl_metamacro_foreach_cxt_recursive7(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6) \ SEP \ MACRO(7, CONTEXT, _7) #define hl_metamacro_foreach_cxt_recursive9(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8) \ hl_metamacro_foreach_cxt_recursive8(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7) \ SEP \ MACRO(8, CONTEXT, _8) #define hl_metamacro_foreach_cxt_recursive10(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9) \ hl_metamacro_foreach_cxt_recursive9(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8) \ SEP \ MACRO(9, CONTEXT, _9) #define hl_metamacro_foreach_cxt_recursive11(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) \ hl_metamacro_foreach_cxt_recursive10(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9) \ SEP \ MACRO(10, CONTEXT, _10) #define hl_metamacro_foreach_cxt_recursive12(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11) \ hl_metamacro_foreach_cxt_recursive11(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) \ SEP \ MACRO(11, CONTEXT, _11) #define hl_metamacro_foreach_cxt_recursive13(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12) \ hl_metamacro_foreach_cxt_recursive12(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11) \ SEP \ MACRO(12, CONTEXT, _12) #define hl_metamacro_foreach_cxt_recursive14(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13) \ hl_metamacro_foreach_cxt_recursive13(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12) \ SEP \ MACRO(13, CONTEXT, _13) #define hl_metamacro_foreach_cxt_recursive15(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14) \ hl_metamacro_foreach_cxt_recursive14(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13) \ SEP \ MACRO(14, CONTEXT, _14) #define hl_metamacro_foreach_cxt_recursive16(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15) \ hl_metamacro_foreach_cxt_recursive15(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14) \ SEP \ MACRO(15, CONTEXT, _15) #define hl_metamacro_foreach_cxt_recursive17(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16) \ hl_metamacro_foreach_cxt_recursive16(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15) \ SEP \ MACRO(16, CONTEXT, _16) #define hl_metamacro_foreach_cxt_recursive18(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17) \ hl_metamacro_foreach_cxt_recursive17(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16) \ SEP \ MACRO(17, CONTEXT, _17) #define hl_metamacro_foreach_cxt_recursive19(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18) \ hl_metamacro_foreach_cxt_recursive18(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17) \ SEP \ MACRO(18, CONTEXT, _18) #define hl_metamacro_foreach_cxt_recursive20(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19) \ hl_metamacro_foreach_cxt_recursive19(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18) \ SEP \ MACRO(19, CONTEXT, _19) // hl_metamacro_for_cxt expansions #define hl_metamacro_for_cxt0(MACRO, SEP, CONTEXT) #define hl_metamacro_for_cxt1(MACRO, SEP, CONTEXT) MACRO(0, CONTEXT) #define hl_metamacro_for_cxt2(MACRO, SEP, CONTEXT) \ hl_metamacro_for_cxt1(MACRO, SEP, CONTEXT) \ SEP \ MACRO(1, CONTEXT) #define hl_metamacro_for_cxt3(MACRO, SEP, CONTEXT) \ hl_metamacro_for_cxt2(MACRO, SEP, CONTEXT) \ SEP \ MACRO(2, CONTEXT) #define hl_metamacro_for_cxt4(MACRO, SEP, CONTEXT) \ hl_metamacro_for_cxt3(MACRO, SEP, CONTEXT) \ SEP \ MACRO(3, CONTEXT) #define hl_metamacro_for_cxt5(MACRO, SEP, CONTEXT) \ hl_metamacro_for_cxt4(MACRO, SEP, CONTEXT) \ SEP \ MACRO(4, CONTEXT) #define hl_metamacro_for_cxt6(MACRO, SEP, CONTEXT) \ hl_metamacro_for_cxt5(MACRO, SEP, CONTEXT) \ SEP \ MACRO(5, CONTEXT) #define hl_metamacro_for_cxt7(MACRO, SEP, CONTEXT) \ hl_metamacro_for_cxt6(MACRO, SEP, CONTEXT) \ SEP \ MACRO(6, CONTEXT) #define hl_metamacro_for_cxt8(MACRO, SEP, CONTEXT) \ hl_metamacro_for_cxt7(MACRO, SEP, CONTEXT) \ SEP \ MACRO(7, CONTEXT) #define hl_metamacro_for_cxt9(MACRO, SEP, CONTEXT) \ hl_metamacro_for_cxt8(MACRO, SEP, CONTEXT) \ SEP \ MACRO(8, CONTEXT) #define hl_metamacro_for_cxt10(MACRO, SEP, CONTEXT) \ hl_metamacro_for_cxt9(MACRO, SEP, CONTEXT) \ SEP \ MACRO(9, CONTEXT) #define hl_metamacro_for_cxt11(MACRO, SEP, CONTEXT) \ hl_metamacro_for_cxt10(MACRO, SEP, CONTEXT) \ SEP \ MACRO(10, CONTEXT) #define hl_metamacro_for_cxt12(MACRO, SEP, CONTEXT) \ hl_metamacro_for_cxt11(MACRO, SEP, CONTEXT) \ SEP \ MACRO(11, CONTEXT) #define hl_metamacro_for_cxt13(MACRO, SEP, CONTEXT) \ hl_metamacro_for_cxt12(MACRO, SEP, CONTEXT) \ SEP \ MACRO(12, CONTEXT) #define hl_metamacro_for_cxt14(MACRO, SEP, CONTEXT) \ hl_metamacro_for_cxt13(MACRO, SEP, CONTEXT) \ SEP \ MACRO(13, CONTEXT) #define hl_metamacro_for_cxt15(MACRO, SEP, CONTEXT) \ hl_metamacro_for_cxt14(MACRO, SEP, CONTEXT) \ SEP \ MACRO(14, CONTEXT) #define hl_metamacro_for_cxt16(MACRO, SEP, CONTEXT) \ hl_metamacro_for_cxt15(MACRO, SEP, CONTEXT) \ SEP \ MACRO(15, CONTEXT) #define hl_metamacro_for_cxt17(MACRO, SEP, CONTEXT) \ hl_metamacro_for_cxt16(MACRO, SEP, CONTEXT) \ SEP \ MACRO(16, CONTEXT) #define hl_metamacro_for_cxt18(MACRO, SEP, CONTEXT) \ hl_metamacro_for_cxt17(MACRO, SEP, CONTEXT) \ SEP \ MACRO(17, CONTEXT) #define hl_metamacro_for_cxt19(MACRO, SEP, CONTEXT) \ hl_metamacro_for_cxt18(MACRO, SEP, CONTEXT) \ SEP \ MACRO(18, CONTEXT) #define hl_metamacro_for_cxt20(MACRO, SEP, CONTEXT) \ hl_metamacro_for_cxt19(MACRO, SEP, CONTEXT) \ SEP \ MACRO(19, CONTEXT) // hl_metamacro_if_eq expansions #define hl_metamacro_if_eq0(VALUE) \ hl_metamacro_concat(hl_metamacro_if_eq0_, VALUE) #define hl_metamacro_if_eq0_0(...) __VA_ARGS__ hl_metamacro_consume_ #define hl_metamacro_if_eq0_1(...) hl_metamacro_expand_ #define hl_metamacro_if_eq0_2(...) hl_metamacro_expand_ #define hl_metamacro_if_eq0_3(...) hl_metamacro_expand_ #define hl_metamacro_if_eq0_4(...) hl_metamacro_expand_ #define hl_metamacro_if_eq0_5(...) hl_metamacro_expand_ #define hl_metamacro_if_eq0_6(...) hl_metamacro_expand_ #define hl_metamacro_if_eq0_7(...) hl_metamacro_expand_ #define hl_metamacro_if_eq0_8(...) hl_metamacro_expand_ #define hl_metamacro_if_eq0_9(...) hl_metamacro_expand_ #define hl_metamacro_if_eq0_10(...) hl_metamacro_expand_ #define hl_metamacro_if_eq0_11(...) hl_metamacro_expand_ #define hl_metamacro_if_eq0_12(...) hl_metamacro_expand_ #define hl_metamacro_if_eq0_13(...) hl_metamacro_expand_ #define hl_metamacro_if_eq0_14(...) hl_metamacro_expand_ #define hl_metamacro_if_eq0_15(...) hl_metamacro_expand_ #define hl_metamacro_if_eq0_16(...) hl_metamacro_expand_ #define hl_metamacro_if_eq0_17(...) hl_metamacro_expand_ #define hl_metamacro_if_eq0_18(...) hl_metamacro_expand_ #define hl_metamacro_if_eq0_19(...) hl_metamacro_expand_ #define hl_metamacro_if_eq0_20(...) hl_metamacro_expand_ #define hl_metamacro_if_eq1(VALUE) hl_metamacro_if_eq0(hl_metamacro_dec(VALUE)) #define hl_metamacro_if_eq2(VALUE) hl_metamacro_if_eq1(hl_metamacro_dec(VALUE)) #define hl_metamacro_if_eq3(VALUE) hl_metamacro_if_eq2(hl_metamacro_dec(VALUE)) #define hl_metamacro_if_eq4(VALUE) hl_metamacro_if_eq3(hl_metamacro_dec(VALUE)) #define hl_metamacro_if_eq5(VALUE) hl_metamacro_if_eq4(hl_metamacro_dec(VALUE)) #define hl_metamacro_if_eq6(VALUE) hl_metamacro_if_eq5(hl_metamacro_dec(VALUE)) #define hl_metamacro_if_eq7(VALUE) hl_metamacro_if_eq6(hl_metamacro_dec(VALUE)) #define hl_metamacro_if_eq8(VALUE) hl_metamacro_if_eq7(hl_metamacro_dec(VALUE)) #define hl_metamacro_if_eq9(VALUE) hl_metamacro_if_eq8(hl_metamacro_dec(VALUE)) #define hl_metamacro_if_eq10(VALUE) hl_metamacro_if_eq9(hl_metamacro_dec(VALUE)) #define hl_metamacro_if_eq11(VALUE) hl_metamacro_if_eq10(hl_metamacro_dec(VALUE)) #define hl_metamacro_if_eq12(VALUE) hl_metamacro_if_eq11(hl_metamacro_dec(VALUE)) #define hl_metamacro_if_eq13(VALUE) hl_metamacro_if_eq12(hl_metamacro_dec(VALUE)) #define hl_metamacro_if_eq14(VALUE) hl_metamacro_if_eq13(hl_metamacro_dec(VALUE)) #define hl_metamacro_if_eq15(VALUE) hl_metamacro_if_eq14(hl_metamacro_dec(VALUE)) #define hl_metamacro_if_eq16(VALUE) hl_metamacro_if_eq15(hl_metamacro_dec(VALUE)) #define hl_metamacro_if_eq17(VALUE) hl_metamacro_if_eq16(hl_metamacro_dec(VALUE)) #define hl_metamacro_if_eq18(VALUE) hl_metamacro_if_eq17(hl_metamacro_dec(VALUE)) #define hl_metamacro_if_eq19(VALUE) hl_metamacro_if_eq18(hl_metamacro_dec(VALUE)) #define hl_metamacro_if_eq20(VALUE) hl_metamacro_if_eq19(hl_metamacro_dec(VALUE)) // hl_metamacro_if_eq_recursive expansions #define hl_metamacro_if_eq_recursive0(VALUE) \ hl_metamacro_concat(hl_metamacro_if_eq_recursive0_, VALUE) #define hl_metamacro_if_eq_recursive0_0(...) __VA_ARGS__ hl_metamacro_consume_ #define hl_metamacro_if_eq_recursive0_1(...) hl_metamacro_expand_ #define hl_metamacro_if_eq_recursive0_2(...) hl_metamacro_expand_ #define hl_metamacro_if_eq_recursive0_3(...) hl_metamacro_expand_ #define hl_metamacro_if_eq_recursive0_4(...) hl_metamacro_expand_ #define hl_metamacro_if_eq_recursive0_5(...) hl_metamacro_expand_ #define hl_metamacro_if_eq_recursive0_6(...) hl_metamacro_expand_ #define hl_metamacro_if_eq_recursive0_7(...) hl_metamacro_expand_ #define hl_metamacro_if_eq_recursive0_8(...) hl_metamacro_expand_ #define hl_metamacro_if_eq_recursive0_9(...) hl_metamacro_expand_ #define hl_metamacro_if_eq_recursive0_10(...) hl_metamacro_expand_ #define hl_metamacro_if_eq_recursive0_11(...) hl_metamacro_expand_ #define hl_metamacro_if_eq_recursive0_12(...) hl_metamacro_expand_ #define hl_metamacro_if_eq_recursive0_13(...) hl_metamacro_expand_ #define hl_metamacro_if_eq_recursive0_14(...) hl_metamacro_expand_ #define hl_metamacro_if_eq_recursive0_15(...) hl_metamacro_expand_ #define hl_metamacro_if_eq_recursive0_16(...) hl_metamacro_expand_ #define hl_metamacro_if_eq_recursive0_17(...) hl_metamacro_expand_ #define hl_metamacro_if_eq_recursive0_18(...) hl_metamacro_expand_ #define hl_metamacro_if_eq_recursive0_19(...) hl_metamacro_expand_ #define hl_metamacro_if_eq_recursive0_20(...) hl_metamacro_expand_ #define hl_metamacro_if_eq_recursive1(VALUE) hl_metamacro_if_eq_recursive0(hl_metamacro_dec(VALUE)) #define hl_metamacro_if_eq_recursive2(VALUE) hl_metamacro_if_eq_recursive1(hl_metamacro_dec(VALUE)) #define hl_metamacro_if_eq_recursive3(VALUE) hl_metamacro_if_eq_recursive2(hl_metamacro_dec(VALUE)) #define hl_metamacro_if_eq_recursive4(VALUE) hl_metamacro_if_eq_recursive3(hl_metamacro_dec(VALUE)) #define hl_metamacro_if_eq_recursive5(VALUE) hl_metamacro_if_eq_recursive4(hl_metamacro_dec(VALUE)) #define hl_metamacro_if_eq_recursive6(VALUE) hl_metamacro_if_eq_recursive5(hl_metamacro_dec(VALUE)) #define hl_metamacro_if_eq_recursive7(VALUE) hl_metamacro_if_eq_recursive6(hl_metamacro_dec(VALUE)) #define hl_metamacro_if_eq_recursive8(VALUE) hl_metamacro_if_eq_recursive7(hl_metamacro_dec(VALUE)) #define hl_metamacro_if_eq_recursive9(VALUE) hl_metamacro_if_eq_recursive8(hl_metamacro_dec(VALUE)) #define hl_metamacro_if_eq_recursive10(VALUE) hl_metamacro_if_eq_recursive9(hl_metamacro_dec(VALUE)) #define hl_metamacro_if_eq_recursive11(VALUE) hl_metamacro_if_eq_recursive10(hl_metamacro_dec(VALUE)) #define hl_metamacro_if_eq_recursive12(VALUE) hl_metamacro_if_eq_recursive11(hl_metamacro_dec(VALUE)) #define hl_metamacro_if_eq_recursive13(VALUE) hl_metamacro_if_eq_recursive12(hl_metamacro_dec(VALUE)) #define hl_metamacro_if_eq_recursive14(VALUE) hl_metamacro_if_eq_recursive13(hl_metamacro_dec(VALUE)) #define hl_metamacro_if_eq_recursive15(VALUE) hl_metamacro_if_eq_recursive14(hl_metamacro_dec(VALUE)) #define hl_metamacro_if_eq_recursive16(VALUE) hl_metamacro_if_eq_recursive15(hl_metamacro_dec(VALUE)) #define hl_metamacro_if_eq_recursive17(VALUE) hl_metamacro_if_eq_recursive16(hl_metamacro_dec(VALUE)) #define hl_metamacro_if_eq_recursive18(VALUE) hl_metamacro_if_eq_recursive17(hl_metamacro_dec(VALUE)) #define hl_metamacro_if_eq_recursive19(VALUE) hl_metamacro_if_eq_recursive18(hl_metamacro_dec(VALUE)) #define hl_metamacro_if_eq_recursive20(VALUE) hl_metamacro_if_eq_recursive19(hl_metamacro_dec(VALUE)) // hl_metamacro_take expansions #define hl_metamacro_take0(...) #define hl_metamacro_take1(...) hl_metamacro_head(__VA_ARGS__) #define hl_metamacro_take2(...) hl_metamacro_head(__VA_ARGS__), hl_metamacro_take1(hl_metamacro_tail(__VA_ARGS__)) #define hl_metamacro_take3(...) hl_metamacro_head(__VA_ARGS__), hl_metamacro_take2(hl_metamacro_tail(__VA_ARGS__)) #define hl_metamacro_take4(...) hl_metamacro_head(__VA_ARGS__), hl_metamacro_take3(hl_metamacro_tail(__VA_ARGS__)) #define hl_metamacro_take5(...) hl_metamacro_head(__VA_ARGS__), hl_metamacro_take4(hl_metamacro_tail(__VA_ARGS__)) #define hl_metamacro_take6(...) hl_metamacro_head(__VA_ARGS__), hl_metamacro_take5(hl_metamacro_tail(__VA_ARGS__)) #define hl_metamacro_take7(...) hl_metamacro_head(__VA_ARGS__), hl_metamacro_take6(hl_metamacro_tail(__VA_ARGS__)) #define hl_metamacro_take8(...) hl_metamacro_head(__VA_ARGS__), hl_metamacro_take7(hl_metamacro_tail(__VA_ARGS__)) #define hl_metamacro_take9(...) hl_metamacro_head(__VA_ARGS__), hl_metamacro_take8(hl_metamacro_tail(__VA_ARGS__)) #define hl_metamacro_take10(...) hl_metamacro_head(__VA_ARGS__), hl_metamacro_take9(hl_metamacro_tail(__VA_ARGS__)) #define hl_metamacro_take11(...) hl_metamacro_head(__VA_ARGS__), hl_metamacro_take10(hl_metamacro_tail(__VA_ARGS__)) #define hl_metamacro_take12(...) hl_metamacro_head(__VA_ARGS__), hl_metamacro_take11(hl_metamacro_tail(__VA_ARGS__)) #define hl_metamacro_take13(...) hl_metamacro_head(__VA_ARGS__), hl_metamacro_take12(hl_metamacro_tail(__VA_ARGS__)) #define hl_metamacro_take14(...) hl_metamacro_head(__VA_ARGS__), hl_metamacro_take13(hl_metamacro_tail(__VA_ARGS__)) #define hl_metamacro_take15(...) hl_metamacro_head(__VA_ARGS__), hl_metamacro_take14(hl_metamacro_tail(__VA_ARGS__)) #define hl_metamacro_take16(...) hl_metamacro_head(__VA_ARGS__), hl_metamacro_take15(hl_metamacro_tail(__VA_ARGS__)) #define hl_metamacro_take17(...) hl_metamacro_head(__VA_ARGS__), hl_metamacro_take16(hl_metamacro_tail(__VA_ARGS__)) #define hl_metamacro_take18(...) hl_metamacro_head(__VA_ARGS__), hl_metamacro_take17(hl_metamacro_tail(__VA_ARGS__)) #define hl_metamacro_take19(...) hl_metamacro_head(__VA_ARGS__), hl_metamacro_take18(hl_metamacro_tail(__VA_ARGS__)) #define hl_metamacro_take20(...) hl_metamacro_head(__VA_ARGS__), hl_metamacro_take19(hl_metamacro_tail(__VA_ARGS__)) // hl_metamacro_drop expansions #define hl_metamacro_drop0(...) __VA_ARGS__ #define hl_metamacro_drop1(...) hl_metamacro_tail(__VA_ARGS__) #define hl_metamacro_drop2(...) hl_metamacro_drop1(hl_metamacro_tail(__VA_ARGS__)) #define hl_metamacro_drop3(...) hl_metamacro_drop2(hl_metamacro_tail(__VA_ARGS__)) #define hl_metamacro_drop4(...) hl_metamacro_drop3(hl_metamacro_tail(__VA_ARGS__)) #define hl_metamacro_drop5(...) hl_metamacro_drop4(hl_metamacro_tail(__VA_ARGS__)) #define hl_metamacro_drop6(...) hl_metamacro_drop5(hl_metamacro_tail(__VA_ARGS__)) #define hl_metamacro_drop7(...) hl_metamacro_drop6(hl_metamacro_tail(__VA_ARGS__)) #define hl_metamacro_drop8(...) hl_metamacro_drop7(hl_metamacro_tail(__VA_ARGS__)) #define hl_metamacro_drop9(...) hl_metamacro_drop8(hl_metamacro_tail(__VA_ARGS__)) #define hl_metamacro_drop10(...) hl_metamacro_drop9(hl_metamacro_tail(__VA_ARGS__)) #define hl_metamacro_drop11(...) hl_metamacro_drop10(hl_metamacro_tail(__VA_ARGS__)) #define hl_metamacro_drop12(...) hl_metamacro_drop11(hl_metamacro_tail(__VA_ARGS__)) #define hl_metamacro_drop13(...) hl_metamacro_drop12(hl_metamacro_tail(__VA_ARGS__)) #define hl_metamacro_drop14(...) hl_metamacro_drop13(hl_metamacro_tail(__VA_ARGS__)) #define hl_metamacro_drop15(...) hl_metamacro_drop14(hl_metamacro_tail(__VA_ARGS__)) #define hl_metamacro_drop16(...) hl_metamacro_drop15(hl_metamacro_tail(__VA_ARGS__)) #define hl_metamacro_drop17(...) hl_metamacro_drop16(hl_metamacro_tail(__VA_ARGS__)) #define hl_metamacro_drop18(...) hl_metamacro_drop17(hl_metamacro_tail(__VA_ARGS__)) #define hl_metamacro_drop19(...) hl_metamacro_drop18(hl_metamacro_tail(__VA_ARGS__)) #define hl_metamacro_drop20(...) hl_metamacro_drop19(hl_metamacro_tail(__VA_ARGS__)) #endif ================================================ FILE: HLNetworking/Source/Config/HLNetworkPolicyConfig.h ================================================ // // HLNetworkPolicyConfig.h // HLNetworking // // Created by wangshiyu13 on 2017/1/2. // Copyright © 2017年 wangshiyu13. All rights reserved. // #import @interface HLNetworkPolicyConfig : NSObject // 是否为后台模式所用的GroupID,该选项只对Task有影响 @property (nonatomic, copy) NSString *AppGroup; // 是否为后台模式,该选项只对Task有影响 @property (nonatomic, assign) BOOL isBackgroundSession; // 出现网络请求错误时,是否在请求错误的文字后加上{code},默认为YES @property (nonatomic, assign) BOOL isErrorCodeDisplayEnabled; // 请求缓存策略,默认为NSURLRequestUseProtocolCachePolicy @property (nonatomic, assign) NSURLRequestCachePolicy cachePolicy; // URLCache设置 @property (nonatomic, assign) NSURLCache *URLCache; // 快速构建config + (HLNetworkPolicyConfig *)config; // 请使用config - (instancetype)init NS_UNAVAILABLE; + (instancetype)new NS_UNAVAILABLE; @end ================================================ FILE: HLNetworking/Source/Config/HLNetworkPolicyConfig.m ================================================ // // HLNetworkPolicyConfig.m // HLNetworking // // Created by wangshiyu13 on 2017/1/2. // Copyright © 2017年 wangshiyu13. All rights reserved. // #import "HLNetworkPolicyConfig.h" @implementation HLNetworkPolicyConfig + (HLNetworkPolicyConfig *)config { return [[self alloc] init]; } - (instancetype)init { self = [super init]; if (self) { _isBackgroundSession = NO; _isErrorCodeDisplayEnabled = YES; _cachePolicy = NSURLRequestUseProtocolCachePolicy; _URLCache = [NSURLCache sharedURLCache]; } return self; } - (id)copyWithZone:(NSZone *)zone { HLNetworkPolicyConfig *config = [[[self class] alloc] init]; if (config) { config.isErrorCodeDisplayEnabled = _isErrorCodeDisplayEnabled; config.isBackgroundSession = _isBackgroundSession; config.AppGroup = [_AppGroup copyWithZone:zone]; } return config; } @end ================================================ FILE: HLNetworking/Source/Config/HLNetworkRequestConfig.h ================================================ // // HLNetworkRequestConfig.h // HLNetworking // // Created by wangshiyu13 on 2017/1/2. // Copyright © 2017年 wangshiyu13. All rights reserved. // #import // 默认的请求超时时间 #define HL_API_REQUEST_TIME_OUT 15 // 每个host最大连接数 #define MAX_HTTP_CONNECTION_PER_HOST 5 @interface HLNetworkRequestConfig : NSObject // API请求的自定义队列 @property (nonatomic, strong, nullable) dispatch_queue_t callbackQueue; // 默认的parameters,可以在HLAPI中选择是否使用,默认开启 @property (nonatomic, strong, nullable) NSDictionary *defaultParams; // 默认的header,可以在HLAPI中覆盖 @property (nonatomic, strong, nullable) NSDictionary *defaultHeaders; // 全局的baseURL,HLAPI的baseURL会覆盖该参数 @property (nonatomic, copy, nullable) NSString *baseURL; // api版本,用于拼接在请求的Path上 // 默认为infoPlist中的CFBundleShortVersionString,格式为v{version}{r},审核版本为r @property (nonatomic, copy, nullable) NSString *apiVersion; // 是否为审核版本,作用于apiVersion,存储在NSUserDefaults中,key为isR @property (nonatomic, assign) BOOL isJudgeVersion; // UserAgent,request header中的UA,默认为nil @property (nonatomic, copy, nullable) NSString *userAgent; // 每个Host的最大连接数,默认为5 @property (nonatomic, assign) NSUInteger maxHttpConnectionPerHost; // 网络状态不好时自动重试次数,默认为0 @property (nonatomic, assign) NSUInteger retryCount; // 请求超时时间,默认为15秒 @property (nonatomic, assign) NSTimeInterval requestTimeoutInterval; // 获取当前版本 - (nonnull NSString *)getCurrentVersion; // 快速构建config + (nonnull HLNetworkRequestConfig *)config; // 请使用config - (nonnull instancetype)init NS_UNAVAILABLE; + (nonnull instancetype)new NS_UNAVAILABLE; @end ================================================ FILE: HLNetworking/Source/Config/HLNetworkRequestConfig.m ================================================ // // HLNetworkRequestConfig.m // HLNetworking // // Created by wangshiyu13 on 2017/1/2. // Copyright © 2017年 wangshiyu13. All rights reserved. // #import "HLNetworkRequestConfig.h" @implementation HLNetworkRequestConfig + (HLNetworkRequestConfig *)config { return [[self alloc] init]; } - (instancetype)init { self = [super init]; if (self) { _callbackQueue = nil; _maxHttpConnectionPerHost = MAX_HTTP_CONNECTION_PER_HOST; _requestTimeoutInterval = HL_API_REQUEST_TIME_OUT; _retryCount = 0; _apiVersion = nil; _isJudgeVersion = [[NSUserDefaults standardUserDefaults] boolForKey:@"isR"] ? : YES; } return self; } - (NSString *)getCurrentVersion { NSString *origin = [[NSBundle mainBundle].infoDictionary[@"CFBundleShortVersionString"] stringByReplacingOccurrencesOfString:@"." withString:@""]; if (self.isJudgeVersion) { return [NSString stringWithFormat:@"v%@r", origin]; } else { return [NSString stringWithFormat:@"v%@", origin]; } } - (id)copyWithZone:(NSZone *)zone { HLNetworkRequestConfig *config = [[[self class] alloc] init]; if (config) { config.defaultHeaders = [_defaultHeaders copyWithZone:zone]; config.defaultParams = [_defaultParams copyWithZone:zone]; config.baseURL = [_baseURL copyWithZone:zone]; config.apiVersion = [_apiVersion copyWithZone:zone]; config.userAgent = [_userAgent copyWithZone:zone]; config.isJudgeVersion = _isJudgeVersion; config.requestTimeoutInterval = _requestTimeoutInterval; config.maxHttpConnectionPerHost = _maxHttpConnectionPerHost; } return config; } @end ================================================ FILE: HLNetworking/Source/Config/HLNetworkTipsConfig.h ================================================ // // HLNetworkTipsConfig.h // HLNetworking // // Created by wangshiyu13 on 2017/1/2. // Copyright © 2017年 wangshiyu13. All rights reserved. // #import FOUNDATION_EXPORT NSString * const HLDefaultGeneralErrorString; FOUNDATION_EXPORT NSString * const HLDefaultFrequentRequestErrorString; FOUNDATION_EXPORT NSString * const HLDefaultNetworkNotReachableString; @interface HLNetworkTipsConfig : NSObject // 出现网络请求时,为了给用户比较好的用户体验,而使用的错误提示文字, // 默认为:服务器连接错误,请稍候重试 @property (nonatomic, copy) NSString *generalErrorTypeStr; // 用户频繁发送同一个请求,使用的错误提示文字 // 默认为:请求发送速度太快, 请稍候重试 @property (nonatomic, copy) NSString *frequentRequestErrorStr; // 网络请求开始时,会先检测相应网络域名的Reachability,如果不可达,则直接返回该错误文字 // 默认为:网络不可用,请稍后重试 @property (nonatomic, copy) NSString *networkNotReachableErrorStr; // 网络指示器(状态栏),默认为YES @property (nonatomic, assign) BOOL isNetworkingActivityIndicatorEnabled; // 快速构建config + (HLNetworkTipsConfig *)config; // 请使用config - (instancetype)init NS_UNAVAILABLE; + (instancetype)new NS_UNAVAILABLE; @end ================================================ FILE: HLNetworking/Source/Config/HLNetworkTipsConfig.m ================================================ // // HLNetworkTipsConfig.m // HLNetworking // // Created by wangshiyu13 on 2017/1/2. // Copyright © 2017年 wangshiyu13. All rights reserved. // #import "HLNetworkTipsConfig.h" NSString * const HLDefaultGeneralErrorString = @"服务器连接错误,请稍候重试"; NSString * const HLDefaultFrequentRequestErrorString = @"请求发送速度太快, 请稍候重试"; NSString * const HLDefaultNetworkNotReachableString = @"网络不可用,请稍后重试"; @implementation HLNetworkTipsConfig + (HLNetworkTipsConfig *)config { return [[self alloc] init]; } - (instancetype)init { self = [super init]; if (self) { _generalErrorTypeStr = HLDefaultGeneralErrorString; _frequentRequestErrorStr = HLDefaultFrequentRequestErrorString; _networkNotReachableErrorStr = HLDefaultNetworkNotReachableString; _isNetworkingActivityIndicatorEnabled = YES; } return self; } - (id)copyWithZone:(NSZone *)zone { HLNetworkTipsConfig *config = [[[self class] alloc] init]; if (config) { config.generalErrorTypeStr = [_generalErrorTypeStr copyWithZone:zone]; config.frequentRequestErrorStr = [_frequentRequestErrorStr copyWithZone:zone]; config.networkNotReachableErrorStr = [_networkNotReachableErrorStr copyWithZone:zone]; config.isNetworkingActivityIndicatorEnabled = _isNetworkingActivityIndicatorEnabled; } return config; } @end ================================================ FILE: HLNetworking/Source/Config/HLSecurityPolicyConfig.h ================================================ // // HLSecurityPolicyConfig.h // HLPPShop // // Created by wangshiyu13 on 2016/9/19. // Copyright © 2016年 wangshiyu13. All rights reserved. // #import // SSL Pinning typedef NS_ENUM(NSUInteger, HLSSLPinningMode) { // 不校验Pinning证书 HLSSLPinningModeNone, // 校验Pinning证书中的PublicKey HLSSLPinningModePublicKey, // 校验整个Pinning证书 HLSSLPinningModeCertificate }; @interface HLSecurityPolicyConfig : NSObject // SSL Pinning证书的校验模式,默认为 HLSSLPinningModeNone @property (readonly, nonatomic, assign) HLSSLPinningMode SSLPinningMode; // 是否允许使用Invalid 证书,默认为 NO @property (nonatomic, assign) BOOL allowInvalidCertificates; // 是否校验在证书 CN 字段中的 domain name,默认为 YES @property (nonatomic, assign) BOOL validatesDomainName; // cer证书文件路径 @property (nonatomic, copy) NSString *cerFilePath; /** 创建新的SecurityPolicy @param pinningMode 证书校验模式 @return 新的SecurityPolicy */ + (instancetype)policyWithPinningMode:(HLSSLPinningMode)pinningMode; - (NSDictionary *)toDictionary; @end ================================================ FILE: HLNetworking/Source/Config/HLSecurityPolicyConfig.m ================================================ // // HLSecurityPolicyConfig.m // HLPPShop // // Created by wangshiyu13 on 2016/9/19. // Copyright © 2016年 wangshiyu13. All rights reserved. // #import "HLSecurityPolicyConfig.h" @interface HLSecurityPolicyConfig () @property (readwrite, nonatomic, assign) HLSSLPinningMode SSLPinningMode; @end @implementation HLSecurityPolicyConfig + (instancetype)policyWithPinningMode:(HLSSLPinningMode)pinningMode { HLSecurityPolicyConfig *securityPolicy = [[HLSecurityPolicyConfig alloc] init]; if (securityPolicy) { securityPolicy.SSLPinningMode = pinningMode; securityPolicy.allowInvalidCertificates = NO; securityPolicy.validatesDomainName = YES; securityPolicy.cerFilePath = nil; } return securityPolicy; } - (NSString *)description { NSMutableString *desc = [NSMutableString string]; #if DEBUG [desc appendString:@"\n\n----HLSecurityPolicyConfig Start----\n"]; [desc appendFormat:@"SSLPinningMode: %@\n", [self getpinningModeString:self.SSLPinningMode]]; [desc appendFormat:@"AllowInvalidCertificates: %@\n", self.allowInvalidCertificates ? @"YES" : @"NO"]; [desc appendFormat:@"ValidatesDomainName: %@\n", self.validatesDomainName ? @"YES" : @"NO"]; [desc appendFormat:@"CerFilePath: %@\n", self.cerFilePath ?: @"未设置"]; [desc appendString:@"------HLSecurityPolicyConfig End------\n"]; #else desc = [NSMutableString stringWithFormat:@""]; #endif return desc; } - (NSDictionary *)toDictionary { NSMutableDictionary *dict = [NSMutableDictionary dictionary]; dict[@"SSLPinningMode"] = [self getpinningModeString:self.SSLPinningMode]; dict[@"AllowInvalidCertificates"] = self.allowInvalidCertificates ? @"YES" : @"NO"; dict[@"ValidatesDomainName"] = self.validatesDomainName ? @"YES" : @"NO"; dict[@"CerFilePath"] = self.cerFilePath ?: @"未设置"; return dict; } - (NSString *)debugDescription { return self.description; } - (NSString *)getpinningModeString:(HLSSLPinningMode)mode { switch (mode) { case HLSSLPinningModeNone: return @"HLSSLPinningModeNone"; break; case HLSSLPinningModePublicKey: return @"HLSSLPinningModePublicKey"; case HLSSLPinningModeCertificate: return @"HLSSLPinningModeCertificate"; default: return @"HLSSLPinningModeNone"; break; } } - (id)copyWithZone:(NSZone *)zone { HLSecurityPolicyConfig *config = [[[self class] alloc] init]; if (config) { config.SSLPinningMode = _SSLPinningMode; config.allowInvalidCertificates = _allowInvalidCertificates; config.validatesDomainName = _validatesDomainName; config.cerFilePath = [_cerFilePath copyWithZone:zone]; } return config; } @end ================================================ FILE: HLNetworking/Source/Engine/HLNetworkEngine.h ================================================ // // HLNetworkEngine.h // HLNetworking // // Created by wangshiyu13 on 2017/1/22. // Copyright © 2017年 wangshiyu13. All rights reserved. // #import #import "HLNetworkConst.h" @class HLNetworkConfig; @class HLURLRequest; @interface HLNetworkEngine : NSObject // 请使用sharedEngine - (_Nonnull instancetype)init NS_UNAVAILABLE; + (_Nonnull instancetype)new NS_UNAVAILABLE; // 单例 + (_Nonnull instancetype)sharedEngine; // 发送请求 // requestObject为HLAPI或者HLTask对象 - (void)sendRequest:(__kindof HLURLRequest * _Nonnull)requestObject andConfig:(HLNetworkConfig * _Nonnull)config progressBack:(HLProgressBlock _Nullable)progressCallBack callBack:(HLCallbackBlock _Nullable)callBack; // 取消请求 - (void)cancelRequestByIdentifier:(NSString * _Nonnull)identifier; // 如果task不存在则返回NSNull对象 - (__kindof NSURLSessionTask * _Nullable)requestByIdentifier:(NSString * _Nonnull)identifier; #pragma mark - reachability相关 // 开始监听,domain为需要监听的域名 - (void)listeningWithDomain:(NSString * _Nonnull)domain listeningBlock:(HLReachabilityBlock _Nonnull)listener; // 停止监听,domain为需要停止的域名 - (void)stopListeningWithDomain:(NSString * _Nonnull)domain; @end ================================================ FILE: HLNetworking/Source/Engine/HLNetworkEngine.m ================================================ // // HLNetworkEngine.m // HLNetworking // // Created by wangshiyu13 on 2017/1/22. // Copyright © 2017年 wangshiyu13. All rights reserved. // #import #import #import "HLNetworkEngine.h" #import "HLNetworkMacro.h" #import "HLNetworkConst.h" #import "HLNetworkConfig.h" #import "HLURLRequest_InternalParams.h" #import "HLAPIRequest_InternalParams.h" #import "HLTaskRequest_InternalParams.h" @interface HLNetworkEngine (){ dispatch_semaphore_t _lock; } @property (nonatomic, strong) NSMutableDictionary *sessionManagerCache; @property (nonatomic, strong) NSMutableDictionary *sessionTasksCache; @property (nonatomic, strong) NSMutableDictionary *resumePathCache; @property (nonatomic, strong) NSMutableDictionary *reachabilities; @end @implementation HLNetworkEngine - (instancetype)init { self = [super init]; if (self) { _lock = dispatch_semaphore_create(1); _reachabilities = [NSMutableDictionary dictionary]; _sessionManagerCache = [NSMutableDictionary dictionary]; _sessionTasksCache = [NSMutableDictionary dictionary]; _resumePathCache = [NSMutableDictionary dictionary]; } return self; } + (HLNetworkEngine *)sharedEngine { static HLNetworkEngine *shared = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ shared = [[self alloc] init]; }); return shared; } #pragma mark - 获取AFHTTPSessionManager /** 根据请求对象获取AFSessionManager @param requestObject 请求对象 @param config 请求参数 @return AFURLSessionManager */ - (AFURLSessionManager *)sessionManagerByRequest:(__kindof HLURLRequest *)requestObject andManagerConfig:(HLNetworkConfig *)config { if (!requestObject) return nil; /** 拼接baseUrlStr */ NSString *baseUrlStr = [self createBaseURLString:requestObject andConfig:config]; /** 设置AFSecurityPolicy参数 */ AFSecurityPolicy *securityPolicy = [self createSecurityPolicy:requestObject andConfig:config]; /** 如果requestObject为HLTask */ if ([requestObject isKindOfClass:[HLTaskRequest class]]) { // AFURLSessionManager return [self createSessionManager:config andBaseURLString:baseUrlStr andSecurityPolicy:securityPolicy]; /** 如果requestObject为HLAPI */ } else if ([requestObject isKindOfClass:[HLAPIRequest class]]) { // AFHTTPSessionManager return [self createSessionManager:requestObject andConfig:config andBaseURLString:baseUrlStr andSecurityPolicy:securityPolicy]; } else { return nil; } } #pragma mark - 移除sessionTask - (void)removeTaskForKey:(NSString *)hashKey { HLLock(); if ([self.sessionTasksCache objectForKey:hashKey]) { [self.sessionTasksCache removeObjectForKey:hashKey]; } HLUnlock(); } # pragma mark - 发送请求 - (void)sendRequest:(__kindof HLURLRequest *)requestObject andConfig:(HLNetworkConfig *)config progressBack:(HLProgressBlock)progressCallBack callBack:(HLCallbackBlock)callBack { /** 容错 */ if (!requestObject) { [self faultTolerantProcessWithBlock:callBack andRequestObject:requestObject andErrorCode:NSURLErrorUnsupportedURL andErrorDescription:@"请求对象不存在!"]; return; } // 如果缓存中已有当前task,则立即使api返回失败回调,错误信息为frequentRequestErrorStr if ([self.sessionTasksCache objectForKey:[requestObject hashKey]]) { [self faultTolerantProcessWithBlock:callBack andRequestObject:requestObject andErrorCode:NSURLErrorCancelled andErrorDescription:config.tips.frequentRequestErrorStr]; return; } /** 必要参数 */ /** 生成sessionManager */ AFURLSessionManager *sessionManager = [self sessionManagerByRequest:requestObject andManagerConfig:config]; if (!sessionManager) { [self faultTolerantProcessWithBlock:callBack andRequestObject:requestObject andErrorCode:NSURLErrorUnsupportedURL andErrorDescription:@"SessionManager无法构建!"]; return; } /** 生成requestURLString */ NSString *requestURLString; NSString *host; // 如果定义了自定义的cURL, 则直接使用 NSURL *cURL = [NSURL URLWithString:[requestObject customURL]]; if (cURL) { host = [NSString stringWithFormat:@"%@://%@", cURL.scheme, cURL.host]; requestURLString = cURL.absoluteString; } else { NSString *tmpBaseURLStr = (NSString *)[requestObject baseURL] ?: config.request.baseURL; if ([tmpBaseURLStr hasSuffix:@"/"]) { tmpBaseURLStr = [tmpBaseURLStr substringWithRange:NSMakeRange(0, tmpBaseURLStr.length - 1)]; } NSURL *tmpBaseURL = [NSURL URLWithString:tmpBaseURLStr]; host = [NSString stringWithFormat:@"%@://%@", tmpBaseURL.scheme, tmpBaseURL.host]; // 使用BaseUrl + apiversion(可选) + path 组成 UrlString // 如果有apiVersion且类型不是HLTask时,则在requestUrlStr中插入该参数 if (IsEmptyValue(config.request.apiVersion) || [requestObject isKindOfClass:[HLTaskRequest class]]) { requestURLString = tmpBaseURL.absoluteString; } else { requestURLString = [NSString stringWithFormat:@"%@/%@", tmpBaseURL.absoluteString, config.request.apiVersion]; } if (!IsEmptyValue([requestObject path])) { requestURLString = [NSString stringWithFormat:@"%@/%@", requestURLString, [requestObject path]]; } } if (IsEmptyValue(requestURLString)) { [self faultTolerantProcessWithBlock:callBack andRequestObject:requestObject andErrorCode:NSURLErrorUnsupportedURL andErrorDescription:@"requestURLString无法构建!"]; return; } /** 网络状态不好使自动放弃该此请求 */ // 设置reachbility,监听url为baseURL SCNetworkReachabilityRef hostReachable = SCNetworkReachabilityCreateWithName(NULL, [host UTF8String]); SCNetworkReachabilityFlags flags; BOOL success = SCNetworkReachabilityGetFlags(hostReachable, &flags); BOOL isReachable = success && (flags & kSCNetworkFlagsReachable) && !(flags & kSCNetworkFlagsConnectionRequired); if (hostReachable) { CFRelease(hostReachable); } // 如果无网络,则立即使api响应失败回调,错误信息是networkNotReachableErrorStr if (!isReachable) { [self faultTolerantProcessWithBlock:callBack andRequestObject:requestObject andErrorCode:NSURLErrorCannotConnectToHost andErrorDescription:[NSString stringWithFormat:@"%@, %@ 无法访问", config.tips.networkNotReachableErrorStr, host]]; return; } // 进度Block void (^progressBlock)(NSProgress *progress) = ^(NSProgress *progress) { if (progress.totalUnitCount <= 0) return; dispatch_async_main(config.request.callbackQueue, ^{ if (progressCallBack) { progressCallBack(progress); } if (requestObject.progressHandler) { requestObject.progressHandler(progress); } }); }; /** 根据requestObject类型,发送请求 */ // requestObject为HLAPI时 if ([requestObject isKindOfClass:[HLAPIRequest class]]) { HLAPIRequest *api = requestObject; AFHTTPSessionManager *session = (AFHTTPSessionManager *)sessionManager; /** 生成请求参数 */ NSMutableDictionary *requestParams; requestParams = [NSMutableDictionary dictionaryWithDictionary:api.parameters]; if (config.request.defaultParams && api.useDefaultParams) { [requestParams addEntriesFromDictionary:config.request.defaultParams]; } /** 生成需要的Block */ // task成功Block @hl_weakify(self) void (^successBlock)(NSURLSessionDataTask *task, id responseObject) = ^(NSURLSessionDataTask * task, id resultObject) { // 移除dataTask缓存 @hl_strongify(self) if (callBack) { callBack(api, resultObject, nil); } [self removeTaskForKey:api.hashKey]; }; // task失败Block void (^failureBlock)(NSURLSessionDataTask * task, NSError * error) = ^(NSURLSessionDataTask * task, NSError * error) { // 移除dataTask缓存 @hl_strongify(self) if (callBack) { callBack(api, nil, error); } [self removeTaskForKey:api.hashKey]; }; // 执行AFN的请求 NSURLSessionDataTask *dataTask; switch (api.requestMethodType) { case GET: { dataTask = [session GET:requestURLString parameters:requestParams progress:progressBlock success:successBlock failure:failureBlock]; } break; case DELETE: { dataTask = [session DELETE:requestURLString parameters:requestParams success:successBlock failure:failureBlock]; } break; case PATCH: { dataTask = [session PATCH:requestURLString parameters:requestParams success:successBlock failure:failureBlock]; } break; case PUT: { dataTask = [session PUT:requestURLString parameters:requestParams success:successBlock failure:failureBlock]; } break; case HEAD: { dataTask = [session HEAD:requestURLString parameters:requestParams success:^(NSURLSessionDataTask * _Nonnull task) { if (successBlock) { dispatch_async_main(config.request.callbackQueue, ^{ successBlock(task, nil); }); } } failure:failureBlock]; } break; case POST: { if (![api requestConstructingBodyBlock]) { dataTask = [session POST:requestURLString parameters:requestParams progress:progressBlock success:successBlock failure:failureBlock]; } else { void (^formDataBlock)(id formData) = ^(id formData) { api.requestConstructingBodyBlock((id)formData); }; dataTask = [session POST:requestURLString parameters:requestParams constructingBodyWithBlock:formDataBlock progress:progressBlock success:successBlock failure:failureBlock]; } } break; default: { dataTask = [session GET:requestURLString parameters:requestParams progress:progressBlock success:successBlock failure:failureBlock]; } break; } // 缓存dataTask if (dataTask) { HLLock(); self.sessionTasksCache[api.hashKey] = dataTask; HLUnlock(); } // requestObject为HLTask时 } else if ([requestObject isKindOfClass:[HLTaskRequest class]]) { /** 准备请求参数 */ HLTaskRequest *task = requestObject; NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:requestURLString]]; NSURL *fileURL = task.filePath ? [NSURL fileURLWithPath:task.filePath] : nil; if (!fileURL) { return; } /** 生成需要的Block */ // 下载地址Block NSURL * (^destinationBlock)(NSURL *targetPath, NSURLResponse *response) = ^NSURL *(NSURL *targetPath, NSURLResponse *response) { NSString *path = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:response.suggestedFilename]; return fileURL ?: [NSURL fileURLWithPath:path]; }; @hl_weakify(self); // 上传完成的Block void (^uploadCompleteBlock)(NSURLResponse * _Nonnull response, id _Nullable responseObject, NSError * _Nullable error) = ^(NSURLResponse * _Nonnull response, id _Nullable responseObject, NSError * _Nullable error) { @hl_strongify(self); if (callBack) { callBack(task, responseObject, error); } [self removeTaskForKey:task.hashKey]; }; // 下载完成的Block void (^donwloadCompleteBlcok)(NSURLResponse * _Nonnull response, NSURL * _Nullable filePath, NSError * _Nullable error) = ^(NSURLResponse * _Nonnull response, NSURL * _Nullable filePath, NSError * _Nullable error) { @hl_strongify(self); if (callBack) { callBack(task, filePath, error); } [self removeTaskForKey:task.hashKey]; }; NSURLSessionTask *sessionTask; switch (task.requestTaskType) { case Upload: { [request setHTTPMethod:@"POST"]; sessionTask = [sessionManager uploadTaskWithRequest:request fromFile:fileURL progress:progressBlock completionHandler:uploadCompleteBlock]; } break; case Download: { NSData *data = [NSData dataWithContentsOfURL:[NSURL fileURLWithPath:task.resumePath]]; if (data) { sessionTask = [sessionManager downloadTaskWithResumeData:data progress:progressBlock destination:destinationBlock completionHandler:donwloadCompleteBlcok]; } else { sessionTask = [sessionManager downloadTaskWithRequest:request progress:progressBlock destination:destinationBlock completionHandler:donwloadCompleteBlcok]; } HLLock(); self.resumePathCache[@(sessionTask.hash)] = task.resumePath; HLUnlock(); } break; default: break; } // 缓存dataTask if (sessionTask) { [sessionTask resume]; HLLock(); self.sessionTasksCache[task.hashKey] = sessionTask; HLUnlock(); } } else { return; } } - (void)cancelRequestByIdentifier:(NSString *)identifier { NSURLSessionTask *sessionTask = [self.sessionTasksCache objectForKey:identifier]; if (sessionTask) { HLLock(); if ([sessionTask isKindOfClass:[NSURLSessionDownloadTask class]]) { NSURLSessionDownloadTask * downloadTask = (NSURLSessionDownloadTask *)sessionTask; [downloadTask cancelByProducingResumeData:^(NSData * _Nullable resumeData) { [resumeData writeToFile:self.resumePathCache[@(downloadTask.hash)] atomically:YES]; }]; } else { [sessionTask cancel]; [self.sessionTasksCache removeObjectForKey:identifier]; } HLUnlock(); } } - (__kindof NSURLSessionTask *)requestByIdentifier:(NSString *)identifier { return [self.sessionTasksCache objectForKey:identifier] ?: nil; } - (void)listeningWithDomain:(NSString *)domain listeningBlock:(HLReachabilityBlock)listener { AFNetworkReachabilityManager *manager = [self.reachabilities objectForKey:domain]; if (!manager) { manager = [AFNetworkReachabilityManager managerForDomain:domain]; self.reachabilities[domain] = manager; } [manager setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) { HLReachabilityStatus result = HLReachabilityStatusUnknown; switch (status) { case AFNetworkReachabilityStatusUnknown: result = HLReachabilityStatusUnknown; break; case AFNetworkReachabilityStatusNotReachable: result = HLReachabilityStatusNotReachable; break; case AFNetworkReachabilityStatusReachableViaWWAN: result = HLReachabilityStatusReachableViaWWAN; break; case AFNetworkReachabilityStatusReachableViaWiFi: result = HLReachabilityStatusReachableViaWiFi; break; default: result = HLReachabilityStatusUnknown; break; } if (listener) { listener(result); } }]; [manager startMonitoring]; } - (void)stopListeningWithDomain:(NSString *)domain { AFNetworkReachabilityManager *manager = [self.reachabilities objectForKey:domain]; if (manager) { [manager stopMonitoring]; if ([self.reachabilities objectForKey:domain]) { [self.reachabilities removeObjectForKey:domain]; } } } #pragma mark - private method // 创建BaseURLString - (NSString *)createBaseURLString:(HLURLRequest *)requestObject andConfig:(HLNetworkConfig *)config { NSString *baseUrlStr; // 如果定义了自定义的cURL, 则直接使用 NSURL *cURL = [NSURL URLWithString:requestObject.customURL]; if (cURL.host) { baseUrlStr = [NSString stringWithFormat:@"%@://%@", cURL.scheme ?: @"https", cURL.host]; } else { NSAssert(requestObject.baseURL != nil || config.request.baseURL != nil, @"api baseURL 和 self.config.baseurl 两者必须有一个有值"); NSString *tmpStr = requestObject.baseURL ?: config.request.baseURL; // 在某些情况下,一些用户会直接把整个url地址写进 baseUrl // 因此,还需要对baseUrl 进行一次切割 NSURL *tmpURL = [NSURL URLWithString:tmpStr]; baseUrlStr = [NSString stringWithFormat:@"%@://%@", tmpURL.scheme ?: @"https", tmpURL.host];; } return baseUrlStr; } // 创建AFSecurityPolicy - (AFSecurityPolicy *)createSecurityPolicy:(HLURLRequest *)requestObject andConfig:(HLNetworkConfig *)config { HLSecurityPolicyConfig *requestSecurityPolicy = requestObject.securityPolicy; NSUInteger pinningMode = requestSecurityPolicy.SSLPinningMode ?: config.defaultSecurityPolicy.SSLPinningMode; AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:pinningMode]; securityPolicy.allowInvalidCertificates = requestSecurityPolicy.allowInvalidCertificates ?: config.defaultSecurityPolicy.allowInvalidCertificates; securityPolicy.validatesDomainName = requestSecurityPolicy.validatesDomainName ?: config.defaultSecurityPolicy.validatesDomainName; NSString *cerPath = requestSecurityPolicy.cerFilePath ?: config.defaultSecurityPolicy.cerFilePath; NSData *certData = nil; if (cerPath && ![cerPath isEqualToString:@""]) { certData = [NSData dataWithContentsOfFile:cerPath]; if (certData) { securityPolicy.pinnedCertificates = [NSSet setWithObject:certData]; } } return securityPolicy; } - (AFURLSessionManager *)createSessionManager:(HLNetworkConfig *)config andBaseURLString:(NSString *)baseUrlStr andSecurityPolicy:(AFSecurityPolicy *)securityPolicy { AFURLSessionManager *sessionManager = [self.sessionManagerCache objectForKey:baseUrlStr]; // 如果缓存中取不到对应的sessionManager,则创建一个新的SessionManager if (!sessionManager) { NSURLSessionConfiguration *sessionConfig; if (config) { if (config.policy.isBackgroundSession) { NSString *kBackgroundSessionID = [NSString stringWithFormat:@"com.wangshiyu13.backgroundSession.task.%@", baseUrlStr]; NSString *kSharedContainerIdentifier = config.policy.AppGroup ?: [NSString stringWithFormat:@"com.wangshiyu13.testApp"]; sessionConfig = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:kBackgroundSessionID]; sessionConfig.sharedContainerIdentifier = kSharedContainerIdentifier; } else { sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration]; } sessionConfig.HTTPMaximumConnectionsPerHost = config.request.maxHttpConnectionPerHost; } else { sessionConfig.HTTPMaximumConnectionsPerHost = MAX_HTTP_CONNECTION_PER_HOST; } sessionManager = [[AFURLSessionManager alloc] initWithSessionConfiguration:sessionConfig]; [self.sessionManagerCache setObject:sessionManager forKey:baseUrlStr]; } sessionManager.securityPolicy = securityPolicy; return sessionManager; } // 创建Request序列化工具 - (AFHTTPRequestSerializer *)createRequestSerializer:(HLAPIRequest *)requestObject andConfig:(HLNetworkConfig *)config { AFHTTPRequestSerializer *requestSerializer; switch ([requestObject requestSerializerType]) { case RequestHTTP: requestSerializer = [AFHTTPRequestSerializer serializer]; break; case RequestJSON: requestSerializer = [AFJSONRequestSerializer serializer]; break; case RequestPlist: requestSerializer = [AFPropertyListRequestSerializer serializer]; break; default: requestSerializer = [AFHTTPRequestSerializer serializer]; break; } requestSerializer.cachePolicy = [requestObject cachePolicy]; requestSerializer.timeoutInterval = [requestObject timeoutInterval]; NSDictionary *requestHeaderFieldParams = [requestObject header]; if (![[requestHeaderFieldParams allKeys] containsObject:@"User-Agent"] && config.request.userAgent) { [requestSerializer setValue:config.request.userAgent forHTTPHeaderField:@"User-Agent"]; } if (requestHeaderFieldParams) { [requestHeaderFieldParams enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { [requestSerializer setValue:obj forHTTPHeaderField:key]; }]; } return requestSerializer; } // 创建Response序列化工具 - (AFHTTPResponseSerializer *)createResponseSerializer:(HLAPIRequest *)requestObject andConfig:(HLNetworkConfig *)config { AFHTTPResponseSerializer *responseSerializer; switch ([requestObject responseSerializerType]) { case ResponseHTTP: responseSerializer = [AFHTTPResponseSerializer serializer]; break; case ResponseJSON: responseSerializer = [AFJSONResponseSerializer serializer]; break; case ResponsePlist: responseSerializer = [AFPropertyListResponseSerializer serializer]; break; case ResponseXML: responseSerializer = [AFXMLParserResponseSerializer serializer]; break; default: responseSerializer = [AFHTTPResponseSerializer serializer]; break; } if (requestObject.accpetContentTypes) { NSMutableSet *tmpSet = [NSMutableSet setWithSet:requestObject.accpetContentTypes]; [tmpSet unionSet:responseSerializer.acceptableContentTypes]; responseSerializer.acceptableContentTypes = [tmpSet copy]; } return responseSerializer; } // 创建AFHTTPSessionManager - (AFHTTPSessionManager *)createSessionManager:(HLAPIRequest *)requestObject andConfig:(HLNetworkConfig *)config andBaseURLString:(NSString *)baseUrlStr andSecurityPolicy:(AFSecurityPolicy *)securityPolicy { AFHTTPSessionManager *sessionManager = [self.sessionManagerCache objectForKey:baseUrlStr]; if (!sessionManager) { // 根据传入的BaseURL创建新的SessionManager NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration]; sessionConfig.HTTPMaximumConnectionsPerHost = config.request.maxHttpConnectionPerHost; sessionConfig.requestCachePolicy = [requestObject cachePolicy] ?: config.policy.cachePolicy; sessionConfig.timeoutIntervalForRequest = [requestObject timeoutInterval] ?: config.request.requestTimeoutInterval; sessionConfig.URLCache = config.policy.URLCache; sessionManager = [[AFHTTPSessionManager alloc] initWithBaseURL:[NSURL URLWithString:baseUrlStr] sessionConfiguration:sessionConfig]; [self.sessionManagerCache setObject:sessionManager forKey:baseUrlStr]; } sessionManager.requestSerializer = [self createRequestSerializer:requestObject andConfig:config]; sessionManager.responseSerializer = [self createResponseSerializer:requestObject andConfig:config]; sessionManager.securityPolicy = securityPolicy; return sessionManager; } // 容错处理 - (void)faultTolerantProcessWithBlock:(HLCallbackBlock)callbackBlock andRequestObject:(__kindof HLURLRequest *)requestObject andErrorCode:(NSInteger)errorCode andErrorDescription:(NSString *)errorDescription { NSError *error = [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorUnsupportedURL userInfo:@{NSLocalizedDescriptionKey: errorDescription}]; if (callbackBlock) { callbackBlock(requestObject, nil, error); } } @end ================================================ FILE: HLNetworking/Source/Generator/Request/API/HLAPIRequest.h ================================================ // // HLAPIRequest.h // HLNetworking // // Created by wangshiyu13 on 2017/1/23. // Copyright © 2017年 wangshiyu13. All rights reserved. // #import "HLURLRequest.h" #import "HLFormDataConfig.h" @class HLAPIRequest; NS_ASSUME_NONNULL_BEGIN #pragma mark - 用于转换回调结果的代理 @protocol HLReformerDelegate @required /** 一般用来进行JSON -> Model 数据的转换工作。返回的id,如果没有error,则为转换成功后的Model数据。如果有error, 则直接返回传参中的responseObject @param request 调用的request @param responseObject 请求的返回 @param error 请求的错误 @return 整理过后的请求数据 */ - (nullable id)reformerObject:(id)responseObject andError:(NSError * _Nullable)error atRequest:(HLAPIRequest *)request; @end @interface HLAPIRequest : HLURLRequest #pragma mark - property @property (nonatomic, assign, readonly) BOOL useDefaultParams; @property (nonatomic, strong, readonly) Class objClz; @property (nonatomic, copy, readonly) NSDictionary *parameters; @property (nonatomic, copy, readonly) NSDictionary *header; @property (nonatomic, copy, readonly) NSSet *accpetContentTypes; #pragma mark - parameters append method /** 进行JSON -> Model 数据的转换工作的Delegate 如果设置了ReformerDelegate,则使用ReformerDelegate的obj解析,否则直接返回 提供该Delegate主要用于Reformer的不相关代码的解耦工作 param responseObject 请求回调对象 param error 错误信息 @return 请求结果数据 */ - (HLAPIRequest *(^)(id _Nullable delegate))setObjReformerDelegate; // HTTP 请求的返回可接受的内容类型,默认为nil,该参数会覆盖HLResponseSerializerType - (HLAPIRequest *(^)(NSSet * _Nullable contentTypes))setAccpetContentTypes; // 是否使用APIManager.config的默认参数,默认为YES - (HLAPIRequest *(^)(BOOL enable))enableDefaultParams; // 设置HLAPI对应的返回值模型类型 - (HLAPIRequest *(^)(NSString *clzName))setResponseClass; // 请求方法 GET POST等 - (HLAPIRequest *(^)(HLRequestMethodType requestMethodType))setMethod; // Request 序列化类型:JSON, HTTP, 见HLRequestSerializerType - (HLAPIRequest *(^)(HLRequestSerializerType requestSerializerType))setRequestType; // Response 序列化类型: JSON, HTTP - (HLAPIRequest *(^)(HLResponseSerializerType responseSerializerType))setResponseType; // 请求中的参数,每次设置都会覆盖之前的内容 - (HLAPIRequest *(^)(NSDictionary * _Nullable parameters))setParams; // 请求中的参数,每次设置都是添加新参数,不会覆盖之前的内容 - (HLAPIRequest *(^)(NSDictionary * _Nullable parameters))addParams; // HTTP 请求的头部区域自定义,默认为nil - (HLAPIRequest *(^)(NSDictionary * _Nullable header))setHeader; #pragma mark - process // 开启API 请求 - (HLAPIRequest *)start; // 取消API 请求 - (HLAPIRequest *)cancel; #pragma mark - handler block function /** 用于组织POST体的formData */ - (HLAPIRequest *(^)(HLRequestConstructingBodyBlock))formData; #pragma mark - 重写父类方法,用于转换类型 // 设置HLAPI的requestDelegate - (HLAPIRequest *(^)(id delegate))setDelegate; // 设置API的baseURL,该参数会覆盖config中的baseURL - (HLAPIRequest *(^)(NSString *baseURL))setBaseURL; // urlQuery,baseURL后的地址 - (HLAPIRequest *(^)(NSString * _Nullable path))setPath; // 自定义的RequestUrl,该参数会无视任何baseURL的设置,优先级最高 - (HLAPIRequest *(^)(NSString *customURL))setCustomURL; // HTTPS 请求的Security策略 - (HLAPIRequest *(^)(HLSecurityPolicyConfig *securityPolicy))setSecurityPolicy; // HTTP 请求的Cache策略 - (HLAPIRequest *(^)(NSURLRequestCachePolicy requestCachePolicy))setCachePolicy; // HTTP 请求超时的时间,默认为15秒 - (HLAPIRequest *(^)(NSTimeInterval requestTimeoutInterval))setTimeout; /** API完成后的成功回调 写法: .success(^(id obj) { dosomething }) */ - (HLAPIRequest *(^)(HLSuccessBlock))success; /** API完成后的失败回调 写法: .failure(^(NSError *error) { }) */ - (HLAPIRequest *(^)(HLFailureBlock))failure; /** API上传、下载等长时间执行的Progress进度 写法: .progress(^(NSProgress *proc){ NSLog(@"当前进度:%@", proc); }) */ - (HLAPIRequest *(^)(HLProgressBlock))progress; /** 用于Debug的Block block内返回HLDebugMessage对象 */ - (HLAPIRequest *(^)(HLDebugBlock))debug; @end NS_ASSUME_NONNULL_END ================================================ FILE: HLNetworking/Source/Generator/Request/API/HLAPIRequest.m ================================================ // // HLAPIRequest.m // HLNetworking // // Created by wangshiyu13 on 2017/1/23. // Copyright © 2017年 wangshiyu13. All rights reserved. // #import "HLURLRequest_InternalParams.h" #import "HLAPIRequest_InternalParams.h" #import "HLNetworkManager.h" #import "HLNetworkConfig.h" #import "HLSecurityPolicyConfig.h" #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wincomplete-implementation" @implementation HLAPIRequest #pragma mark - initialize method - (instancetype)init { self = [super init]; if (self) { _useDefaultParams = YES; _objClz = [NSObject class]; _accpetContentTypes = nil; _header = [HLNetworkManager config].request.defaultHeaders; _parameters = nil; _requestMethodType = GET; _requestSerializerType = RequestHTTP; _responseSerializerType = ResponseJSON; } return self; } - (id)copyWithZone:(NSZone *)zone { HLAPIRequest *request = [super copyWithZone:zone]; if (request) { request.useDefaultParams = _useDefaultParams; request.objClz = _objClz; request.accpetContentTypes = [_accpetContentTypes copyWithZone:zone]; request.header = [_header copyWithZone:zone]; request.parameters = [_parameters copyWithZone:zone]; request.requestMethodType = _requestMethodType; request.requestSerializerType = _requestSerializerType; request.responseSerializerType = _responseSerializerType; request.objReformerDelegate = _objReformerDelegate; } return request; } #pragma mark - parameters append method /** 进行JSON -> Model 数据的转换工作的Delegate 如果设置了ReformerDelegate,则使用ReformerDelegate的obj解析,否则直接返回 提供该Delegate主要用于Reformer的不相关代码的解耦工作 param responseObject 请求回调对象 param error 错误信息 @return 请求结果数据 */ - (HLAPIRequest *(^)(id delegate))setObjReformerDelegate { return ^HLAPIRequest* (id delegate) { self.objReformerDelegate = delegate; return self; }; } /** HTTP 请求的返回可接受的内容类型 默认为:[NSSet setWithObjects: @"text/json", @"text/html", @"application/json", @"text/javascript", nil]; */ - (HLAPIRequest *(^)(NSSet *contentTypes))setAccpetContentTypes { return ^HLAPIRequest* (NSSet *contentTypes) { self.accpetContentTypes = contentTypes; return self; }; } // 是否使用APIManager.config的默认参数 - (HLAPIRequest *(^)(BOOL enable))enableDefaultParams { return ^HLAPIRequest* (BOOL enable) { self.useDefaultParams = enable; return self; }; } // 设置HLAPI对应的返回值模型类型 - (HLAPIRequest *(^)(NSString *clzName))setResponseClass { return ^HLAPIRequest* (NSString *clzName) { Class clz = NSClassFromString(clzName); if (clz) { self.objClz = clz; } else { self.objClz = nil; } return self; }; } // 请求方法 GET POST等 - (HLAPIRequest *(^)(HLRequestMethodType requestMethodType))setMethod { return ^HLAPIRequest* (HLRequestMethodType requestMethodType) { self.requestMethodType = requestMethodType; return self; }; } // Request 序列化类型:JSON, HTTP, 见HLRequestSerializerType - (HLAPIRequest *(^)(HLRequestSerializerType requestSerializerType))setRequestType { return ^HLAPIRequest* (HLRequestSerializerType requestSerializerType) { self.requestSerializerType = requestSerializerType; return self; }; } // Response 序列化类型: JSON, HTTP - (HLAPIRequest *(^)(HLResponseSerializerType responseSerializerType))setResponseType { return ^HLAPIRequest* (HLResponseSerializerType responseSerializerType) { self.responseSerializerType = responseSerializerType; return self; }; } // 请求中的参数,每次设置都会覆盖之前的内容 - (HLAPIRequest *(^)(NSDictionary *parameters))setParams { return ^HLAPIRequest* (NSDictionary *parameters) { self.parameters = parameters; return self; }; } // 请求中的参数,每次设置都是添加新参数,不会覆盖之前的内容 - (HLAPIRequest *(^)(NSDictionary *parameters))addParams { return ^HLAPIRequest* (NSDictionary *parameters) { NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithDictionary:self.parameters]; [dict addEntriesFromDictionary:parameters]; self.parameters = [dict copy]; return self; }; } // HTTP 请求的头部区域自定义,默认为nil - (HLAPIRequest *(^)(NSDictionary *header))setHeader { return ^HLAPIRequest* (NSDictionary *header) { self.header = header; return self; }; } #pragma mark - handler block function - (HLAPIRequest *(^)(HLRequestConstructingBodyBlock))formData { return ^HLAPIRequest* (HLRequestConstructingBodyBlock bodyBlock) { self.requestConstructingBodyBlock = bodyBlock; return self; }; } #pragma mark - helper - (NSUInteger)hash { NSString *hashStr = nil; if (self.customURL) { hashStr = [NSString stringWithFormat:@"%@%@?%@?%lu", self.header, self.customURL, self.parameters, (unsigned long)self.requestMethodType]; } else { hashStr = [NSString stringWithFormat:@"%@%@/%@?%@?%lu", self.header, self.baseURL, self.path, self.parameters, (unsigned long)self.requestMethodType]; } return [hashStr hash]; } // 拼接打印信息 - (NSString *)description { NSMutableString *desc = [NSMutableString string]; #if DEBUG [desc appendString:@"\n===============HLAPI Start===============\n"]; [desc appendFormat:@"APIVersion: %@\n", [HLNetworkManager config].request.apiVersion ?: @"未设置"]; [desc appendFormat:@"Class: %@\n", self.objClz]; [desc appendFormat:@"BaseURL: %@\n", self.baseURL ?: [HLNetworkManager config].request.baseURL]; [desc appendFormat:@"Path: %@\n", self.path ?: @"未设置"]; [desc appendFormat:@"CustomURL: %@\n", self.customURL ?: @"未设置"]; [desc appendFormat:@"Parameters: %@\n", self.parameters ?: @"未设置"]; [desc appendFormat:@"Header: %@\n", self.header ?: @"未设置"]; [desc appendFormat:@"ContentTypes: %@\n", self.accpetContentTypes]; [desc appendFormat:@"TimeoutInterval: %f\n", self.timeoutInterval]; [desc appendFormat:@"SecurityPolicy: %@\n", self.securityPolicy]; [desc appendFormat:@"RequestMethodType: %@\n", [self getRequestMethodString:self.requestMethodType]]; [desc appendFormat:@"RequestSerializerType: %@\n", [self getRequestSerializerTypeString: self.requestSerializerType]]; [desc appendFormat:@"ResponseSerializerType: %@\n", [self getResponseSerializerTypeString: self.responseSerializerType]]; [desc appendFormat:@"CachePolicy: %@\n", [self getCachePolicy:self.cachePolicy]]; [desc appendString:@"=================HLAPI End================\n"]; #else desc = [NSMutableString stringWithFormat:@""]; #endif return desc; } - (NSString *)debugDescription { return self.description; } - (NSString *)getCachePolicy:(NSURLRequestCachePolicy)policy { switch (policy) { case NSURLRequestUseProtocolCachePolicy: return @"NSURLRequestUseProtocolCachePolicy"; break; case NSURLRequestReloadIgnoringLocalCacheData: return @"NSURLRequestReloadIgnoringLocalCacheData"; break; case NSURLRequestReloadIgnoringLocalAndRemoteCacheData: return @"NSURLRequestReloadIgnoringLocalAndRemoteCacheData"; break; case NSURLRequestReturnCacheDataElseLoad: return @"NSURLRequestReturnCacheDataElseLoad"; break; case NSURLRequestReturnCacheDataDontLoad: return @"NSURLRequestReturnCacheDataDontLoad"; break; case NSURLRequestReloadRevalidatingCacheData: return @"NSURLRequestReloadRevalidatingCacheData"; break; default: return @"NULL"; break; } } - (NSString *)getRequestMethodString:(HLRequestMethodType)method { switch (method) { case GET: return @"GET"; break; case POST: return @"POST"; break; case HEAD: return @"HEAD"; break; case PUT: return @"PUT"; break; case PATCH: return @"PATCH"; break; case DELETE: return @"PATCH"; break; default: return @"NULL"; break; } } - (NSString *)getRequestSerializerTypeString:(HLRequestSerializerType)type { switch (type) { case RequestJSON: return @"RequestJSON"; break; case RequestPlist: return @"RequestPlist"; break; case RequestHTTP: return @"RequestHTTP"; break; default: return @"NULL"; break; } } - (NSString *)getResponseSerializerTypeString:(HLResponseSerializerType)type { switch (type) { case ResponseXML: return @"ResponseXML"; break; case ResponsePlist: return @"ResponsePlist"; break; case ResponseHTTP: return @"ResponseHTTP"; break; case ResponseJSON: return @"ResponseJSON"; break; default: return @"NULL"; break; } } - (NSDictionary *)toDictionary { NSMutableDictionary *dict = [NSMutableDictionary dictionary]; dict[@"APIVersion"] = [HLNetworkManager config].request.apiVersion ?: @"未设置"; dict[@"Class"] = [NSString stringWithFormat:@"%@", self.objClz]; dict[@"BaseURL"] = self.baseURL ?: [HLNetworkManager config].request.baseURL; dict[@"Path"] = self.path ?: @"未设置"; dict[@"CustomURL"] = self.customURL ?: @"未设置"; dict[@"Parameters"] = self.parameters ?: @"未设置"; dict[@"Header"] = self.header ?: @"未设置"; dict[@"ContentTypes"] = [NSString stringWithFormat:@"%@", self.accpetContentTypes]; dict[@"TimeoutInterval"] = [NSString stringWithFormat:@"%f", self.timeoutInterval]; dict[@"SecurityPolicy"] = [self.securityPolicy toDictionary]; dict[@"RequestMethodType"] = [self getRequestMethodString:self.requestMethodType]; dict[@"RequestSerializerType"] = [self getRequestSerializerTypeString: self.requestSerializerType]; dict[@"ResponseSerializerType"] = [self getResponseSerializerTypeString: self.responseSerializerType]; dict[@"CachePolicy"] = [self getCachePolicy:self.cachePolicy]; return dict; } @end #pragma clang diagnostic pop ================================================ FILE: HLNetworking/Source/Generator/Request/API/HLAPIRequest_InternalParams.h ================================================ // // HLAPIRequest_InternalParams.h // HLNetworking // // Created by wangshiyu13 on 2017/1/23. // Copyright © 2017年 wangshiyu13. All rights reserved. // #import "HLAPIRequest.h" NS_ASSUME_NONNULL_BEGIN @interface HLAPIRequest () // readOnly property @property (nonatomic, strong, nullable) Class objClz; @property (nonatomic, assign) BOOL useDefaultParams; @property (nonatomic, weak, nullable) id objReformerDelegate; @property (nonatomic, assign) HLRequestMethodType requestMethodType; @property (nonatomic, assign) HLRequestSerializerType requestSerializerType; @property (nonatomic, assign) HLResponseSerializerType responseSerializerType; @property (nonatomic, copy, nullable) NSDictionary *parameters; @property (nonatomic, copy, nullable) NSDictionary *header; @property (nonatomic, copy) NSSet *accpetContentTypes; @property (nonatomic, copy, nullable) HLRequestConstructingBodyBlock requestConstructingBodyBlock; @end NS_ASSUME_NONNULL_END ================================================ FILE: HLNetworking/Source/Generator/Request/Base/HLURLRequest.h ================================================ // // HLURLRequest.h // HLNetworking // // Created by wangshiyu13 on 2017/1/23. // Copyright © 2017年 wangshiyu13. All rights reserved. // #import #import "HLNetworkConst.h" @class HLURLRequest; @class HLSecurityPolicyConfig; @protocol HLMultipartFormDataProtocol; @protocol HLURLRequestDelegate; NS_ASSUME_NONNULL_BEGIN #pragma mark - HLAPIRequestDelegate @protocol HLURLRequestDelegate @optional // 请求将要发出 - (void)requestWillBeSent:(nullable __kindof HLURLRequest *)request; // 请求已经发出 - (void)requestDidSent:(nullable __kindof HLURLRequest *)request; @end @interface HLURLRequest : NSObject #pragma mark - property @property (nonatomic, assign, readonly) NSTimeInterval timeoutInterval; @property (nonatomic, copy, readonly) NSString *baseURL; @property (nonatomic, copy, readonly) NSString *path; @property (nonatomic, copy, nullable, getter=customURL, readonly) NSString *cURL; #pragma mark - initialize method // 请使用API + (instancetype)request; - (instancetype)init NS_UNAVAILABLE; + (instancetype)new NS_UNAVAILABLE; #pragma mark - parameters append method // 设置HLAPI的requestDelegate - (__kindof HLURLRequest *(^)(id _Nullable delegate))setDelegate; // 设置API的baseURL,该参数会覆盖config中的baseURL - (__kindof HLURLRequest *(^)(NSString *baseURL))setBaseURL; // urlQuery,baseURL后的地址 - (__kindof HLURLRequest *(^)(NSString * _Nullable path))setPath; // 自定义的RequestUrl,该参数会无视任何baseURL的设置,优先级最高 - (__kindof HLURLRequest *(^)(NSString *customURL))setCustomURL; // HTTPS 请求的Security策略 - (__kindof HLURLRequest *(^)(HLSecurityPolicyConfig *securityPolicy))setSecurityPolicy; // HTTP 请求的Cache策略 - (__kindof HLURLRequest *(^)(NSURLRequestCachePolicy requestCachePolicy))setCachePolicy; // HTTP 请求超时的时间,默认为15秒 - (__kindof HLURLRequest *(^)(NSTimeInterval requestTimeoutInterval))setTimeout; #pragma mark - process // 开启API 请求 - (__kindof HLURLRequest *)start; // 取消API 请求 - (__kindof HLURLRequest *)cancel; // 继续Task - (__kindof HLURLRequest *)resume; // 暂停Task - (__kindof HLURLRequest *)pause; #pragma mark - helper - (NSDictionary *)toDictionary; - (NSString *)hashKey; @end #pragma mark - handler block function @interface HLURLRequest (Handler) /** API完成后的成功回调 写法: .success(^(id obj) { dosomething }) */ - (__kindof HLURLRequest *(^)(HLSuccessBlock))success; /** API完成后的失败回调 写法: .failure(^(NSError *error) { }) */ - (__kindof HLURLRequest *(^)(HLFailureBlock))failure; /** API上传、下载等长时间执行的Progress进度 写法: .progress(^(NSProgress *proc){ NSLog(@"当前进度:%@", proc); }) */ - (__kindof HLURLRequest *(^)(HLProgressBlock))progress; /** 用于Debug的Block block内返回HLDebugMessage对象 */ - (__kindof HLURLRequest *(^)(HLDebugBlock))debug; @end NS_ASSUME_NONNULL_END ================================================ FILE: HLNetworking/Source/Generator/Request/Base/HLURLRequest.m ================================================ // // HLURLRequest.m // HLNetworking // // Created by wangshiyu13 on 2017/1/23. // Copyright © 2017年 wangshiyu13. All rights reserved. // #import "HLURLRequest.h" #import "HLURLRequest_InternalParams.h" #import "HLNetworkConfig.h" #import "HLNetworkMacro.h" #import "HLNetworkManager.h" #import "HLSecurityPolicyConfig.h" @implementation HLURLRequest #pragma mark - initialize method - (instancetype)init { self = [super init]; if (self) { _cURL = nil; _path = nil; _baseURL = [HLNetworkManager config].request.baseURL; _timeoutInterval = HL_API_REQUEST_TIME_OUT; _retryCount = [HLNetworkManager config].request.retryCount; _cachePolicy = NSURLRequestUseProtocolCachePolicy; _securityPolicy = [HLNetworkManager config].defaultSecurityPolicy; } return self; } + (instancetype)request { return [[self alloc] init]; } - (id)copyWithZone:(NSZone *)zone { HLURLRequest *request = [[[self class] alloc] init]; if (request) { request.cURL = [_cURL copyWithZone:zone]; request.path = [_path copyWithZone:zone]; request.baseURL = [_baseURL copyWithZone:zone]; request.timeoutInterval = _timeoutInterval; request.retryCount = _retryCount; request.securityPolicy = [_securityPolicy copyWithZone:zone]; request.cachePolicy = _cachePolicy; request.delegate = _delegate; } return request; } #pragma mark - parameters append method // 设置HLAPI的requestDelegate - (__kindof HLURLRequest *(^)(id delegate))setDelegate { return ^HLURLRequest* (id delegate) { self.delegate = delegate; return self; }; } // 设置API的baseURL,该参数会覆盖config中的baseURL - (__kindof HLURLRequest *(^)(NSString *baseURL))setBaseURL { return ^HLURLRequest* (NSString *baseURL) { self.baseURL = baseURL; return self; }; } // urlQuery,baseURL后的地址 - (__kindof HLURLRequest *(^)(NSString *path))setPath { return ^HLURLRequest* (NSString *path) { self.path = path; return self; }; } // 自定义的RequestUrl,该参数会无视任何baseURL的设置,优先级最高 - (__kindof HLURLRequest *(^)(NSString *customURL))setCustomURL { return ^HLURLRequest* (NSString *customURL) { self.cURL = customURL; NSURL *tmpURL = [NSURL URLWithString:customURL]; if (tmpURL.host) { self.baseURL = [NSString stringWithFormat:@"%@://%@", tmpURL.scheme ?: @"https", tmpURL.host]; self.path = [NSString stringWithFormat:@"%@", tmpURL.query]; } return self; }; } // HTTPS 请求的Security策略 - (__kindof HLURLRequest *(^)(HLSecurityPolicyConfig *securityPolicy))setSecurityPolicy { return ^HLURLRequest* (HLSecurityPolicyConfig *securityPolicy) { self.securityPolicy = securityPolicy; return self; }; } // HTTP 请求的Cache策略 - (__kindof HLURLRequest *(^)(NSURLRequestCachePolicy requestCachePolicy))setCachePolicy { return ^HLURLRequest* (NSURLRequestCachePolicy requestCachePolicy) { self.cachePolicy = requestCachePolicy; return self; }; } // HTTP 请求超时的时间,默认为15秒 - (__kindof HLURLRequest *(^)(NSTimeInterval requestTimeoutInterval))setTimeout { return ^HLURLRequest* (NSTimeInterval requestTimeoutInterval) { self.timeoutInterval = requestTimeoutInterval; return self; }; } #pragma mark - handler block function /** API完成后的成功回调 写法: .success(^(id obj) { dosomething }) */ - (__kindof HLURLRequest *(^)(HLSuccessBlock))success { return ^HLURLRequest* (HLSuccessBlock objBlock) { self.successHandler = objBlock; return self; }; } /** API完成后的失败回调 写法: .failure(^(NSError *error) { }) */ - (__kindof HLURLRequest *(^)(HLFailureBlock))failure { return ^HLURLRequest* (HLFailureBlock errorBlock) { self.failureHandler = errorBlock; return self; }; } /** API上传、下载等长时间执行的Progress进度 写法: .progress(^(NSProgress *proc){ NSLog(@"当前进度:%@", proc); }) */ - (__kindof HLURLRequest *(^)(HLProgressBlock))progress { return ^HLURLRequest* (HLProgressBlock progressBlock) { self.progressHandler = progressBlock; return self; }; } /** 用于Debug的Block block内返回HLDebugMessage对象 */ - (__kindof HLURLRequest *(^)(HLDebugBlock))debug { return ^HLURLRequest* (HLDebugBlock debugBlock) { self.debugHandler = debugBlock; return self; }; } #pragma mark - process // 开启API 请求 - (__kindof HLURLRequest *)start { [HLNetworkManager send:self]; return self; } // 取消API 请求 - (__kindof HLURLRequest *)cancel { [HLNetworkManager cancel:self]; return self; } // 继续Task - (__kindof HLURLRequest *)resume { [HLNetworkManager resume:self]; return self; } // 暂停Task - (__kindof HLURLRequest *)pause { [HLNetworkManager pause:self]; return self; } #pragma mark - helper - (NSDictionary *)toDictionary { NSMutableDictionary *dict = [NSMutableDictionary dictionary]; dict[@"APIVersion"] = [HLNetworkManager config].request.apiVersion ?: @"未设置"; dict[@"BaseURL"] = self.baseURL ?: [HLNetworkManager config].request.baseURL; dict[@"Path"] = self.path ?: @"未设置"; dict[@"CustomURL"] = self.customURL ?: @"未设置"; dict[@"TimeoutInterval"] = [NSString stringWithFormat:@"%f", self.timeoutInterval]; dict[@"SecurityPolicy"] = [self.securityPolicy toDictionary]; dict[@"CachePolicy"] = [self getCachePolicy:self.cachePolicy]; return dict; } - (NSString *)hashKey { return [NSString stringWithFormat:@"%lu", (unsigned long)[self hash]]; } - (NSUInteger)hash { NSString *hashStr = nil; if (self.customURL) { hashStr = [NSString stringWithFormat:@"%@", self.customURL]; } else { hashStr = [NSString stringWithFormat:@"%@/%@", self.baseURL, self.path]; } return [hashStr hash]; } - (BOOL)isEqualToRequest:(HLURLRequest *)request { return [self hash] == [request hash]; } - (BOOL)isEqual:(id)object { if (self == object) return YES; if (![object isKindOfClass:[HLURLRequest class]]) return NO; return [self isEqualToRequest:(HLURLRequest *) object]; } - (NSString *)getCachePolicy:(NSURLRequestCachePolicy)policy { switch (policy) { case NSURLRequestUseProtocolCachePolicy: return @"NSURLRequestUseProtocolCachePolicy"; break; case NSURLRequestReloadIgnoringLocalCacheData: return @"NSURLRequestReloadIgnoringLocalCacheData"; break; case NSURLRequestReloadIgnoringLocalAndRemoteCacheData: return @"NSURLRequestReloadIgnoringLocalAndRemoteCacheData"; break; case NSURLRequestReturnCacheDataElseLoad: return @"NSURLRequestReturnCacheDataElseLoad"; break; case NSURLRequestReturnCacheDataDontLoad: return @"NSURLRequestReturnCacheDataDontLoad"; break; case NSURLRequestReloadRevalidatingCacheData: return @"NSURLRequestReloadRevalidatingCacheData"; break; default: return @"NULL"; break; } } @end ================================================ FILE: HLNetworking/Source/Generator/Request/Base/HLURLRequest_InternalParams.h ================================================ // // HLURLRequest_InternalParams.h // HLNetworking // // Created by wangshiyu13 on 2017/1/23. // Copyright © 2017年 wangshiyu13. All rights reserved. // #import "HLURLRequest.h" NS_ASSUME_NONNULL_BEGIN @interface HLURLRequest () @property (nonatomic, weak, nullable) id delegate; @property (nonatomic, copy) NSString *cURL; @property (nonatomic, copy) NSString *baseURL; @property (nonatomic, copy) NSString *path; @property (nonatomic, assign)NSTimeInterval timeoutInterval; @property (nonatomic, assign)NSURLRequestCachePolicy cachePolicy; @property (nonatomic, strong)HLSecurityPolicyConfig *securityPolicy; @property (nonatomic, copy, nullable) HLSuccessBlock successHandler; @property (nonatomic, copy, nullable) HLFailureBlock failureHandler; @property (nonatomic, copy, nullable) HLProgressBlock progressHandler; @property (nonatomic, copy, nullable) HLDebugBlock debugHandler; @property (nonatomic, assign) NSUInteger retryCount; @property (nonatomic, strong, nullable) dispatch_queue_t queue; @end NS_ASSUME_NONNULL_END ================================================ FILE: HLNetworking/Source/Generator/Request/Group/HLRequestGroup.h ================================================ // // HLRequestGroup.h // HLNetworking // // Created by wangshiyu13 on 2017/1/23. // Copyright © 2017年 wangshiyu13. All rights reserved. // #import @class HLURLRequest; @class HLRequestGroup; typedef NS_ENUM(NSUInteger, HLRequestGroupMode) { HLRequestGroupModeBatch, HLRequestGroupModeChain }; NS_ASSUME_NONNULL_BEGIN @protocol HLRequestGroupDelegate // Requests 全部调用完成之后调用 - (void)requestGroupAllDidFinished:(nonnull HLRequestGroup *)apiGroup; @end @interface HLRequestGroup : NSObject // 请求组类型 @property (nonatomic, assign, readonly) HLRequestGroupMode groupMode; @property (nonatomic, assign) NSUInteger maxRequestCount; // 自定义的同步请求所在的串行队列 @property (nonatomic, strong, readonly) dispatch_queue_t customQueue; // Group 内 api 执行完成之后调用的delegate @property (nonatomic, weak, nullable) id delegate; // 请使用manager或sharedManager - (instancetype)init NS_UNAVAILABLE; + (instancetype)new NS_UNAVAILABLE; // 返回一个新的manager对象 + (instancetype)groupWithMode:(HLRequestGroupMode)mode; // 加入到group集合中 - (void)add:(nonnull __kindof HLURLRequest *)request; // 将带有API集合的Array 赋值 - (void)addRequests:(nonnull NSArray<__kindof HLURLRequest *> *)requests; // 开启队列请求 - (void)start; // 取消所有请求 - (void)cancel; // 设置组GCD队列 - (dispatch_queue_t)setupGroupQueue:(NSString *)queueName; #pragma mark - 遍历方法 @property (readonly) NSUInteger count; - (void)enumerateObjectsUsingBlock:(void (^)(__kindof HLURLRequest *request, NSUInteger idx, BOOL * stop))block; - (nonnull NSEnumerator*)objectEnumerator; - (nonnull id)objectAtIndexedSubscript:(NSUInteger)idx; @end NS_ASSUME_NONNULL_END ================================================ FILE: HLNetworking/Source/Generator/Request/Group/HLRequestGroup.m ================================================ // // HLRequestGroup.m // HLNetworking // // Created by wangshiyu13 on 2017/1/23. // Copyright © 2017年 wangshiyu13. All rights reserved. // #import "HLRequestGroup.h" #import "HLURLRequest.h" #import "HLNetworkManager.h" #define mix(A, B) A##B // 创建任务队列 static dispatch_queue_t qkhl_api_chain_queue(const char * queueName) { static dispatch_queue_t mix(qkhl_api_chain_queue_, queueName); static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ mix(qkhl_api_chain_queue_, queueName) = dispatch_queue_create(queueName, DISPATCH_QUEUE_SERIAL); }); return mix(qkhl_api_chain_queue_, queueName); } @interface HLRequestGroup () @property (nonatomic, strong, readwrite) NSMutableArray <__kindof HLURLRequest *>*apiArray; // 自定义的同步请求所在的串行队列 @property (nonatomic, strong, readwrite) dispatch_queue_t customQueue; @end @implementation HLRequestGroup #pragma mark - initialize method - (instancetype)initWithMode:(HLRequestGroupMode)mode { self = [super init]; if (self) { _apiArray = [NSMutableArray array]; _groupMode = mode; _maxRequestCount = 1; } return self; } + (instancetype)groupWithMode:(HLRequestGroupMode)mode { return [[self alloc] initWithMode:mode]; } #pragma mark - NSFastEnumeration - (NSUInteger)count { return _apiArray.count; } - (nonnull id)objectAtIndexedSubscript:(NSUInteger)idx { if (idx >= _apiArray.count) { [NSException raise:NSRangeException format:@"Index %lu 的区间为 [0, %lu].", (unsigned long)idx, (unsigned long)_apiArray.count]; } return _apiArray[idx]; } - (void)enumerateObjectsUsingBlock:(void (^)(__kindof HLURLRequest *request, NSUInteger idx, BOOL *stop))block { [_apiArray enumerateObjectsUsingBlock:block]; } - (NSEnumerator*)objectEnumerator { return [_apiArray objectEnumerator]; } - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id _Nullable __unsafe_unretained [])buffer count:(NSUInteger)len { return [_apiArray countByEnumeratingWithState:state objects:buffer count:len]; } #pragma mark - Add Requests - (void)add:(__kindof HLURLRequest *)request { if (!request) { return; } if ([self.apiArray containsObject:request]) { #ifdef DEBUG NSLog(@"批处理队列中已有相同的API!"); #endif } [self.apiArray addObject:request]; } - (void)addRequests:(nonnull NSArray<__kindof HLURLRequest *> *)requests { if (!requests) return; if (requests.count == 0) return; [requests enumerateObjectsUsingBlock:^(HLURLRequest * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { [self add:obj]; }]; } - (void)start { if (self.apiArray.count == 0) return; [HLNetworkManager sendGroup:self]; } - (void)cancel { if (self.apiArray.count == 0) return; [HLNetworkManager cancelGroup:self]; } - (dispatch_queue_t)setupGroupQueue:(NSString *)queueName { self.customQueue = qkhl_api_chain_queue([queueName UTF8String]); return self.customQueue; } @end ================================================ FILE: HLNetworking/Source/Generator/Request/Task/HLTaskRequest.h ================================================ // // HLTaskRequest.h // HLNetworking // // Created by wangshiyu13 on 2017/1/23. // Copyright © 2017年 wangshiyu13. All rights reserved. // #import "HLURLRequest.h" NS_ASSUME_NONNULL_BEGIN @interface HLTaskRequest : HLURLRequest #pragma mark - property @property (nonatomic, copy, readonly) NSString *filePath; @property (nonatomic, copy, readonly) NSString *resumePath; #pragma mark - parameters append method // 设置下载或者上传的本地文件路径 - (HLTaskRequest *(^)(NSString *filePath))setFilePath; // 设置task的类型(上传/下载) - (HLTaskRequest *(^)(HLRequestTaskType requestTaskType))setTaskType; #pragma mark - process // 开启API 请求 - (HLTaskRequest *)start; // 取消API 请求 - (HLTaskRequest *)cancel; // 继续Task - (HLTaskRequest *)resume; // 暂停Task - (HLTaskRequest *)pause; #pragma mark - 重写父类方法,用于转换类型 // 设置HLAPI的requestDelegate - (HLTaskRequest *(^)(id delegate))setDelegate; // 设置API的baseURL,该参数会覆盖config中的baseURL - (HLTaskRequest *(^)(NSString *baseURL))setBaseURL; // urlQuery,baseURL后的地址 - (HLTaskRequest *(^)(NSString *path))setPath; // 自定义的RequestUrl,该参数会无视任何baseURL的设置,优先级最高 - (HLTaskRequest *(^)(NSString *customURL))setCustomURL; // HTTPS 请求的Security策略 - (HLTaskRequest *(^)(HLSecurityPolicyConfig *securityPolicy))setSecurityPolicy; // HTTP 请求的Cache策略 - (HLTaskRequest *(^)(NSURLRequestCachePolicy requestCachePolicy))setCachePolicy; // HTTP 请求超时的时间,默认为15秒 - (HLTaskRequest *(^)(NSTimeInterval requestTimeoutInterval))setTimeout; /** API完成后的成功回调 写法: .success(^(id obj) { dosomething }) */ - (HLTaskRequest *(^)(HLSuccessBlock))success; /** API完成后的失败回调 写法: .failure(^(NSError *error) { }) */ - (HLTaskRequest *(^)(HLFailureBlock))failure; /** API上传、下载等长时间执行的Progress进度 写法: .progress(^(NSProgress *proc){ NSLog(@"当前进度:%@", proc); }) */ - (HLTaskRequest *(^)(HLProgressBlock))progress; /** 用于Debug的Block block内返回HLDebugMessage对象 */ - (HLTaskRequest *(^)(HLDebugBlock))debug; @end NS_ASSUME_NONNULL_END ================================================ FILE: HLNetworking/Source/Generator/Request/Task/HLTaskRequest.m ================================================ // // HLTaskRequest.m // HLNetworking // // Created by wangshiyu13 on 2017/1/23. // Copyright © 2017年 wangshiyu13. All rights reserved. // #import "HLTaskRequest_InternalParams.h" #import "HLURLRequest_InternalParams.h" #import "HLNetworkManager.h" #import "HLNetworkConfig.h" #import "HLSecurityPolicyConfig.h" #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wincomplete-implementation" @implementation HLTaskRequest #pragma mark - initialize method - (instancetype)init { self = [super init]; if (self) { _requestTaskType = Download; NSString *baseResumePath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"com.qkhl.HLNetworking/downloadDict"]; if (![[NSFileManager defaultManager] fileExistsAtPath:baseResumePath isDirectory:nil]) { [[NSFileManager defaultManager] createDirectoryAtPath:baseResumePath withIntermediateDirectories:YES attributes:nil error:nil]; } _resumePath = [baseResumePath stringByAppendingPathComponent:[NSString stringWithFormat:@"%lu.arc", (unsigned long)self.hash]]; } return self; } - (id)copyWithZone:(NSZone *)zone { HLTaskRequest *request = [super copyWithZone:zone]; if (request) { request.filePath = [_filePath copyWithZone:zone]; request.resumePath = [_resumePath copyWithZone:zone]; request.requestTaskType = _requestTaskType; } return request; } #pragma mark - parameters append method // 设置下载或者上传的本地文件路径 - (HLTaskRequest *(^)(NSString *filePath))setFilePath { return ^HLTaskRequest* (NSString *filePath) { self.filePath = filePath; return self; }; } // 设置task的类型(上传/下载) - (HLTaskRequest *(^)(HLRequestTaskType requestTaskType))setTaskType { return ^HLTaskRequest* (HLRequestTaskType requestTaskType) { self.requestTaskType = requestTaskType; return self; }; } #pragma mark - helper - (NSUInteger)hash { NSString *hashStr; if (self.customURL) { hashStr = self.customURL; } else { hashStr = [NSString stringWithFormat:@"%@/%@", self.baseURL, self.path]; } return [hashStr hash]; } - (NSString *)description { NSMutableString *desc = [NSMutableString string]; #if DEBUG [desc appendString:@"\n===============HLTask Start===============\n"]; [desc appendFormat:@"Class: %@\n", self.class]; [desc appendFormat:@"BaseURL: %@\n", self.baseURL ?: [HLNetworkManager config].request.baseURL]; [desc appendFormat:@"Path: %@\n", self.path ?: @"未设置"]; [desc appendFormat:@"CustomURL: %@\n", self.customURL ?: @"未设置"]; [desc appendFormat:@"ResumePath: %@", self.resumePath]; [desc appendFormat:@"CachePath: %@", self.filePath]; [desc appendFormat:@"TimeoutInterval: %f\n", self.timeoutInterval]; [desc appendFormat:@"SecurityPolicy: %@\n", self.securityPolicy]; [desc appendFormat:@"RequestTaskType: %@\n", [self getRequestTaskTypeString:self.requestTaskType]]; [desc appendFormat:@"CachePolicy: %@\n", [self getCachePolicyString:self.cachePolicy]]; [desc appendString:@"===============End===============\n"]; #else desc = [NSMutableString stringWithFormat:@""]; #endif return desc; } - (NSString *)getRequestTaskTypeString:(HLRequestTaskType)type { switch (type) { case Download: return @"Download"; break; case Upload: return @"Upload"; break; default: return @"Download"; break; } } - (NSString *)getCachePolicyString:(NSURLRequestCachePolicy)policy { switch (policy) { case NSURLRequestUseProtocolCachePolicy: return @"NSURLRequestUseProtocolCachePolicy"; break; case NSURLRequestReloadIgnoringLocalCacheData: return @"NSURLRequestReloadIgnoringLocalCacheData"; break; case NSURLRequestReloadIgnoringLocalAndRemoteCacheData: return @"NSURLRequestReloadIgnoringLocalAndRemoteCacheData"; break; case NSURLRequestReturnCacheDataElseLoad: return @"NSURLRequestReturnCacheDataElseLoad"; break; case NSURLRequestReturnCacheDataDontLoad: return @"NSURLRequestReturnCacheDataDontLoad"; break; case NSURLRequestReloadRevalidatingCacheData: return @"NSURLRequestReloadRevalidatingCacheData"; break; default: return @"NSURLRequestUseProtocolCachePolicy"; break; } } - (NSDictionary *)toDictionary { NSMutableDictionary *dict = [NSMutableDictionary dictionary]; dict[@"APIVersion"] = [HLNetworkManager config].request.apiVersion ?: @"未设置"; dict[@"BaseURL"] = self.baseURL ?: [HLNetworkManager config].request.baseURL; dict[@"Path"] = self.path ?: @"未设置"; dict[@"CustomURL"] = self.customURL ?: @"未设置"; dict[@"ResumePath"] = self.resumePath ?: @"未设置"; dict[@"TimeoutInterval"] = [NSString stringWithFormat:@"%f", self.timeoutInterval]; dict[@"SecurityPolicy"] = [self.securityPolicy toDictionary]; dict[@"RequestMethodType"] = [self getRequestTaskTypeString:self.requestTaskType]; dict[@"CachePolicy"] = [self getCachePolicyString:self.cachePolicy]; return dict; } @end #pragma clang diagnostic pop ================================================ FILE: HLNetworking/Source/Generator/Request/Task/HLTaskRequest_InternalParams.h ================================================ // // HLTaskRequest_InternalParams.h // HLNetworking // // Created by wangshiyu13 on 2017/1/23. // Copyright © 2017年 wangshiyu13. All rights reserved. // #import "HLTaskRequest.h" @interface HLTaskRequest () @property (nonatomic, copy) NSString *filePath; @property (nonatomic, copy) NSString *resumePath; @property (nonatomic, assign)HLRequestTaskType requestTaskType; @end ================================================ FILE: HLNetworking/Source/Generator/Response/HLURLResponse.h ================================================ // // HLURLResponse.h // HLNetworking // // Created by wangshiyu13 on 2017/1/4. // Copyright © 2017年 wangshiyu13. All rights reserved. // #import #import "HLURLResult.h" @interface HLURLResponse : NSObject @property (nonatomic, strong, readonly) HLURLResult *result; @property (nonatomic, assign, readonly) NSUInteger requestId; @property (nonatomic, copy, readonly) NSURLRequest *request; - (NSDictionary *)toDictionary; - (instancetype)initWithResult:(HLURLResult *)result requestId:(NSNumber *)requestId request:(NSURLRequest *)request; @end ================================================ FILE: HLNetworking/Source/Generator/Response/HLURLResponse.m ================================================ // // HLURLResponse.m // HLNetworking // // Created by wangshiyu13 on 2017/1/4. // Copyright © 2017年 wangshiyu13. All rights reserved. // #import "HLURLResponse.h" @interface HLURLResponse () @property (nonatomic, strong, readwrite) HLURLResult *result; @property (nonatomic, copy, readwrite) NSURLRequest *request; @property (nonatomic, assign, readwrite) NSUInteger requestId; @end @implementation HLURLResponse #pragma mark - life cycle - (instancetype)initWithResult:(HLURLResult *)result requestId:(NSNumber *)requestId request:(NSURLRequest *)request { self = [super init]; if (self) { _result = result; _requestId = [requestId integerValue]; _request = request; } return self; } #pragma mark - private methods - (NSString *)description { NSMutableString *desc = [NSMutableString string]; [desc appendString:@"\n++++++++HLURLResponse Start++++++++\n"]; [desc appendFormat:@"Result : %@\n", self.result]; [desc appendFormat:@"Request : %@\n", self.request]; [desc appendFormat:@"RequestId : %lu\n", (unsigned long)self.requestId]; [desc appendString:@"+++++++++HLURLResponse End+++++++++\n"]; return desc; } - (NSDictionary *)toDictionary { NSMutableDictionary *dict = [NSMutableDictionary dictionary]; dict[@"Result"] = [self.result toDictionary]; dict[@"Request"] = self.request.description; dict[@"RequestId"] = [NSString stringWithFormat:@"%lu", (unsigned long)self.requestId]; return dict; } - (NSString *)debugDescription { return self.description; } @end ================================================ FILE: HLNetworking/Source/Generator/Result/HLURLResult.h ================================================ // // HLURLResult.h // HLNetworking // // Created by wangshiyu13 on 2017/1/4. // Copyright © 2017年 wangshiyu13. All rights reserved. // #import typedef NS_ENUM(NSUInteger, HLURLResultStatus) { HLURLResultStatusSuccess, //作为底层,请求是否成功只考虑是否成功收到服务器反馈。至于签名是否正确,返回的数据是否完整,由上层的CTAPIBaseManager来决定。 HLURLResultStatusErrorTimeout, HLURLResultStatusErrorNotReachable // 默认除了超时以外的错误都是无网络错误。 }; @interface HLURLResult : NSObject @property (nonatomic, strong, readonly) id resultObject; @property (nonatomic, strong, readonly) NSError *error; @property (nonatomic, assign, readonly) HLURLResultStatus status; - (NSDictionary *)toDictionary; - (instancetype)initWithObject:(id)resultObject andError:(NSError *)error; @end ================================================ FILE: HLNetworking/Source/Generator/Result/HLURLResult.m ================================================ // // HLURLResult.m // HLNetworking // // Created by wangshiyu13 on 2017/1/4. // Copyright © 2017年 wangshiyu13. All rights reserved. // #import "HLURLResult.h" @interface HLURLResult () @property (nonatomic, strong, readwrite) id resultObject; @property (nonatomic, strong, readwrite) NSError *error; @property (nonatomic, assign, readwrite) HLURLResultStatus status; @end @implementation HLURLResult - (instancetype)initWithObject:(id)resultObject andError:(NSError *)error { self = [super init]; if (self) { _resultObject = resultObject; _error = error; _status = [self resultStatusWithError:error]; } return self; } - (HLURLResultStatus)resultStatusWithError:(NSError *)error { if (error) { HLURLResultStatus result = HLURLResultStatusErrorNotReachable; // 除了超时以外,所有错误都当成是无网络 if (error.code == NSURLErrorTimedOut) { result = HLURLResultStatusErrorTimeout; } return result; } else { return HLURLResultStatusSuccess; } } - (NSString *)description { NSMutableString *desc = [NSMutableString string]; [desc appendString:@"\n---------HLURLResult Start---------\n"]; [desc appendFormat:@"Status : %@\n", [self getHLURLResultStatusString:self.status]]; [desc appendFormat:@"Object : %@\n", self.resultObject]; [desc appendFormat:@"Error : %@\n", self.error ?: @"成功"]; [desc appendString:@"----------HLURLResult End----------"]; return desc; } - (NSString *)debugDescription { return self.description; } - (NSDictionary *)toDictionary { NSMutableDictionary *dict = [NSMutableDictionary dictionary]; dict[@"Status"] = [self getHLURLResultStatusString:self.status]; dict[@"Object"] = [NSString stringWithFormat:@"%@", [self.resultObject class]]; dict[@"Error"] = self.error.localizedDescription ?: @"无错误"; return dict; } - (NSString *)getHLURLResultStatusString:(HLURLResultStatus)status { switch (status) { case HLURLResultStatusSuccess: return @"HLURLResultStatusSuccess"; break; case HLURLResultStatusErrorTimeout: return @"HLURLResultStatusErrorTimeout"; break; case HLURLResultStatusErrorNotReachable: return @"HLURLResultStatusErrorNotReachable"; break; default: return @"HLURLResultStatusErrorUnknown"; break; } } @end ================================================ FILE: HLNetworking/Source/HLNetworking.h ================================================ // // HLNetworking.h // HLPPShop // // Created by wangshiyu13 on 2016/9/19. // Copyright © 2016年 wangshiyu13. All rights reserved. // #ifndef HLNetworking_h #define HLNetworking_h // config #import "HLNetworkMacro.h" #import "HLNetworkConst.h" #import "HLNetworkConfig.h" #import "HLSecurityPolicyConfig.h" // manager #import "HLNetworkManager.h" // request #import "HLURLRequest.h" #import "HLRequestGroup.h" #import "HLAPIRequest.h" #import "HLTaskRequest.h" // logger #import "HLNetworkLogger.h" #endif /* HLNetworking_h */ ================================================ FILE: HLNetworking/Source/Logger/HLDebugMessage.h ================================================ // // HLDebugMessage.h // HLNetworking // // Created by wangshiyu13 on 2017/1/2. // Copyright © 2017年 wangshiyu13. All rights reserved. // #import #import "HLURLResponse.h" #import "NSNull+ToDictionary.h" typedef NSString *HLDebugKey; @interface HLDebugMessage : NSObject // 请求对象,HLAPI或HLTask @property (nonatomic, strong, readonly)id requestObject; // 获取NSURLSessionTask @property (nonatomic, strong, readonly)NSURLSessionTask *sessionTask; // 获取RequestObject @property (nonatomic, strong, readonly)HLURLResponse *response; // 执行的队列名 @property (nonatomic, copy, readonly)NSString *queueName; // 生成时间 @property (nonatomic, copy, readonly) NSString *timeString; - (instancetype)initWithRequest:(id)requestObject andResult:(id)resultObject andError:(NSError *)error andQueueName:(NSString *)queueName; - (NSDictionary *)toDictionary; @end ================================================ FILE: HLNetworking/Source/Logger/HLDebugMessage.m ================================================ // // HLDebugMessage.m // HLNetworking // // Created by wangshiyu13 on 2017/1/2. // Copyright © 2017年 wangshiyu13. All rights reserved. // #import "HLDebugMessage.h" #import "HLNetworkEngine.h" HLDebugKey const kHLSessionTaskDebugKey = @"kHLSessionTaskDebugKey"; HLDebugKey const kHLRequestDebugKey = @"kHLRequestDebugKey"; HLDebugKey const kHLResponseDebugKey = @"kHLResponseDebugKey"; HLDebugKey const kHLQueueDebugKey = @"kHLQueueDebugKey"; @interface HLDebugMessage () // 获取NSURLSessionTask @property (nonatomic, strong, readwrite)NSURLSessionTask *sessionTask; // 获取HLAPI @property (nonatomic, strong, readwrite)id requestObject; // 获取NSURLResponse @property (nonatomic, strong, readwrite)HLURLResponse *response; // 执行的队列名 @property (nonatomic, copy, readwrite)NSString *queueName; // 生成时间 @property (nonatomic, copy, readwrite) NSString *timeString; @end @implementation HLDebugMessage - (instancetype)initWithRequest:(id)requestObject andResult:(id)resultObject andError:(NSError *)error andQueueName:(NSString *)queueName { self = [super init]; if (self) { NSDateFormatter *myFormatter = [[NSDateFormatter alloc] init]; [myFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"]; _timeString = [myFormatter stringFromDate:[NSDate date]]; #pragma clang diagnostic push #pragma clang diagnostic ignored"-Wundeclared-selector" NSString *hashKey = [requestObject performSelector:@selector(hashKey)]; #pragma clang diagnostic pop id sessionTask = [[HLNetworkEngine sharedEngine] requestByIdentifier: hashKey]; id request = [NSNull null]; id requestId = [NSNull null]; if ([requestObject isKindOfClass:[NSURLSessionTask class]]) { request = [sessionTask currentRequest]; } if ([requestObject hash]) { requestId = [NSNumber numberWithUnsignedInteger:[requestObject hash]]; } // 生成response对象 HLURLResult *result = [[HLURLResult alloc] initWithObject:resultObject andError:error]; HLURLResponse *response = [[HLURLResponse alloc] initWithResult:result requestId:requestId request:request]; _sessionTask = sessionTask; _requestObject = request; _response = response; _queueName = queueName; } return self; } - (NSDictionary *)toDictionary { NSMutableDictionary *dictionary = [NSMutableDictionary dictionary]; dictionary[@"Time"] = self.timeString; dictionary[@"RequestObject"] = [self.requestObject toDictionary]; dictionary[@"Response"] = [self.response toDictionary]; dictionary[@"SessionTask"] = [self.sessionTask description]; dictionary[@"Queue"] = self.queueName; return dictionary; } - (NSString *)description { NSMutableString *desc = [NSMutableString string]; [desc appendString:@"\n****************Debug Message Start****************\n"]; [desc appendFormat:@"Time : %@\n", self.timeString]; [desc appendFormat:@"RequestObject : %@\n", self.requestObject ?: @"无参数"]; [desc appendFormat:@"SessionTask : %@\n", self.sessionTask ?: @"无参数"]; [desc appendFormat:@"Response : %@\n", self.response ?: @"无参数"]; [desc appendFormat:@"Queue : %@", self.queueName ?: @"无参数"]; [desc appendString:@"\n****************Debug Message End****************\n"]; return desc; } - (NSString *)debugDescription { return self.description; } @end ================================================ FILE: HLNetworking/Source/Logger/HLNetworkLogger.h ================================================ // // HLNetworkLogger.h // HLNetworking // // Created by wangshiyu13 on 2017/1/4. // Copyright © 2017年 wangshiyu13. All rights reserved. // #import #import "HLNetworkLoggerConfig.h" #import "HLDebugMessage.h" #import "UIDevice+deviceInfo.h" NS_ASSUME_NONNULL_BEGIN @protocol HLNetworkCustomLoggerDelegate @required // 根据传入的message拼接存储的日志结构 - (NSDictionary *)customInfoWithMessage:(HLDebugMessage *)message; @optional // 根据传入的设置拼接日志头部信息 - (NSDictionary *)customHeaderWithMessage:(HLNetworkLoggerConfig *)config; @end @interface HLNetworkLogger : NSObject @property (nonatomic, strong, readonly) HLNetworkLoggerConfig *config; // 设置代理 + (void)setDelegate:(id)delegate; // 写入后会清空当前记录的日志 + (void)writeToFile; // 打印debugMessage,该方法只在debug模式下有效 + (void)logInfoWithDebugMessage:(HLDebugMessage *)debugMessage; // 添加日志 + (void)addLogInfoWithDictionary:(NSDictionary *)dictionary; // 日志文件路径数组 + (nullable NSArray *)logFilePaths; // 设置config + (void)setupConfig:(void(^)(HLNetworkLoggerConfig *config))configBlock; // 是否已经开启日志 + (BOOL)isEnable; // 开启日志 + (void)startLogging; // 关闭日志 + (void)stopLogging; // 当前代理对象 + (nullable id)currentDelegate; // 单例对象 + (instancetype)shared; @end NS_ASSUME_NONNULL_END ================================================ FILE: HLNetworking/Source/Logger/HLNetworkLogger.m ================================================ // // HLNetworkLogger.m // HLNetworking // // Created by wangshiyu13 on 2017/1/4. // Copyright © 2017年 wangshiyu13. All rights reserved. // #import "HLNetworkLogger.h" #import "HLNetworkMacro.h" #import "UIDevice+deviceInfo.h" // 创建任务队列 static dispatch_queue_t qkhl_log_queue() { static dispatch_queue_t qkhl_log_queue; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ qkhl_log_queue = dispatch_queue_create("com.qkhl.networking.wangshiyu13.log.queue", DISPATCH_QUEUE_SERIAL); }); return qkhl_log_queue; } @interface HLNetworkLogger () @property (nonatomic, strong, readwrite) HLNetworkLoggerConfig *config; @property (nonatomic, weak, nullable) id delegate; @property (nonatomic, assign) BOOL enable; @property (nonatomic, strong) NSMutableArray *debugInfoArray; @end @implementation HLNetworkLogger #pragma mark - logger - (id)currentDelegate { return [self delegate]; } - (void)logInfoWithDebugMessage:(HLDebugMessage *)debugMessage { #if DEBUG NSLog(@"%@", debugMessage); #endif } - (NSArray *)logFilePaths { NSString *dirPath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"com.qkhl.HLNetworking/log"]; NSArray *fileList = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:dirPath error:nil]; NSMutableArray *tmpArray = [NSMutableArray array]; for (NSString *fileName in fileList) { NSString *path = [NSString stringWithFormat:@"%@/%@", dirPath, fileName]; [tmpArray addObject:path]; } return [tmpArray copy]; } - (void)writeToFile { dispatch_async(qkhl_log_queue(), ^{ if (self.config.enableLocalLog) { BOOL succeed = NO; if (self.config.loggerType == HLNetworkLoggerTypeJSON) { NSOutputStream *outputStream = [NSOutputStream outputStreamToFileAtPath:self.config.logFilePath append:YES]; [outputStream open]; succeed = [NSJSONSerialization writeJSONObject:self.debugInfoArray toStream:outputStream options:NSJSONWritingPrettyPrinted error:nil]; [outputStream close]; } else { succeed = [self.debugInfoArray writeToFile:self.config.logFilePath atomically:YES]; } if (succeed) { [self.debugInfoArray removeAllObjects]; } } }); } - (void)addLogInfoWithDictionary:(NSDictionary *)dictionary { dispatch_async(qkhl_log_queue(), ^{ if (self.config.enableLocalLog) { if (self.debugInfoArray.count > self.config.logAutoSaveCount) { [self writeToFile]; } if (dictionary.count > 0) { [self.debugInfoArray addObject:dictionary]; } } }); } - (void)startLogging { self.enable = YES; } - (void)stopLogging { self.enable = NO; } #pragma mark - setupConfig - (void)setupConfig:(void (^)(HLNetworkLoggerConfig * _Nonnull))configBlock { HL_SAFE_BLOCK(configBlock, self.config); } #pragma mark - init + (instancetype)shared { static dispatch_once_t onceToken; static HLNetworkLogger *shared; dispatch_once(&onceToken, ^{ shared = [[self alloc] init]; }); return shared; } - (instancetype)init { self = [super init]; if (self) { _config = [HLNetworkLoggerConfig config]; _enable = NO; _debugInfoArray = [NSMutableArray array]; } return self; } - (NSMutableArray *)debugInfoArray { if (_debugInfoArray.count == 0) { NSDictionary *infoHeader; if ([self.delegate respondsToSelector:@selector(customHeaderWithMessage:)]) { infoHeader = [self.delegate customHeaderWithMessage:self.config]; } else { infoHeader = @{@"AppInfo": @{@"OSVersion": [UIDevice currentDevice].systemVersion, @"DeviceType": [UIDevice currentDevice].hl_machineType, @"UDID": [UIDevice currentDevice].hl_udid, @"UUID": [UIDevice currentDevice].hl_uuid, @"MacAddressMD5": [UIDevice currentDevice].hl_macaddressMD5, @"ChannelID": _config.channelID, @"AppKey": _config.appKey, @"AppName": _config.appName, @"AppVersion": _config.appVersion, @"ServiceType": _config.serviceType}}; } [_debugInfoArray addObject:infoHeader]; } return _debugInfoArray; } #pragma mark - static method + (id)currentDelegate { return [[self shared] currentDelegate]; } + (void)setDelegate:(id)delegate { [[self shared] setDelegate:delegate]; } + (NSArray *)logFilePaths { return [[self shared] logFilePaths]; } + (void)setupConfig:(void (^)(HLNetworkLoggerConfig * _Nonnull))configBlock { [[self shared] setupConfig:configBlock]; } + (BOOL)isEnable { return [[self shared] enable]; } + (void)logInfoWithDebugMessage:(HLDebugMessage *)debugMessage { [[self shared] logInfoWithDebugMessage:debugMessage]; } + (void)writeToFile { [[self shared] writeToFile]; } + (void)addLogInfoWithDictionary:(NSDictionary *)dictionary { [[self shared] addLogInfoWithDictionary:dictionary]; } + (void)startLogging { [[self shared] startLogging]; } + (void)stopLogging { [[self shared] stopLogging]; } @end ================================================ FILE: HLNetworking/Source/Logger/HLNetworkLoggerConfig.h ================================================ // // HLNetworkLoggerConfig.h // HLNetworking // // Created by wangshiyu13 on 2017/1/4. // Copyright © 2017年 wangshiyu13. All rights reserved. // #import #import @class HLDebugMessage; typedef NS_OPTIONS(NSUInteger, HLNetworkLoggerLevel) { HLNetworkLoggerNoneLevel = 0, HLNetworkLoggerNetErrorLevel = 1 << 0, HLNetworkLoggerRequestLevel = 1 << 1, HLNetworkLoggerResponseLevel = 1 << 2, HLNetworkLoggerAllLevel = 1 << 3 }; typedef NS_ENUM(NSUInteger, HLNetworkLoggerType) { HLNetworkLoggerTypeJSON, HLNetworkLoggerTypePlist }; @interface HLNetworkLoggerConfig : NSObject // 渠道ID @property (nonatomic, copy) NSString *channelID; // app标志 @property (nonatomic, copy) NSString *appKey; // app名字 @property (nonatomic, copy) NSString *appName; // app版本 @property (nonatomic, copy) NSString *appVersion; // 服务名 @property (nonatomic, copy) NSString *serviceType; // 是否开启本地日志 @property (nonatomic, assign) BOOL enableLocalLog; // 日志自动保存数,默认为50次保存一次 @property (nonatomic, assign) NSUInteger logAutoSaveCount; // 日志等级,该选项暂时无效 @property (nonatomic, assign) HLNetworkLoggerLevel loggerLevel; // 日志保存类型 @property (nonatomic, assign) HLNetworkLoggerType loggerType; // 日志文件路径 @property (nonatomic, copy, readonly) NSString *logFilePath; + (instancetype)config; @end ================================================ FILE: HLNetworking/Source/Logger/HLNetworkLoggerConfig.m ================================================ // // HLNetworkLoggerConfig.m // HLNetworking // // Created by wangshiyu13 on 2017/1/4. // Copyright © 2017年 wangshiyu13. All rights reserved. // #import "HLNetworkLoggerConfig.h" @interface HLNetworkLoggerConfig () // 系统版本 @property (nonatomic, copy, readwrite) NSString *osVersion; // 设备型号 @property (nonatomic, copy, readwrite) NSString *deviceModel; // 设备标识 @property (nonatomic, copy, readwrite) NSString *UDID; @end @implementation HLNetworkLoggerConfig + (instancetype)config { return [[self alloc] init]; } - (instancetype)init { self = [super init]; if (self) { _channelID = @""; _appKey = @""; _appName = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleDisplayName"] ?: @""; _appVersion = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"] ?: @""; _serviceType = @""; _enableLocalLog = NO; _loggerLevel = HLNetworkLoggerNoneLevel; _logAutoSaveCount = 50; _loggerType = HLNetworkLoggerTypeJSON; } return self; } - (NSString *)logFilePath { NSString *filePath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"com.qkhl.HLNetworking/log"]; if (![[NSFileManager defaultManager] fileExistsAtPath:filePath isDirectory:nil]) { [[NSFileManager defaultManager] createDirectoryAtPath:filePath withIntermediateDirectories:YES attributes:nil error:nil]; } NSDateFormatter *myFormatter = [[NSDateFormatter alloc] init]; [myFormatter setDateFormat:@"yyyy-MM-dd_HH-mm-ss"]; NSString *dateString = [myFormatter stringFromDate:[NSDate date]]; return [filePath stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.log", dateString]]; } @end ================================================ FILE: HLNetworking/Source/Logger/NSNull+ToDictionary.h ================================================ // // NSNull+ToDictionary.h // HLNetworking // // Created by wangshiyu13 on 2017/1/23. // Copyright © 2017年 wangshiyu13. All rights reserved. // #import @interface NSNull (ToDictionary) - (NSDictionary *)toDictionary; @end ================================================ FILE: HLNetworking/Source/Logger/NSNull+ToDictionary.m ================================================ // // NSNull+ToDictionary.m // HLNetworking // // Created by wangshiyu13 on 2017/1/23. // Copyright © 2017年 wangshiyu13. All rights reserved. // #import "NSNull+ToDictionary.h" @implementation NSNull (ToDictionary) - (NSDictionary *)toDictionary { return @{@"NSNull": @"null"}; } @end ================================================ FILE: HLNetworking/Source/Logger/UIDevice+deviceInfo.h ================================================ // // UIDevice+deviceInfo.h // HLNetworking // // Created by Georg Kitz on 20.08.11. // Copyright 2011 Aurora Apps. All rights reserved. // #import @interface UIDevice (deviceInfo) - (NSString *) hl_uuid; - (NSString *) hl_udid; - (NSString *) hl_macaddress; - (NSString *) hl_macaddressMD5; - (NSString *) hl_machineType; @end ================================================ FILE: HLNetworking/Source/Logger/UIDevice+deviceInfo.m ================================================ // // UIDevice+deviceInfo.m // HLNetworking // // Created by Georg Kitz on 20.08.11. // Copyright 2011 Aurora Apps. All rights reserved. // #import "UIDevice+deviceInfo.h" #include #include // Per msqr #include #include #include #include static NSString *HLKeychainServiceName = @"HLKeychainServiceName"; static NSString *HLUDIDName = @"HLNetworkingUDID"; static NSString *HLPasteboardType = @"HLPasteboardType"; @interface UIDevice(Private) - (NSString *) localMAC; @end @implementation UIDevice (deviceInfo) /////////////////////////////////////////////////////////////////////////////////// #pragma mark - #pragma mark Private Methods // Return the local MAC addy // Courtesy of FreeBSD hackers email list // Accidentally munged during previous update. Fixed thanks to erica sadun & mlamb. - (NSString *) localMAC{ int mib[6]; size_t len; char *buf; unsigned char *ptr; struct if_msghdr *ifm; struct sockaddr_dl *sdl; mib[0] = CTL_NET; mib[1] = AF_ROUTE; mib[2] = 0; mib[3] = AF_LINK; mib[4] = NET_RT_IFLIST; if ((mib[5] = if_nametoindex("en0")) == 0) { printf("Error: if_nametoindex error\n"); return NULL; } if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) { printf("Error: sysctl, take 1\n"); return NULL; } if ((buf = malloc(len)) == NULL) { printf("Could not allocate memory. error!\n"); return NULL; } if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) { printf("Error: sysctl, take 2"); free(buf); return NULL; } ifm = (struct if_msghdr *)buf; sdl = (struct sockaddr_dl *)(ifm + 1); ptr = (unsigned char *)LLADDR(sdl); NSString *outstring = [NSString stringWithFormat:@"%02X:%02X:%02X:%02X:%02X:%02X", *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4), *(ptr+5)]; free(buf); return outstring; } //////////////////////////////////////////////////////////////////////////////// #pragma mark - #pragma mark Public Methods - (NSString *)hl_createUUID { CFUUIDRef uuid = CFUUIDCreate(NULL); CFStringRef string = CFUUIDCreateString(NULL, uuid); CFRelease(uuid); return (__bridge_transfer NSString *)string; } - (NSString *)hl_uuid { NSString *key = @"HLNetworkingUUID"; NSString *uuid = [[NSUserDefaults standardUserDefaults] objectForKey:key]; if (uuid.length == 0) { [[NSUserDefaults standardUserDefaults] setObject:[self hl_createUUID] forKey:key]; return [[[NSUserDefaults standardUserDefaults] objectForKey:key] copy]; } else { return uuid; } } - (NSString *) hl_udid { NSString *udid = [self getUDID]; if (udid.length==0) { udid = [self hl_uuid]; [self saveUDID:udid]; } return udid; } - (NSString *)hl_macaddress { NSString *key = @"macAddress"; NSString *macAddress = [[NSUserDefaults standardUserDefaults] objectForKey:key]; if (macAddress.length == 0) { macAddress = [self localMAC]; if (macAddress.length>0){ [[NSUserDefaults standardUserDefaults] setObject:macAddress forKey:key]; [[NSUserDefaults standardUserDefaults] setObject:@"" forKey:@"macaddressMD5"]; } } return macAddress; } - (NSString *) hl_macaddressMD5 { NSString *key = @"MACAddressMD5"; NSString *macid = [[NSUserDefaults standardUserDefaults] objectForKey:key]; if (macid.length == 0) { NSString *macaddress = [[UIDevice currentDevice] hl_macaddress]; macid = [self md5:macaddress]; if (!macid){ macid = @"macaddress_empty"; }else{ [[NSUserDefaults standardUserDefaults] setObject:macid forKey:key]; } } return macid; } - (NSString *)hl_machineType { struct utsname systemInfo; uname(&systemInfo); NSString *machineType = [NSString stringWithCString:systemInfo.machine encoding:NSUTF8StringEncoding]; NSString *plistPath = [[NSBundle mainBundle] pathForResource:@"iPhoneTypeDefine" ofType:@"plist"]; NSDictionary *dictionary = [NSDictionary dictionaryWithContentsOfFile:plistPath]; NSString *type = dictionary[machineType]; if (type) { return type; } else { return machineType; } } #pragma mark - UDID相关 - (NSString *)getUDID { NSData *udidData = [self searchKeychainCopyMatching:HLUDIDName]; NSString *udid = nil; if (udidData != nil) { NSString *temp = [[NSString alloc] initWithData:udidData encoding:NSUTF8StringEncoding]; udid = [NSString stringWithFormat:@"%@", temp]; } if (udid.length == 0) { udid = [self readPasteBoradforIdentifier:HLUDIDName]; } return udid; } #pragma mark - UDID相关 - (void)saveUDID:(NSString *)udid { BOOL saveOk = NO; NSData *udidData = [self searchKeychainCopyMatching:HLUDIDName]; if (udidData == nil) { saveOk = [self createKeychainValue:udid forIdentifier:HLUDIDName]; } else { saveOk = [self updateKeychainValue:udid forIdentifier:HLUDIDName]; } if (!saveOk) { [self createPasteBoradValue:udid forIdentifier:HLUDIDName]; } } - (NSMutableDictionary *)newSearchDictionary:(NSString *)identifier { NSMutableDictionary *searchDictionary = [[NSMutableDictionary alloc] init]; [searchDictionary setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass]; NSData *encodedIdentifier = [identifier dataUsingEncoding:NSUTF8StringEncoding]; [searchDictionary setObject:encodedIdentifier forKey:(__bridge id)kSecAttrGeneric]; [searchDictionary setObject:encodedIdentifier forKey:(__bridge id)kSecAttrAccount]; [searchDictionary setObject:HLKeychainServiceName forKey:(__bridge id)kSecAttrService]; return searchDictionary; } - (NSData *)searchKeychainCopyMatching:(NSString *)identifier { NSMutableDictionary *searchDictionary = [self newSearchDictionary:identifier]; // Add search attributes [searchDictionary setObject:(__bridge id)kSecMatchLimitOne forKey:(__bridge id)kSecMatchLimit]; // Add search return types [searchDictionary setObject:(id)kCFBooleanTrue forKey:(__bridge id)kSecReturnData]; CFDataRef result = nil; SecItemCopyMatching((__bridge CFDictionaryRef)searchDictionary, (CFTypeRef *)&result); return (__bridge NSData *)result; } - (BOOL)createKeychainValue:(NSString *)value forIdentifier:(NSString *)identifier { NSMutableDictionary *dictionary = [self newSearchDictionary:identifier]; NSData *passwordData = [value dataUsingEncoding:NSUTF8StringEncoding]; [dictionary setObject:passwordData forKey:(__bridge id)kSecValueData]; OSStatus status = SecItemAdd((__bridge CFDictionaryRef)dictionary, NULL); if (status == errSecSuccess) { return YES; } return NO; } - (BOOL)updateKeychainValue:(NSString *)value forIdentifier:(NSString *)identifier { NSMutableDictionary *searchDictionary = [self newSearchDictionary:identifier]; NSMutableDictionary *updateDictionary = [[NSMutableDictionary alloc] init]; NSData *passwordData = [value dataUsingEncoding:NSUTF8StringEncoding]; [updateDictionary setObject:passwordData forKey:(__bridge id)kSecValueData]; OSStatus status = SecItemUpdate((__bridge CFDictionaryRef)searchDictionary, (__bridge CFDictionaryRef)updateDictionary); if (status == errSecSuccess) { return YES; } return NO; } - (void)deleteKeychainValue:(NSString *)identifier { NSMutableDictionary *searchDictionary = [self newSearchDictionary:identifier]; SecItemDelete((__bridge CFDictionaryRef)searchDictionary); } - (void)createPasteBoradValue:(NSString *)value forIdentifier:(NSString *)identifier { UIPasteboard *pb = [UIPasteboard pasteboardWithName:HLKeychainServiceName create:YES]; NSDictionary *dict = [NSDictionary dictionaryWithObject:value forKey:identifier]; NSData *dictData = [NSKeyedArchiver archivedDataWithRootObject:dict]; [pb setData:dictData forPasteboardType:HLPasteboardType]; } - (NSString *)readPasteBoradforIdentifier:(NSString *)identifier { UIPasteboard *pb = [UIPasteboard pasteboardWithName:HLKeychainServiceName create:YES]; NSDictionary *dict = [NSKeyedUnarchiver unarchiveObjectWithData:[pb dataForPasteboardType:HLPasteboardType]]; return [dict objectForKey:identifier]; } - (NSString *)md5:(NSString *)string { NSData* inputData = [string dataUsingEncoding:NSUTF8StringEncoding]; unsigned char outputData[CC_MD5_DIGEST_LENGTH]; CC_MD5([inputData bytes], (unsigned int)[inputData length], outputData); NSMutableString* hashStr = [NSMutableString string]; int i = 0; for (i = 0; i < CC_MD5_DIGEST_LENGTH; ++i) [hashStr appendFormat:@"%02x", outputData[i]]; return hashStr; } @end ================================================ FILE: HLNetworking/Source/Logger/iPhoneTypeDefine.plist ================================================ i386 32-bit Simulator x86_64 64-bit Simulator iPod1,1 iPod Touch iPod2,1 iPod Touch 2 iPod3,1 iPod Touch 3 iPod4,1 iPod Touch 4 iPod5,1 iPod Touch 5 iPod7,1 iPod Touch 6 iPad1,1 iPad iPad2,1 iPad 2 iPad2,2 iPad 2 iPad2,3 iPad 2 iPad2,4 iPad 2 iPad2,5 iPad Mini iPad2,6 iPad Mini iPad2,7 iPad Mini iPad3,1 iPad 3 iPad3,2 iPad 3 iPad3,3 iPad 3 iPad3,4 iPad 4 iPad3,5 iPad 4 iPad3,6 iPad 4 iPad4,1 iPad Air iPad4,2 iPad Air iPad4,3 iPad Air iPad4,4 iPad Mini 2 iPad4,5 iPad Mini 2 iPad4,6 iPad Mini 2 iPad4,7 iPad Mini 3 iPad4,8 iPad Mini 3 iPad4,9 iPad Mini 3 iPad5,1 iPad Mini 4 iPad5,2 iPad Mini 4 iPad5,3 iPad Air 2 iPad5,4 iPad Air 2 iPad6,3 iPad Pro 9.7 iPad6,4 iPad Pro 9.7 iPad6,7 iPad Pro 12.9 iPad6,8 iPad Pro 12.9 iPhone1,1 iPhone iPhone1,2 iPhone 3G iPhone2,1 iPhone 3GS iPhone3,1 iPhone 4 (GSM) iPhone3,3 iPhone 4 (CDMA/Verizon/Sprint) iPhone4,1 iPhone 4S iPhone5,1 iPhone 5 (model A1428, AT&T/Canada) iPhone5,2 iPhone 5 (model A1429, everything else) iPhone5,3 iPhone 5c (model A1456, A1532 | GSM) iPhone5,4 iPhone 5c (model A1507, A1516, A1526 (China), A1529 | Global) iPhone6,1 iPhone 5s (model A1433, A1533 | GSM) iPhone6,2 iPhone 5s (model A1457, A1518, A1528 (China), A1530 | Global) iPhone7,1 iPhone 6 Plus iPhone7,2 iPhone 6 iPhone8,1 iPhone 6s iPhone8,2 iPhone 6s Plus iPhone8,4 iPhone SE iPhone9,1 iPhone 7 iPhone9,2 iPhone 7 Plus iPhone9,3 iPhone 7 iPhone9,4 iPhone 7 Plus ================================================ FILE: HLNetworking/Source/Manager/HLNetworkManager.h ================================================ // // HLNetworkManager.h // HLNetworking // // Created by wangshiyu13 on 2017/1/23. // Copyright © 2017年 wangshiyu13. All rights reserved. // #import #import "HLNetworkConst.h" @class HLNetworkConfig; @class HLURLRequest; @class HLRequestGroup; @protocol HLNetworkResponseDelegate; // 判断当前是否为审核版本 FOUNDATION_EXPORT inline BOOL HLJudgeVersion(void); // 设置是否为审核版本 FOUNDATION_EXPORT inline void HLJudgeVersionSwitch(BOOL isR); NS_ASSUME_NONNULL_BEGIN @interface HLNetworkManager : NSObject #pragma mark - property @property (nonatomic, strong, readonly) HLNetworkConfig *config; + (HLNetworkConfig *)config; #pragma mark - initialize method // 请使用manager或sharedManager + (instancetype)new NS_UNAVAILABLE; - (instancetype)init NS_UNAVAILABLE; // 返回一个新的manager对象 + (instancetype)manager; // 返回单例 + (instancetype)sharedManager; // 配置设置 + (void)setupConfig:(void(^)(HLNetworkConfig *config))configBlock; - (void)setupConfig:(void(^)(HLNetworkConfig *config))configBlock; #pragma mark - process // 发送API请求,默认为manager内置队列 + (void)send:(__kindof HLURLRequest *)request; - (void)send:(__kindof HLURLRequest *)request; // 发送一组请求 + (void)sendGroup:(HLRequestGroup *)group; - (void)sendGroup:(HLRequestGroup *)group; // 取消API请求,如果该请求已经发送或者正在发送,则不保证一定可以取消,但会将Block回落点置空,delegate正常回调,默认为manager内置队列 + (void)cancel:(__kindof HLURLRequest *)request; - (void)cancel:(__kindof HLURLRequest *)request; // 取消API请求,如果该请求已经发送或者正在发送,则不保证一定可以取消,但会将Block回落点置空,delegate正常回调,默认为manager内置队列 + (void)cancelGroup:(HLRequestGroup *)group; - (void)cancelGroup:(HLRequestGroup *)group; // 恢复Task + (void)resume:(__kindof HLURLRequest *)request; - (void)resume:(__kindof HLURLRequest *)request; // 暂停Task + (void)pause:(__kindof HLURLRequest *)request; - (void)pause:(__kindof HLURLRequest *)request; // 注册网络请求监听者 + (void)registerResponseObserver:(id)observer; - (void)registerResponseObserver:(id)observer; // 删除网络请求监听者 + (void)removeResponseObserver:(id)observer; - (void)removeResponseObserver:(id)observer; #pragma mark - reachability相关 // 当前reachability状态 @property (nonatomic, assign, readonly) HLReachabilityStatus reachabilityStatus; // 当前是否可访问网络 @property (nonatomic, assign, readonly, getter = isReachable) BOOL reachable; // 当前是否使用数据流量访问网络 @property (nonatomic, assign, readonly, getter = isReachableViaWWAN) BOOL reachableViaWWAN; // 当前是否使用WiFi访问网络 @property (nonatomic, assign, readonly, getter = isReachableViaWiFi) BOOL reachableViaWiFi; // 通过sharedMager单例,获取当前reachability状态 + (HLReachabilityStatus)reachabilityStatus; // 通过sharedMager单例,获取当前是否可访问网络 + (BOOL)isReachable; // 通过sharedMager单例,获取当前是否使用数据流量访问网络 + (BOOL)isReachableViaWWAN; // 通过sharedMager单例,获取当前是否使用WiFi访问网络 + (BOOL)isReachableViaWiFi; // 开启默认reachability监视器,block返回状态 + (void)listening:(HLReachabilityBlock)listener; // 默认reachability监视器停止监听 + (void)stopListening; // 监听给定的域名是否可以访问,block内返回状态 - (void)listeningWithDomain:(NSString *)domain listeningBlock:(HLReachabilityBlock)listener; // 停止给定域名的网络状态监听 - (void)stopListeningWithDomain:(NSString *)domain; @end #pragma mark - manager监听代理 @protocol HLNetworkResponseDelegate // 快速设置需要监听的task对象 #define HLObserverRequests(...) \ - (NSArray <__kindof HLURLRequest *>* _Nonnull)observerRequests { \ return [NSArray arrayWithObjects:__VA_ARGS__, nil]; \ } @required // 设置需要监听的task对象 - (NSArray <__kindof HLURLRequest *>*)observerRequests; @optional // task 上传、下载等长时间执行的Progress进度 - (void)requestProgress:(nullable NSProgress *)progress atRequest:(nullable __kindof HLURLRequest *)request; // 请求成功的回调 - (void)requestSucess:(nullable id)responseObject atRequest:(nullable __kindof HLURLRequest *)request; // 请求失败的回调 - (void)requestFailure:(nullable NSError *)error atRequest:(nullable __kindof HLURLRequest *)request; @end NS_ASSUME_NONNULL_END ================================================ FILE: HLNetworking/Source/Manager/HLNetworkManager.m ================================================ // // HLNetworkManager.m // HLNetworking // // Created by wangshiyu13 on 2017/1/23. // Copyright © 2017年 wangshiyu13. All rights reserved. // #import "HLNetworkManager.h" #import "HLNetworkEngine.h" #import "HLNetworkConfig.h" #import "HLNetworkMacro.h" #import "HLNetworkLogger.h" #import "HLDebugMessage.h" #import "HLURLRequest_InternalParams.h" #import "HLRequestGroup.h" #import "HLTaskRequest.h" #import "HLAPIRequest_InternalParams.h" inline BOOL HLJudgeVersion(void) { return [[NSUserDefaults standardUserDefaults] boolForKey:@"isR"]; } inline void HLJudgeVersionSwitch(BOOL isR) { [[NSUserDefaults standardUserDefaults] setBool:isR forKey:@"isR"]; } // 创建任务队列 static dispatch_queue_t qkhl_network_request_queue() { static dispatch_queue_t qkhl_network_request_queue; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ qkhl_network_request_queue = dispatch_queue_create("com.qkhl.wangshiyu13.networking.callback.queue", DISPATCH_QUEUE_PRIORITY_DEFAULT); }); return qkhl_network_request_queue; } // 创建上传下载任务队列 static dispatch_queue_t qkhl_network_task_queue() { static dispatch_queue_t qkhl_network_task_queue; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ qkhl_network_task_queue = dispatch_queue_create("com.qkhl.wangshiyu13.networking.task.queue", DISPATCH_QUEUE_PRIORITY_DEFAULT); }); return qkhl_network_task_queue; } @interface HLNetworkManager () { dispatch_semaphore_t _lock; } @property (nonatomic, strong, readwrite) HLNetworkConfig *config; @property (nonatomic, strong) NSHashTable> *responseObservers; @property (nonatomic, assign, readwrite) HLReachabilityStatus reachabilityStatus; @property (nonatomic, assign, readwrite, getter = isReachable) BOOL reachable; @property (nonatomic, assign, readwrite, getter = isReachableViaWWAN) BOOL reachableViaWWAN; @property (nonatomic, assign, readwrite, getter = isReachableViaWiFi) BOOL reachableViaWiFi; @end @implementation HLNetworkManager + (HLNetworkConfig *)config { return [[self sharedManager] config]; } #pragma mark - initialize method + (instancetype)manager { return [[self alloc] init]; } + (instancetype)sharedManager { static HLNetworkManager *shared = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ shared = [[self alloc] init]; }); return shared; } - (instancetype)init { self = [super init]; if (self) { _lock = dispatch_semaphore_create(1); _config = [HLNetworkConfig config]; _reachabilityStatus = HLReachabilityStatusUnknown; _responseObservers = [NSHashTable hashTableWithOptions:NSHashTableWeakMemory]; } return self; } - (void)setupConfig:(void (^)(HLNetworkConfig * _Nonnull config))configBlock { HL_SAFE_BLOCK(configBlock, self.config); } + (void)setupConfig:(void (^)(HLNetworkConfig * _Nonnull config))configBlock { [[self sharedManager] setupConfig:configBlock]; } #pragma mark - process // 发送API请求,默认为manager内置队列 - (void)send:(__kindof HLURLRequest *)request { @hl_weakify(self); if (!request.queue) { if ([request isKindOfClass:[HLTaskRequest class]]) { request.queue = qkhl_network_task_queue(); } else { request.queue = qkhl_network_request_queue(); } } dispatch_async(request.queue, ^{ @hl_strongify(self); [self send:request atSemaphore:nil atGroup:nil]; }); } + (void)send:(__kindof HLURLRequest *)request { [[self sharedManager] send:request]; } // 发送一组请求,使用信号量做同步请求,使用group做完成通知 - (void)sendGroup:(HLRequestGroup *)group { if (!group) return; dispatch_queue_t queue; if (group.customQueue) { queue = group.customQueue; } else { if ([group[0] isKindOfClass:[HLTaskRequest class]]) { queue = qkhl_network_task_queue(); } else { queue = qkhl_network_request_queue(); } } // 根据groupMode 配置信号量 dispatch_semaphore_t semaphore = nil; if (group.groupMode == HLRequestGroupModeChain) { semaphore = dispatch_semaphore_create(group.maxRequestCount); } dispatch_group_t api_group = dispatch_group_create(); @hl_weakify(self); dispatch_async(queue, ^{ [group enumerateObjectsUsingBlock:^(HLURLRequest * _Nonnull request, NSUInteger idx, BOOL * _Nonnull stop) { @hl_strongify(self); request.queue = queue; if (group.groupMode == HLRequestGroupModeChain) { dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); } dispatch_group_enter(api_group); [self send:request atSemaphore:semaphore atGroup:api_group]; }]; dispatch_group_notify(api_group, dispatch_get_main_queue(), ^{ if (group.delegate) { [group.delegate requestGroupAllDidFinished:group]; } }); }); } + (void)sendGroup:(HLRequestGroup *)group { [[self sharedManager] sendGroup:group]; } // 取消API请求,如果该请求已经发送或者正在发送,则不保证一定可以取消,但会将Block回落点置空,delegate正常回调,默认为manager内置队列 - (void)cancel:(__kindof HLURLRequest *)request { if (!request.queue) { if ([request isKindOfClass:[HLTaskRequest class]]) { request.queue = qkhl_network_task_queue(); } else { request.queue = qkhl_network_request_queue(); } } dispatch_async(request.queue, ^{ [[HLNetworkEngine sharedEngine] cancelRequestByIdentifier:request.hashKey]; }); } + (void)cancel:(__kindof HLURLRequest *)request { [[self sharedManager] cancel:request]; } // 取消API请求,如果该请求已经发送或者正在发送,则不保证一定可以取消,但会将Block回落点置空,delegate正常回调,默认为manager内置队列 - (void)cancelGroup:(HLRequestGroup *)group { NSAssert(group.count != 0, @"APIGroup元素不可小于1"); [group enumerateObjectsUsingBlock:^(__kindof HLURLRequest * _Nonnull request, NSUInteger idx, BOOL * _Nonnull stop) { [self cancel:request]; }]; } + (void)cancelGroup:(HLRequestGroup *)group { [[self sharedManager] cancelGroup:group]; } // 恢复Task - (void)resume:(__kindof HLURLRequest *)request { @hl_weakify(self); if (!request.queue) { if ([request isKindOfClass:[HLTaskRequest class]]) { request.queue = qkhl_network_task_queue(); } else { request.queue = qkhl_network_request_queue(); } } dispatch_async(request.queue, ^{ @hl_strongify(self); NSURLSessionTask *sessionTask = [[HLNetworkEngine sharedEngine] requestByIdentifier:request.hashKey]; if (sessionTask) { [sessionTask resume]; } else { [self send:request]; } }); } + (void)resume:(__kindof HLURLRequest *)request { [[self sharedManager] resume:request]; } // 暂停Task - (void)pause:(__kindof HLURLRequest *)request { if (!request.queue) { if ([request isKindOfClass:[HLTaskRequest class]]) { request.queue = qkhl_network_task_queue(); } else { request.queue = qkhl_network_request_queue(); } } dispatch_async(request.queue, ^{ NSURLSessionTask *sessionTask = [[HLNetworkEngine sharedEngine] requestByIdentifier:request.hashKey]; if (sessionTask) { [sessionTask suspend]; } }); } + (void)pause:(__kindof HLURLRequest *)request { [[self sharedManager] pause:request]; } // 注册网络请求监听者 - (void)registerResponseObserver:(id)observer { HLLock(); [self.responseObservers addObject:observer]; HLUnlock(); } + (void)registerResponseObserver:(id)observer { [[self sharedManager] registerResponseObserver:observer]; } // 删除网络请求监听者 - (void)removeResponseObserver:(id)observer { HLLock(); if ([self.responseObservers containsObject:observer]) { [self.responseObservers removeObject:observer]; } HLUnlock(); } + (void)removeResponseObserver:(id)observer { [[self sharedManager] removeResponseObserver:observer]; } #pragma mark - reachability - (BOOL)isReachable { return [self isReachableViaWWAN] || [self isReachableViaWiFi]; } - (BOOL)isReachableViaWWAN { return self.reachabilityStatus == HLReachabilityStatusReachableViaWWAN; } - (BOOL)isReachableViaWiFi { return self.reachabilityStatus == HLReachabilityStatusReachableViaWiFi; } + (HLReachabilityStatus)reachabilityStatus { return [[self sharedManager] reachabilityStatus]; } + (BOOL)isReachable { return [[self sharedManager] isReachable]; } + (BOOL)isReachableViaWWAN { return [[self sharedManager] isReachableViaWWAN]; } + (BOOL)isReachableViaWiFi { return [[self sharedManager] isReachableViaWiFi]; } + (void)listening:(HLReachabilityBlock)listener { [[self sharedManager] listeningWithDomain:[[self sharedManager] config].request.baseURL listeningBlock:listener]; } + (void)stopListening { [[self sharedManager] stopListeningWithDomain:[[self sharedManager] config].request.baseURL]; } - (void)listeningWithDomain:(NSString *)domain listeningBlock:(HLReachabilityBlock)listener { if (self.config.enableReachability) { @hl_weakify(self) [[HLNetworkEngine sharedEngine] listeningWithDomain:domain listeningBlock:^(HLReachabilityStatus status) { @hl_strongify(self) self.reachabilityStatus = status; listener(status); }]; } } - (void)stopListeningWithDomain:(NSString *)domain { [[HLNetworkEngine sharedEngine] stopListeningWithDomain:domain]; } #pragma mark - private method - (void)send:(HLURLRequest *)request atSemaphore:(dispatch_semaphore_t)semaphore atGroup:(dispatch_group_t)group { // 对api.delegate 发送即将请求api的消息 if ([request.delegate respondsToSelector:@selector(requestWillBeSent:)]) { dispatch_async_main(self.config.request.callbackQueue, ^{ [request.delegate requestWillBeSent:request]; }); } if (self.config.tips.isNetworkingActivityIndicatorEnabled) { [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES]; } // 定义进度block @hl_weakify(self) void (^progressBlock)(NSProgress *proc) = ^(NSProgress *proc) { if (proc.totalUnitCount <= 0) return; dispatch_async_main(self.config.request.callbackQueue, ^{ for (id obj in self.responseObservers) { if ([[obj observerRequests] containsObject:request]) { if ([obj respondsToSelector:@selector(requestProgress:atRequest:)]) { [obj requestProgress:proc atRequest:request]; } } } }); }; // 定义回调block void (^callBackBlock)(HLURLRequest *request, id responseObject, NSError *error) = ^(HLURLRequest *request, id responseObject, NSError *error) { @hl_strongify(self) if (self.config.tips.isNetworkingActivityIndicatorEnabled) { [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO]; } [self callbackWithRequest:request andResultObject:responseObject andError:error andGroup:group andSemaphore:semaphore]; }; [[HLNetworkEngine sharedEngine] sendRequest:request andConfig:self.config progressBack:progressBlock callBack:callBackBlock]; // 对api.delegate 发送已经请求api的消息 if ([request.delegate respondsToSelector:@selector(requestDidSent:)]) { dispatch_async_main(self.config.request.callbackQueue, ^{ [request.delegate requestDidSent:request]; }); } } /** Task完成的回调方法 @param request 调用的request @param resultObject 返回的对象 @param error 返回的错误 @param group 调用的组 @param semaphore 调用的信号量 */ - (void)callbackWithRequest:(HLURLRequest *)request andResultObject:(id)resultObject andError:(NSError *)error andGroup:(dispatch_group_t)group andSemaphore:(dispatch_semaphore_t)semaphore { // 处理回调的block NSError *netError = error; if (netError) { // 网络状态不好时自动重试 if (request.retryCount > 0) { request.retryCount --; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ [self send:request atSemaphore:semaphore atGroup:group]; }); return; } // 如果不是reachability无法访问host或用户取消错误(NSURLErrorCancelled),则对错误提示进行处理 if (![error.domain isEqualToString: NSURLErrorDomain] && error.code != NSURLErrorCancelled) { // 使用KVC修改error内部属性 // 默认使用self.config.generalErrorTypeStr = "服务器连接错误,请稍候重试" NSMutableDictionary *tmpUserInfo = [[NSMutableDictionary alloc]initWithDictionary:error.userInfo copyItems:NO]; if (![[tmpUserInfo allKeys] containsObject:NSLocalizedFailureReasonErrorKey]) { tmpUserInfo[NSLocalizedFailureReasonErrorKey] = NSLocalizedString(self.config.tips.generalErrorTypeStr, nil); } if (![[tmpUserInfo allKeys] containsObject:NSLocalizedRecoverySuggestionErrorKey]) { tmpUserInfo[NSLocalizedRecoverySuggestionErrorKey] = NSLocalizedString(self.config.tips.generalErrorTypeStr, nil); } // 加上 networking error code NSString *newErrorDescription = self.config.tips.generalErrorTypeStr; if (self.config.policy.isErrorCodeDisplayEnabled) { newErrorDescription = [NSString stringWithFormat:@"%@, error code = (%ld)", self.config.tips.generalErrorTypeStr, (long)error.code]; } tmpUserInfo[NSLocalizedDescriptionKey] = NSLocalizedString(newErrorDescription, nil); NSDictionary *userInfo = [tmpUserInfo copy]; netError = [NSError errorWithDomain:error.domain code:error.code userInfo:userInfo]; } } if ([request isKindOfClass:[HLAPIRequest class]]) { HLAPIRequest *tmpRequest = (HLAPIRequest *)request; if (tmpRequest.objReformerDelegate) { resultObject = [tmpRequest.objReformerDelegate reformerObject:resultObject andError:netError atRequest:tmpRequest]; } } // 设置Debug及log信息 HLDebugMessage *msg = [[HLDebugMessage alloc] initWithRequest:request andResult:resultObject andError:netError andQueueName:[NSString stringWithFormat:@"%@", [request isKindOfClass:[HLTaskRequest class]] ? qkhl_network_task_queue() : qkhl_network_request_queue()]]; #if DEBUG if (self.config.enableGlobalLog) { [HLNetworkLogger logInfoWithDebugMessage:msg]; } if (request.debugHandler) { request.debugHandler(msg); request.debugHandler = nil; } #endif if ([HLNetworkLogger isEnable]) { NSDictionary *msgDictionary; if ([HLNetworkLogger currentDelegate]) { msgDictionary = [[HLNetworkLogger currentDelegate] customInfoWithMessage:msg]; } else { msgDictionary = [msg toDictionary]; } [HLNetworkLogger addLogInfoWithDictionary:msgDictionary]; } if (netError) { if ([request failureHandler]) { dispatch_async_main(self.config.request.callbackQueue, ^{ request.failureHandler(netError); request.failureHandler = nil; }); } } else { if ([request successHandler]) { dispatch_async_main(self.config.request.callbackQueue, ^{ request.successHandler(resultObject); request.successHandler = nil; }); } } if (request.progressHandler) { request.progressHandler = nil; } // 处理回调的delegate for (id observer in self.responseObservers) { if ([[observer observerRequests] containsObject:request]) { if (netError) { if ([observer respondsToSelector:@selector(requestFailure:atRequest:)]) { dispatch_async_main(self.config.request.callbackQueue, ^{ [observer requestFailure:netError atRequest:request]; }); } } else { if ([observer respondsToSelector:@selector(requestSucess:atRequest:)]) { dispatch_async_main(self.config.request.callbackQueue, ^{ [observer requestSucess:resultObject atRequest:request]; }); } } } } // 完成后离组 if (group) { dispatch_group_leave(group); } // 完成后信号量加1 if (semaphore) { dispatch_semaphore_signal(semaphore); } } //获取已下载的文件大小 - (unsigned long long)fileSizeForPath:(NSString *)path { signed long long fileSize = 0; NSFileManager *fileManager = [NSFileManager new]; // default is not thread safe if ([fileManager fileExistsAtPath:path]) { NSError *error = nil; NSDictionary *fileDict = [fileManager attributesOfItemAtPath:path error:&error]; if (!error && fileDict) { fileSize = [fileDict fileSize]; } } return fileSize; } @end ================================================ FILE: HLNetworking/ViewController.h ================================================ // // ViewController.h // HLNetworking // // Created by wangshiyu13 on 2016/9/22. // Copyright © 2016年 wangshiyu13. All rights reserved. // #import @interface ViewController : UIViewController @end ================================================ FILE: HLNetworking/ViewController.m ================================================ // // ViewController.m // HLNetworking // // Created by wangshiyu13 on 2016/9/22. // Copyright © 2016年 wangshiyu13. All rights reserved. // #import "ViewController.h" #import "HLNetworking.h" #import "HLAPICenter+home.h" //static dispatch_queue_t my_api_queue() { // static dispatch_queue_t my_api_queue; // static dispatch_once_t onceToken; // dispatch_once(&onceToken, ^{ // my_api_queue = dispatch_queue_create("com.qkhl.queue", DISPATCH_QUEUE_SERIAL); // }); // return my_api_queue; //} @interface ViewController () @property(nonatomic, strong)HLAPIRequest *api1; @property(nonatomic, strong)HLAPIRequest *api2; @property(nonatomic, strong)HLAPIRequest *api3; @property(nonatomic, strong)HLAPIRequest *api4; @property(nonatomic, strong)HLAPIRequest *api5; @property(nonatomic, strong)HLAPIRequest *api6; @property(nonatomic, strong)HLAPIRequest *api7; @property(nonatomic, strong)HLTaskRequest *task1; @property(nonatomic, strong) NSMutableArray *taskArray; @property(nonatomic, assign)BOOL isPause; @property(nonatomic, strong) id model; @end @implementation ViewController - (HLTaskRequest *)task1 { if (!_task1) { _task1 = [HLTaskRequest request] .setDelegate(self) .setFilePath([[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"minion_01.mp4"]) .setCustomURL(@"http://120.25.226.186:32812/resources/videos/minion_01.mp4") .progress(^(NSProgress *proc){ NSLog(@"\n进度=====\n当前进度:%@", proc); }) .success(^(id response){ NSLog(@"\n完成=====\n对象:%@", response); }) .failure(^(NSError *error){ NSLog(@"\n失败=====\n错误:%@", error); }); } return _task1; } - (void)viewDidLoad { [super viewDidLoad]; // setupLogger // [HLNetworkLogger setupConfig:^(HLNetworkLoggerConfig * _Nonnull config) { // config.enableLocalLog = YES; // config.logAutoSaveCount = 5; // config.loggerType = HLNetworkLoggerTypePlist; // }]; // [HLNetworkLogger setDelegate:self]; // [HLNetworkLogger startLogging]; // // // setupNetwork // [HLNetworkManager setupConfig:^(HLNetworkConfig * _Nonnull config) { // config.request.baseURL = @"https://httpbin.org"; // config.policy.isBackgroundSession = NO; // config.request.apiVersion = nil; //// config.request.retryCount = 4; // }]; // [HLNetworkManager registerResponseObserver:self]; // [self testTask]; // [self testAPI]; // [self testButton]; // [self testHome]; } - (void)testHome { [HLAPICenter.home.success(^(id responce) { self.model = responce; }).failure(^(NSError *obj){ NSLog(@"----%@", obj); }) start]; } - (void)testButton { self.isPause = YES; UIButton *pauseButton = [UIButton buttonWithType:UIButtonTypeSystem]; pauseButton.frame = CGRectMake(0, 0, 100, 100); pauseButton.backgroundColor = [UIColor redColor]; [self.view addSubview:pauseButton]; [pauseButton addTarget:self action:@selector(start) forControlEvents:UIControlEventTouchUpInside]; } - (void)start { if (self.isPause) { [self.task1 resume]; } else { [self.task1 cancel]; } self.isPause = !self.isPause; } - (void)testTask { self.taskArray = [NSMutableArray array]; for (int i = 1; i<=5; i++) { NSString *url = [NSString stringWithFormat:@"http://120.25.226.186:32812/resources/videos/minion_%02d.mp4", i]; HLTaskRequest *task = [HLTaskRequest request] .setDelegate(self) .setFilePath([[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:[NSString stringWithFormat:@"minion_%02d.mp4", i]]) .setCustomURL(url); [self.taskArray addObject:task]; } HLRequestGroup *group = [HLRequestGroup groupWithMode:HLRequestGroupModeChain]; group.delegate = self; [group addRequests:self.taskArray]; [group start]; } - (void)testAPI { __block int i = 0; HLRequestGroup *group = [HLRequestGroup groupWithMode:HLRequestGroupModeChain]; group.delegate = self; group.maxRequestCount = 1; self.api1 = [HLAPIRequest request] .setMethod(GET) .setPath(@"user-agent") .setDelegate(self) .setObjReformerDelegate(self) .success(^(id obj) { NSLog(@"\napi 1 --- 已回调 %@ \n----", obj); NSLog(@"%d", i++); self.api4.setParams(@{@"show_env": @(i)}); }); self.api2 = [HLAPIRequest request] .setMethod(HEAD) .setPath(@"headers") .setDelegate(self) .success(^(id obj) { NSLog(@"\napi 2 --- 已回调 %@ \n----", obj); NSLog(@"%d", i++); }); self.api3 = [HLAPIRequest request] .setMethod(GET) .setPath(@"get") .setParams(@{@"a": @(i)}) .setDelegate(self) .success(^(id obj) { NSLog(@"\napi 3 --- 已回调 %@ \n----", obj); NSLog(@"%d", i++); }); self.api4 = [HLAPIRequest request] .setMethod(POST) .setPath(@"post") .setDelegate(self) .success(^(id obj) { NSLog(@"\napi 4 --- 已回调 %@ \n----", obj); NSLog(@"%d", i++); }); self.api5 = [HLAPIRequest request] .setMethod(PATCH) .setPath(@"patch") .setDelegate(self) .success(^(id obj) { NSLog(@"\napi 5 --- 已回调 %@ \n----", obj); NSLog(@"%d", i++); }); self.api6 = [HLAPIRequest request] .setMethod(PUT) .setPath(@"put") .setDelegate(self) .success(^(id obj) { NSLog(@"\napi 6 --- 已回调 %@ \n----",obj); NSLog(@"%d", i++); }); self.api7 = [HLAPIRequest request] .setMethod(DELETE) .setPath(@"delete") .setDelegate(self) .success(^(id obj) { NSLog(@"\napi 7 --- 已回调 %@ \n----",obj); NSLog(@"%d", i++); }); // [self.api1 start]; // [self.api2 start]; // [self.api3 start]; // [self.api4 start]; // [self.api5 start]; // [self.api6 start]; // [self.api7 start]; [group addRequests:@[self.api1, self.api2, self.api3, self.api4, self.api5, self.api6, self.api7]]; [group start]; // [asyncBatch addAPIs:[NSSet setWithObjects:self.api1, self.api2, self.api3, self.api4, self.api5, self.api6, self.api7, nil]]; // [asyncBatch start]; } - (void)requestGroupAllDidFinished:(__kindof HLRequestGroup *)apiGroup { NSLog(@"apiGroupAllDidFinished"); // for (NSString *path in [HLNetworkLogger logFilePaths]) { // NSLog(@"%@", path); // } } #pragma mark - HLObjReformerProtocol - (id)reformerObject:(id)responseObject andError:(NSError *)error atRequest:(HLAPIRequest *)request { return [NSString stringWithFormat:@"我被转换了"]; } #pragma mark - HLRequestDelegate - (void)requestWillBeSent:(HLURLRequest *)request { NSString *newToken = @"获取了新token"; ((HLAPIRequest *)request) .addParams(@{@"token": newToken}) .success(^(id obj) { NSLog(@"\napi x --- 已回调 %@ \n----", obj); }); NSLog(@"\n%@---willBeSent---", request.hashKey); } - (void)requestDidSent:(HLURLRequest *)request { NSLog(@"\n%@---didSent---", request.hashKey); } #pragma mark - HLResponseDelegate - (NSArray *)observerRequests { return self.taskArray; } // 进度的回调 - (void)requestProgress:(nullable NSProgress *)progress atRequest:(nullable HLURLRequest *)request { NSLog(@"\n%@------RequestProgress--------%@\n", request.hashKey, progress); NSLog(@"%@", [NSThread currentThread]); } // 请求成功的回调 - (void)requestSucess:(nullable id)responseObject atRequest:(nullable HLURLRequest *)request { NSLog(@"\n%@------RequestSuccessDelegate\n", request.hashKey); NSLog(@"%@", [NSThread currentThread]); } // 请求失败的回调 - (void)requestFailure:(nullable NSError *)error atRequest:(nullable HLURLRequest *)request { NSLog(@"\n%@------RequestFailureDelegate------%@\n", request.hashKey, error); NSLog(@"%@", [NSThread currentThread]); } - (NSDictionary *)customInfoWithMessage:(HLDebugMessage *)message { NSMutableDictionary *dict = [NSMutableDictionary dictionary]; dict[@"Time"] = message.timeString; dict[@"RequestObject"] = [message.requestObject toDictionary]; dict[@"Response"] = [message.response toDictionary]; return [dict copy]; } - (NSDictionary *)customHeaderWithMessage:(HLNetworkLoggerConfig *)config { return @{@"AppInfo": @{@"OSVersion": [UIDevice currentDevice].systemVersion, @"DeviceType": [UIDevice currentDevice].hl_machineType, @"UDID": [UIDevice currentDevice].hl_udid, @"UUID": [UIDevice currentDevice].hl_uuid, @"MacAddressMD5": [UIDevice currentDevice].hl_macaddressMD5, @"ChannelID": config.channelID, @"AppKey": config.appKey, @"AppName": config.appName, @"AppVersion": config.appVersion, @"ServiceType": config.serviceType}}; } - (void)dealloc { [HLNetworkManager removeResponseObserver:self]; } @end ================================================ FILE: HLNetworking/main.m ================================================ // // main.m // HLNetworking // // Created by wangshiyu13 on 2016/9/22. // Copyright © 2016年 wangshiyu13. All rights reserved. // #import #import "AppDelegate.h" int main(int argc, char * argv[]) { @autoreleasepool { return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); } } ================================================ FILE: HLNetworking.podspec ================================================ Pod::Spec.new do |spec| spec.name = 'HLNetworking' spec.version = '2.0.2' spec.license = { :type => "MIT", :file => 'LICENSE' } spec.homepage = 'https://github.com/QianKun-HanLin/HLNetworking' spec.authors = {"wangshiyu13" => "wangshiyu13@163.com"} spec.summary = '基于AFNetworking的高阶网络请求管理器' spec.source = { :git => 'https://github.com/QianKun-HanLin/HLNetworking.git', :tag => spec.version, :submodules => true } spec.requires_arc = true spec.ios.deployment_target = '8.0' spec.default_subspec = 'Core' spec.resource = "HLNetworking/Source/Logger/iPhoneTypeDefine.plist" spec.subspec 'Core' do |core| core.source_files = 'HLNetworking/Source/HLNetworking.h', 'HLNetworking/Source/Generator/**/*.{h,m}', 'HLNetworking/Source/Manager/**/*.{h,m}', 'HLNetworking/Source/Engine/**/*.{h,m}', 'HLNetworking/Source/Logger/**/*.{h,m}', 'HLNetworking/Source/Config/**/*.{h,m}' core.dependency 'AFNetworking', '~> 3.1.0' end spec.subspec 'Center' do |center| center.source_files = 'HLNetworking/Source/Center/*.{h,m}' center.dependency 'HLNetworking/Core' center.dependency 'YYModel' end end ================================================ FILE: HLNetworking.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 46; objects = { /* Begin PBXBuildFile section */ CA11CB6F72D47813F2CFB2E5 /* libPods-HLNetworking.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B5A78D7A6A24AB5E8E2123F3 /* libPods-HLNetworking.a */; }; CF36274F1D9368BD00C26AAF /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = CF36274E1D9368BD00C26AAF /* main.m */; }; CF3627521D9368BD00C26AAF /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = CF3627511D9368BD00C26AAF /* AppDelegate.m */; }; CF3627551D9368BD00C26AAF /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = CF3627541D9368BD00C26AAF /* ViewController.m */; }; CF3627581D9368BD00C26AAF /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = CF3627561D9368BD00C26AAF /* Main.storyboard */; }; CF36275A1D9368BD00C26AAF /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = CF3627591D9368BD00C26AAF /* Assets.xcassets */; }; CF36275D1D9368BD00C26AAF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = CF36275B1D9368BD00C26AAF /* LaunchScreen.storyboard */; }; CF5C95681E1A336500A3380C /* HLNetworkTipsConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = CF5C95671E1A336500A3380C /* HLNetworkTipsConfig.m */; }; CF5C956B1E1A342000A3380C /* HLNetworkRequestConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = CF5C956A1E1A342000A3380C /* HLNetworkRequestConfig.m */; }; CF5C956E1E1A351600A3380C /* HLNetworkPolicyConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = CF5C956D1E1A351600A3380C /* HLNetworkPolicyConfig.m */; }; CF6BAB041E35C213003ECA28 /* HLAPIRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = CF6BAAFC1E35C213003ECA28 /* HLAPIRequest.m */; }; CF6BAB051E35C213003ECA28 /* HLURLRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = CF6BAB001E35C213003ECA28 /* HLURLRequest.m */; }; CF6BAB091E35D362003ECA28 /* HLTaskRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = CF6BAB081E35D362003ECA28 /* HLTaskRequest.m */; }; CF6BAB171E35DAC6003ECA28 /* HLRequestGroup.m in Sources */ = {isa = PBXBuildFile; fileRef = CF6BAB161E35DAC6003ECA28 /* HLRequestGroup.m */; }; CF6BAB1B1E35DC37003ECA28 /* HLNetworkEngine.m in Sources */ = {isa = PBXBuildFile; fileRef = CF6BAB1A1E35DC37003ECA28 /* HLNetworkEngine.m */; }; CF6BAB261E35DE16003ECA28 /* HLFormDataConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = CF6BAB251E35DE16003ECA28 /* HLFormDataConfig.m */; }; CF6BAB291E35DE9C003ECA28 /* HLNetworkManager.m in Sources */ = {isa = PBXBuildFile; fileRef = CF6BAB281E35DE9C003ECA28 /* HLNetworkManager.m */; }; CF6C3C7F1E351A7F0052C4DF /* NSNull+ToDictionary.m in Sources */ = {isa = PBXBuildFile; fileRef = CF6C3C7E1E351A7F0052C4DF /* NSNull+ToDictionary.m */; }; CF7005A11E1CA12200DF8E80 /* HLNetworkLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = CF7005A01E1CA12200DF8E80 /* HLNetworkLogger.m */; }; CF7005A41E1CDADD00DF8E80 /* HLNetworkLoggerConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = CF7005A31E1CDADD00DF8E80 /* HLNetworkLoggerConfig.m */; }; CF7005A71E1CE30100DF8E80 /* HLDebugMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = CF7005A61E1CE30100DF8E80 /* HLDebugMessage.m */; }; CF8B9AE61E4B7CCA00DC7AF6 /* HLTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = CF8B9AE51E4B7CCA00DC7AF6 /* HLTestCase.m */; }; CF8B9AE81E4B7D9B00DC7AF6 /* HLAPIRequestTest.m in Sources */ = {isa = PBXBuildFile; fileRef = CF8B9AE71E4B7D9B00DC7AF6 /* HLAPIRequestTest.m */; }; CF8B9B211E4BA35400DC7AF6 /* testImage.jpg in Resources */ = {isa = PBXBuildFile; fileRef = CF8B9B201E4BA35400DC7AF6 /* testImage.jpg */; }; CF8B9B241E4BA49300DC7AF6 /* HLTaskRequestTest.m in Sources */ = {isa = PBXBuildFile; fileRef = CF8B9B231E4BA49300DC7AF6 /* HLTaskRequestTest.m */; }; CF8B9B291E4BBD7600DC7AF6 /* HLRequestGroupTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CF8B9B281E4BBD7600DC7AF6 /* HLRequestGroupTests.m */; }; CF8B9B2B1E4BC33800DC7AF6 /* HLManagerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CF8B9B2A1E4BC33800DC7AF6 /* HLManagerTests.m */; }; CF8B9B2C1E4BC7D900DC7AF6 /* httpbin.org.cer in Resources */ = {isa = PBXBuildFile; fileRef = CF8B9B221E4BA35900DC7AF6 /* httpbin.org.cer */; }; CFD3864B1E1999DC001CF086 /* HLAPICenter+home.m in Sources */ = {isa = PBXBuildFile; fileRef = CFD3864A1E1999DC001CF086 /* HLAPICenter+home.m */; }; CFDCF7411D9C261B00DE1C8E /* HLNetworkConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = CFDCF72E1D9C261B00DE1C8E /* HLNetworkConfig.m */; }; CFDCF7421D9C261B00DE1C8E /* HLSecurityPolicyConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = CFDCF7301D9C261B00DE1C8E /* HLSecurityPolicyConfig.m */; }; CFDE3FE41E12220E00CDA39E /* HLAPICenter.m in Sources */ = {isa = PBXBuildFile; fileRef = CFDE3FE01E12220E00CDA39E /* HLAPICenter.m */; }; CFDE3FE51E12220E00CDA39E /* HLBaseObjReformer.m in Sources */ = {isa = PBXBuildFile; fileRef = CFDE3FE31E12220E00CDA39E /* HLBaseObjReformer.m */; }; CFE869A81E20F6BC001BE8D4 /* iPhoneTypeDefine.plist in Resources */ = {isa = PBXBuildFile; fileRef = CFE869A71E20F6BC001BE8D4 /* iPhoneTypeDefine.plist */; }; CFE869AB1E20FA9F001BE8D4 /* UIDevice+deviceInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = CFE869AA1E20FA9F001BE8D4 /* UIDevice+deviceInfo.m */; }; CFF1A88D1E22256F00767B35 /* HLURLResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = CFF1A8891E22256F00767B35 /* HLURLResponse.m */; }; CFF1A88E1E22256F00767B35 /* HLURLResult.m in Sources */ = {isa = PBXBuildFile; fileRef = CFF1A88C1E22256F00767B35 /* HLURLResult.m */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ CF8B9ADC1E4B69B500DC7AF6 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = CF3627421D9368BD00C26AAF /* Project object */; proxyType = 1; remoteGlobalIDString = CF3627491D9368BD00C26AAF; remoteInfo = HLNetworking; }; /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ 0E4E388C48FBF73DFFCF16AD /* libPods-HLNetworkingTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-HLNetworkingTests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 3D14D0F53EFCAA4AF53EEE33 /* Pods-HLNetworking.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-HLNetworking.release.xcconfig"; path = "Pods/Target Support Files/Pods-HLNetworking/Pods-HLNetworking.release.xcconfig"; sourceTree = ""; }; 7181179E3FED125878C5BA34 /* Pods-HLNetworking.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-HLNetworking.debug.xcconfig"; path = "Pods/Target Support Files/Pods-HLNetworking/Pods-HLNetworking.debug.xcconfig"; sourceTree = ""; }; B5A78D7A6A24AB5E8E2123F3 /* libPods-HLNetworking.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-HLNetworking.a"; sourceTree = BUILT_PRODUCTS_DIR; }; CF36274A1D9368BD00C26AAF /* HLNetworking.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = HLNetworking.app; sourceTree = BUILT_PRODUCTS_DIR; }; CF36274E1D9368BD00C26AAF /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; CF3627501D9368BD00C26AAF /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; CF3627511D9368BD00C26AAF /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; CF3627531D9368BD00C26AAF /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; CF3627541D9368BD00C26AAF /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; CF3627571D9368BD00C26AAF /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; CF3627591D9368BD00C26AAF /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; CF36275C1D9368BD00C26AAF /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; CF36275E1D9368BD00C26AAF /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; CF5C95661E1A336500A3380C /* HLNetworkTipsConfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HLNetworkTipsConfig.h; sourceTree = ""; }; CF5C95671E1A336500A3380C /* HLNetworkTipsConfig.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HLNetworkTipsConfig.m; sourceTree = ""; }; CF5C95691E1A342000A3380C /* HLNetworkRequestConfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HLNetworkRequestConfig.h; sourceTree = ""; }; CF5C956A1E1A342000A3380C /* HLNetworkRequestConfig.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HLNetworkRequestConfig.m; sourceTree = ""; }; CF5C956C1E1A351600A3380C /* HLNetworkPolicyConfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HLNetworkPolicyConfig.h; sourceTree = ""; }; CF5C956D1E1A351600A3380C /* HLNetworkPolicyConfig.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HLNetworkPolicyConfig.m; sourceTree = ""; }; CF6BAAFB1E35C213003ECA28 /* HLAPIRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HLAPIRequest.h; sourceTree = ""; }; CF6BAAFC1E35C213003ECA28 /* HLAPIRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HLAPIRequest.m; sourceTree = ""; }; CF6BAAFF1E35C213003ECA28 /* HLURLRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HLURLRequest.h; sourceTree = ""; }; CF6BAB001E35C213003ECA28 /* HLURLRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HLURLRequest.m; sourceTree = ""; }; CF6BAB011E35C213003ECA28 /* HLURLRequest_InternalParams.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HLURLRequest_InternalParams.h; sourceTree = ""; }; CF6BAB061E35C24D003ECA28 /* HLAPIRequest_InternalParams.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HLAPIRequest_InternalParams.h; sourceTree = ""; }; CF6BAB071E35D362003ECA28 /* HLTaskRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HLTaskRequest.h; sourceTree = ""; }; CF6BAB081E35D362003ECA28 /* HLTaskRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HLTaskRequest.m; sourceTree = ""; }; CF6BAB0A1E35D3B8003ECA28 /* HLTaskRequest_InternalParams.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HLTaskRequest_InternalParams.h; sourceTree = ""; }; CF6BAB151E35DAC6003ECA28 /* HLRequestGroup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HLRequestGroup.h; sourceTree = ""; }; CF6BAB161E35DAC6003ECA28 /* HLRequestGroup.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HLRequestGroup.m; sourceTree = ""; }; CF6BAB191E35DC37003ECA28 /* HLNetworkEngine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HLNetworkEngine.h; sourceTree = ""; }; CF6BAB1A1E35DC37003ECA28 /* HLNetworkEngine.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HLNetworkEngine.m; sourceTree = ""; }; CF6BAB241E35DE16003ECA28 /* HLFormDataConfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HLFormDataConfig.h; sourceTree = ""; }; CF6BAB251E35DE16003ECA28 /* HLFormDataConfig.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HLFormDataConfig.m; sourceTree = ""; }; CF6BAB271E35DE9C003ECA28 /* HLNetworkManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HLNetworkManager.h; sourceTree = ""; }; CF6BAB281E35DE9C003ECA28 /* HLNetworkManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HLNetworkManager.m; sourceTree = ""; }; CF6C3C751E34F9200052C4DF /* HLNetworkConst.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HLNetworkConst.h; sourceTree = ""; }; CF6C3C7D1E351A7F0052C4DF /* NSNull+ToDictionary.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSNull+ToDictionary.h"; sourceTree = ""; }; CF6C3C7E1E351A7F0052C4DF /* NSNull+ToDictionary.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSNull+ToDictionary.m"; sourceTree = ""; }; CF70059F1E1CA12200DF8E80 /* HLNetworkLogger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HLNetworkLogger.h; sourceTree = ""; }; CF7005A01E1CA12200DF8E80 /* HLNetworkLogger.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HLNetworkLogger.m; sourceTree = ""; }; CF7005A21E1CDADD00DF8E80 /* HLNetworkLoggerConfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HLNetworkLoggerConfig.h; sourceTree = ""; }; CF7005A31E1CDADD00DF8E80 /* HLNetworkLoggerConfig.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HLNetworkLoggerConfig.m; sourceTree = ""; }; CF7005A51E1CE30100DF8E80 /* HLDebugMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HLDebugMessage.h; sourceTree = ""; }; CF7005A61E1CE30100DF8E80 /* HLDebugMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HLDebugMessage.m; sourceTree = ""; }; CF7326AD1DE729D100EDA1CE /* HLNetworkMacro.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HLNetworkMacro.h; sourceTree = ""; }; CF8B9AD71E4B69B500DC7AF6 /* HLNetworkingTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = HLNetworkingTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; CF8B9ADB1E4B69B500DC7AF6 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; CF8B9AE41E4B7CCA00DC7AF6 /* HLTestCase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HLTestCase.h; sourceTree = ""; }; CF8B9AE51E4B7CCA00DC7AF6 /* HLTestCase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HLTestCase.m; sourceTree = ""; }; CF8B9AE71E4B7D9B00DC7AF6 /* HLAPIRequestTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HLAPIRequestTest.m; sourceTree = ""; }; CF8B9B201E4BA35400DC7AF6 /* testImage.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = testImage.jpg; sourceTree = ""; }; CF8B9B221E4BA35900DC7AF6 /* httpbin.org.cer */ = {isa = PBXFileReference; lastKnownFileType = file; path = httpbin.org.cer; sourceTree = ""; }; CF8B9B231E4BA49300DC7AF6 /* HLTaskRequestTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HLTaskRequestTest.m; sourceTree = ""; }; CF8B9B281E4BBD7600DC7AF6 /* HLRequestGroupTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HLRequestGroupTests.m; sourceTree = ""; }; CF8B9B2A1E4BC33800DC7AF6 /* HLManagerTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HLManagerTests.m; sourceTree = ""; }; CFD386491E1999DC001CF086 /* HLAPICenter+home.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "HLAPICenter+home.h"; sourceTree = ""; }; CFD3864A1E1999DC001CF086 /* HLAPICenter+home.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "HLAPICenter+home.m"; sourceTree = ""; }; CFDCF72D1D9C261B00DE1C8E /* HLNetworkConfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HLNetworkConfig.h; sourceTree = ""; }; CFDCF72E1D9C261B00DE1C8E /* HLNetworkConfig.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HLNetworkConfig.m; sourceTree = ""; }; CFDCF72F1D9C261B00DE1C8E /* HLSecurityPolicyConfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HLSecurityPolicyConfig.h; sourceTree = ""; }; CFDCF7301D9C261B00DE1C8E /* HLSecurityPolicyConfig.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HLSecurityPolicyConfig.m; sourceTree = ""; }; CFDCF7311D9C261B00DE1C8E /* HLNetworking.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HLNetworking.h; sourceTree = ""; }; CFDE3FDF1E12220E00CDA39E /* HLAPICenter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HLAPICenter.h; sourceTree = ""; }; CFDE3FE01E12220E00CDA39E /* HLAPICenter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HLAPICenter.m; sourceTree = ""; }; CFDE3FE11E12220E00CDA39E /* HLAPIMacro.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HLAPIMacro.h; sourceTree = ""; }; CFDE3FE21E12220E00CDA39E /* HLBaseObjReformer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HLBaseObjReformer.h; sourceTree = ""; }; CFDE3FE31E12220E00CDA39E /* HLBaseObjReformer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HLBaseObjReformer.m; sourceTree = ""; }; CFDE3FE61E1222A900CDA39E /* HLNetworking.podspec */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = HLNetworking.podspec; sourceTree = SOURCE_ROOT; }; CFDE3FE81E1222CB00CDA39E /* LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE; sourceTree = SOURCE_ROOT; }; CFDE3FE91E1222CB00CDA39E /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = SOURCE_ROOT; }; CFE869A71E20F6BC001BE8D4 /* iPhoneTypeDefine.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = iPhoneTypeDefine.plist; sourceTree = ""; }; CFE869A91E20FA9F001BE8D4 /* UIDevice+deviceInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIDevice+deviceInfo.h"; sourceTree = ""; }; CFE869AA1E20FA9F001BE8D4 /* UIDevice+deviceInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIDevice+deviceInfo.m"; sourceTree = ""; }; CFF1A8881E22256F00767B35 /* HLURLResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HLURLResponse.h; sourceTree = ""; }; CFF1A8891E22256F00767B35 /* HLURLResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HLURLResponse.m; sourceTree = ""; }; CFF1A88B1E22256F00767B35 /* HLURLResult.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HLURLResult.h; sourceTree = ""; }; CFF1A88C1E22256F00767B35 /* HLURLResult.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HLURLResult.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ CF3627471D9368BD00C26AAF /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( CA11CB6F72D47813F2CFB2E5 /* libPods-HLNetworking.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; CF8B9AD41E4B69B500DC7AF6 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 8A8E0E7C6E12EA9397609AAC /* Frameworks */ = { isa = PBXGroup; children = ( B5A78D7A6A24AB5E8E2123F3 /* libPods-HLNetworking.a */, 0E4E388C48FBF73DFFCF16AD /* libPods-HLNetworkingTests.a */, ); name = Frameworks; sourceTree = ""; }; CF3627411D9368BD00C26AAF = { isa = PBXGroup; children = ( CF36274C1D9368BD00C26AAF /* HLNetworking */, CF8B9AD81E4B69B500DC7AF6 /* HLNetworkingTests */, CF36274B1D9368BD00C26AAF /* Products */, F112EDD6A5BC41CD0E259D05 /* Pods */, 8A8E0E7C6E12EA9397609AAC /* Frameworks */, ); sourceTree = ""; }; CF36274B1D9368BD00C26AAF /* Products */ = { isa = PBXGroup; children = ( CF36274A1D9368BD00C26AAF /* HLNetworking.app */, CF8B9AD71E4B69B500DC7AF6 /* HLNetworkingTests.xctest */, ); name = Products; sourceTree = ""; }; CF36274C1D9368BD00C26AAF /* HLNetworking */ = { isa = PBXGroup; children = ( CF54B9BA1DEC429700CEEE8D /* Podspec */, CF3627641D9368CD00C26AAF /* Source */, CF3627501D9368BD00C26AAF /* AppDelegate.h */, CF3627511D9368BD00C26AAF /* AppDelegate.m */, CF3627531D9368BD00C26AAF /* ViewController.h */, CF3627541D9368BD00C26AAF /* ViewController.m */, CFD386491E1999DC001CF086 /* HLAPICenter+home.h */, CFD3864A1E1999DC001CF086 /* HLAPICenter+home.m */, CF3627561D9368BD00C26AAF /* Main.storyboard */, CF3627591D9368BD00C26AAF /* Assets.xcassets */, CF36275B1D9368BD00C26AAF /* LaunchScreen.storyboard */, CF36275E1D9368BD00C26AAF /* Info.plist */, CF36274D1D9368BD00C26AAF /* Supporting Files */, ); path = HLNetworking; sourceTree = ""; }; CF36274D1D9368BD00C26AAF /* Supporting Files */ = { isa = PBXGroup; children = ( CF36274E1D9368BD00C26AAF /* main.m */, ); name = "Supporting Files"; sourceTree = ""; }; CF3627641D9368CD00C26AAF /* Source */ = { isa = PBXGroup; children = ( CF6BAB1D1E35DDE3003ECA28 /* Manager */, CF6BAB181E35DC37003ECA28 /* Engine */, CFDCF72A1D9C261B00DE1C8E /* Config */, CFF1A8851E22254B00767B35 /* Generator */, CF70059E1E1CA0CF00DF8E80 /* Logger */, CFDE3FDE1E12220E00CDA39E /* Center */, CFDCF7311D9C261B00DE1C8E /* HLNetworking.h */, ); path = Source; sourceTree = ""; }; CF54B9BA1DEC429700CEEE8D /* Podspec */ = { isa = PBXGroup; children = ( CFDE3FE81E1222CB00CDA39E /* LICENSE */, CFDE3FE91E1222CB00CDA39E /* README.md */, CFDE3FE61E1222A900CDA39E /* HLNetworking.podspec */, ); name = Podspec; sourceTree = ""; }; CF6BAAE41E35B57B003ECA28 /* Request */ = { isa = PBXGroup; children = ( CF6BAB0B1E35DA10003ECA28 /* Group */, CF6BAB031E35C213003ECA28 /* Task */, CF6BAAFA1E35C213003ECA28 /* API */, CF6BAAFE1E35C213003ECA28 /* Base */, ); path = Request; sourceTree = ""; }; CF6BAAFA1E35C213003ECA28 /* API */ = { isa = PBXGroup; children = ( CF6BAAFB1E35C213003ECA28 /* HLAPIRequest.h */, CF6BAAFC1E35C213003ECA28 /* HLAPIRequest.m */, CF6BAB061E35C24D003ECA28 /* HLAPIRequest_InternalParams.h */, ); path = API; sourceTree = ""; }; CF6BAAFE1E35C213003ECA28 /* Base */ = { isa = PBXGroup; children = ( CF6BAAFF1E35C213003ECA28 /* HLURLRequest.h */, CF6BAB001E35C213003ECA28 /* HLURLRequest.m */, CF6BAB011E35C213003ECA28 /* HLURLRequest_InternalParams.h */, ); path = Base; sourceTree = ""; }; CF6BAB031E35C213003ECA28 /* Task */ = { isa = PBXGroup; children = ( CF6BAB071E35D362003ECA28 /* HLTaskRequest.h */, CF6BAB081E35D362003ECA28 /* HLTaskRequest.m */, CF6BAB0A1E35D3B8003ECA28 /* HLTaskRequest_InternalParams.h */, ); path = Task; sourceTree = ""; }; CF6BAB0B1E35DA10003ECA28 /* Group */ = { isa = PBXGroup; children = ( CF6BAB151E35DAC6003ECA28 /* HLRequestGroup.h */, CF6BAB161E35DAC6003ECA28 /* HLRequestGroup.m */, ); path = Group; sourceTree = ""; }; CF6BAB181E35DC37003ECA28 /* Engine */ = { isa = PBXGroup; children = ( CF6BAB191E35DC37003ECA28 /* HLNetworkEngine.h */, CF6BAB1A1E35DC37003ECA28 /* HLNetworkEngine.m */, ); path = Engine; sourceTree = ""; }; CF6BAB1D1E35DDE3003ECA28 /* Manager */ = { isa = PBXGroup; children = ( CF6BAB271E35DE9C003ECA28 /* HLNetworkManager.h */, CF6BAB281E35DE9C003ECA28 /* HLNetworkManager.m */, ); path = Manager; sourceTree = ""; }; CF70059E1E1CA0CF00DF8E80 /* Logger */ = { isa = PBXGroup; children = ( CFE869A71E20F6BC001BE8D4 /* iPhoneTypeDefine.plist */, CF7005A51E1CE30100DF8E80 /* HLDebugMessage.h */, CF7005A61E1CE30100DF8E80 /* HLDebugMessage.m */, CF6C3C7D1E351A7F0052C4DF /* NSNull+ToDictionary.h */, CF6C3C7E1E351A7F0052C4DF /* NSNull+ToDictionary.m */, CF70059F1E1CA12200DF8E80 /* HLNetworkLogger.h */, CF7005A01E1CA12200DF8E80 /* HLNetworkLogger.m */, CF7005A21E1CDADD00DF8E80 /* HLNetworkLoggerConfig.h */, CF7005A31E1CDADD00DF8E80 /* HLNetworkLoggerConfig.m */, CFE869A91E20FA9F001BE8D4 /* UIDevice+deviceInfo.h */, CFE869AA1E20FA9F001BE8D4 /* UIDevice+deviceInfo.m */, ); path = Logger; sourceTree = ""; }; CF8B9AD81E4B69B500DC7AF6 /* HLNetworkingTests */ = { isa = PBXGroup; children = ( CF8B9B221E4BA35900DC7AF6 /* httpbin.org.cer */, CF8B9B201E4BA35400DC7AF6 /* testImage.jpg */, CF8B9AE41E4B7CCA00DC7AF6 /* HLTestCase.h */, CF8B9AE51E4B7CCA00DC7AF6 /* HLTestCase.m */, CF8B9AE71E4B7D9B00DC7AF6 /* HLAPIRequestTest.m */, CF8B9B231E4BA49300DC7AF6 /* HLTaskRequestTest.m */, CF8B9B281E4BBD7600DC7AF6 /* HLRequestGroupTests.m */, CF8B9B2A1E4BC33800DC7AF6 /* HLManagerTests.m */, CF8B9ADB1E4B69B500DC7AF6 /* Info.plist */, ); path = HLNetworkingTests; sourceTree = ""; }; CFDCF72A1D9C261B00DE1C8E /* Config */ = { isa = PBXGroup; children = ( CF6BAB241E35DE16003ECA28 /* HLFormDataConfig.h */, CF6BAB251E35DE16003ECA28 /* HLFormDataConfig.m */, CFDCF72D1D9C261B00DE1C8E /* HLNetworkConfig.h */, CFDCF72E1D9C261B00DE1C8E /* HLNetworkConfig.m */, CF5C95661E1A336500A3380C /* HLNetworkTipsConfig.h */, CF5C95671E1A336500A3380C /* HLNetworkTipsConfig.m */, CF5C95691E1A342000A3380C /* HLNetworkRequestConfig.h */, CF5C956A1E1A342000A3380C /* HLNetworkRequestConfig.m */, CF5C956C1E1A351600A3380C /* HLNetworkPolicyConfig.h */, CF5C956D1E1A351600A3380C /* HLNetworkPolicyConfig.m */, CFDCF72F1D9C261B00DE1C8E /* HLSecurityPolicyConfig.h */, CFDCF7301D9C261B00DE1C8E /* HLSecurityPolicyConfig.m */, CF7326AD1DE729D100EDA1CE /* HLNetworkMacro.h */, CF6C3C751E34F9200052C4DF /* HLNetworkConst.h */, ); path = Config; sourceTree = ""; }; CFDE3FDE1E12220E00CDA39E /* Center */ = { isa = PBXGroup; children = ( CFDE3FDF1E12220E00CDA39E /* HLAPICenter.h */, CFDE3FE01E12220E00CDA39E /* HLAPICenter.m */, CFDE3FE11E12220E00CDA39E /* HLAPIMacro.h */, CFDE3FE21E12220E00CDA39E /* HLBaseObjReformer.h */, CFDE3FE31E12220E00CDA39E /* HLBaseObjReformer.m */, ); path = Center; sourceTree = ""; }; CFF1A8851E22254B00767B35 /* Generator */ = { isa = PBXGroup; children = ( CF6BAAE41E35B57B003ECA28 /* Request */, CFF1A8871E22256F00767B35 /* Response */, CFF1A88A1E22256F00767B35 /* Result */, ); path = Generator; sourceTree = ""; }; CFF1A8871E22256F00767B35 /* Response */ = { isa = PBXGroup; children = ( CFF1A8881E22256F00767B35 /* HLURLResponse.h */, CFF1A8891E22256F00767B35 /* HLURLResponse.m */, ); path = Response; sourceTree = ""; }; CFF1A88A1E22256F00767B35 /* Result */ = { isa = PBXGroup; children = ( CFF1A88B1E22256F00767B35 /* HLURLResult.h */, CFF1A88C1E22256F00767B35 /* HLURLResult.m */, ); path = Result; sourceTree = ""; }; F112EDD6A5BC41CD0E259D05 /* Pods */ = { isa = PBXGroup; children = ( 7181179E3FED125878C5BA34 /* Pods-HLNetworking.debug.xcconfig */, 3D14D0F53EFCAA4AF53EEE33 /* Pods-HLNetworking.release.xcconfig */, ); name = Pods; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ CF3627491D9368BD00C26AAF /* HLNetworking */ = { isa = PBXNativeTarget; buildConfigurationList = CF3627611D9368BD00C26AAF /* Build configuration list for PBXNativeTarget "HLNetworking" */; buildPhases = ( EFE9F6F619AF648AA951BFC1 /* [CP] Check Pods Manifest.lock */, CF3627461D9368BD00C26AAF /* Sources */, CF3627471D9368BD00C26AAF /* Frameworks */, CF3627481D9368BD00C26AAF /* Resources */, A10C11870C746AAFCB3CECBA /* [CP] Embed Pods Frameworks */, E3E05E733EC1F1F58A931032 /* [CP] Copy Pods Resources */, ); buildRules = ( ); dependencies = ( ); name = HLNetworking; productName = HLNetworking; productReference = CF36274A1D9368BD00C26AAF /* HLNetworking.app */; productType = "com.apple.product-type.application"; }; CF8B9AD61E4B69B500DC7AF6 /* HLNetworkingTests */ = { isa = PBXNativeTarget; buildConfigurationList = CF8B9AE01E4B69B500DC7AF6 /* Build configuration list for PBXNativeTarget "HLNetworkingTests" */; buildPhases = ( CF8B9AD31E4B69B500DC7AF6 /* Sources */, CF8B9AD41E4B69B500DC7AF6 /* Frameworks */, CF8B9AD51E4B69B500DC7AF6 /* Resources */, ); buildRules = ( ); dependencies = ( CF8B9ADD1E4B69B500DC7AF6 /* PBXTargetDependency */, ); name = HLNetworkingTests; productName = HLNetworkingTests; productReference = CF8B9AD71E4B69B500DC7AF6 /* HLNetworkingTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ CF3627421D9368BD00C26AAF /* Project object */ = { isa = PBXProject; attributes = { LastUpgradeCheck = 0810; ORGANIZATIONNAME = wangshiyu13; TargetAttributes = { CF3627491D9368BD00C26AAF = { CreatedOnToolsVersion = 8.0; DevelopmentTeam = 5TJBR4D2AC; ProvisioningStyle = Automatic; }; CF8B9AD61E4B69B500DC7AF6 = { CreatedOnToolsVersion = 8.2.1; ProvisioningStyle = Automatic; TestTargetID = CF3627491D9368BD00C26AAF; }; }; }; buildConfigurationList = CF3627451D9368BD00C26AAF /* Build configuration list for PBXProject "HLNetworking" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( en, Base, ); mainGroup = CF3627411D9368BD00C26AAF; productRefGroup = CF36274B1D9368BD00C26AAF /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( CF3627491D9368BD00C26AAF /* HLNetworking */, CF8B9AD61E4B69B500DC7AF6 /* HLNetworkingTests */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ CF3627481D9368BD00C26AAF /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( CFE869A81E20F6BC001BE8D4 /* iPhoneTypeDefine.plist in Resources */, CF36275D1D9368BD00C26AAF /* LaunchScreen.storyboard in Resources */, CF36275A1D9368BD00C26AAF /* Assets.xcassets in Resources */, CF3627581D9368BD00C26AAF /* Main.storyboard in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; CF8B9AD51E4B69B500DC7AF6 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( CF8B9B2C1E4BC7D900DC7AF6 /* httpbin.org.cer in Resources */, CF8B9B211E4BA35400DC7AF6 /* testImage.jpg in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ A10C11870C746AAFCB3CECBA /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); name = "[CP] Embed Pods Frameworks"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-HLNetworking/Pods-HLNetworking-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; E3E05E733EC1F1F58A931032 /* [CP] Copy Pods Resources */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); name = "[CP] Copy Pods Resources"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-HLNetworking/Pods-HLNetworking-resources.sh\"\n"; showEnvVarsInLog = 0; }; EFE9F6F619AF648AA951BFC1 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); name = "[CP] Check Pods Manifest.lock"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n"; showEnvVarsInLog = 0; }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ CF3627461D9368BD00C26AAF /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( CFD3864B1E1999DC001CF086 /* HLAPICenter+home.m in Sources */, CFE869AB1E20FA9F001BE8D4 /* UIDevice+deviceInfo.m in Sources */, CFDCF7421D9C261B00DE1C8E /* HLSecurityPolicyConfig.m in Sources */, CF6BAB041E35C213003ECA28 /* HLAPIRequest.m in Sources */, CF5C95681E1A336500A3380C /* HLNetworkTipsConfig.m in Sources */, CFF1A88E1E22256F00767B35 /* HLURLResult.m in Sources */, CF5C956E1E1A351600A3380C /* HLNetworkPolicyConfig.m in Sources */, CF3627551D9368BD00C26AAF /* ViewController.m in Sources */, CF5C956B1E1A342000A3380C /* HLNetworkRequestConfig.m in Sources */, CF7005A11E1CA12200DF8E80 /* HLNetworkLogger.m in Sources */, CF6BAB1B1E35DC37003ECA28 /* HLNetworkEngine.m in Sources */, CF7005A41E1CDADD00DF8E80 /* HLNetworkLoggerConfig.m in Sources */, CF6BAB091E35D362003ECA28 /* HLTaskRequest.m in Sources */, CF7005A71E1CE30100DF8E80 /* HLDebugMessage.m in Sources */, CF6BAB051E35C213003ECA28 /* HLURLRequest.m in Sources */, CFDCF7411D9C261B00DE1C8E /* HLNetworkConfig.m in Sources */, CF3627521D9368BD00C26AAF /* AppDelegate.m in Sources */, CFDE3FE41E12220E00CDA39E /* HLAPICenter.m in Sources */, CFDE3FE51E12220E00CDA39E /* HLBaseObjReformer.m in Sources */, CF6BAB291E35DE9C003ECA28 /* HLNetworkManager.m in Sources */, CF6BAB261E35DE16003ECA28 /* HLFormDataConfig.m in Sources */, CF6C3C7F1E351A7F0052C4DF /* NSNull+ToDictionary.m in Sources */, CFF1A88D1E22256F00767B35 /* HLURLResponse.m in Sources */, CF6BAB171E35DAC6003ECA28 /* HLRequestGroup.m in Sources */, CF36274F1D9368BD00C26AAF /* main.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; CF8B9AD31E4B69B500DC7AF6 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( CF8B9B2B1E4BC33800DC7AF6 /* HLManagerTests.m in Sources */, CF8B9AE81E4B7D9B00DC7AF6 /* HLAPIRequestTest.m in Sources */, CF8B9B291E4BBD7600DC7AF6 /* HLRequestGroupTests.m in Sources */, CF8B9B241E4BA49300DC7AF6 /* HLTaskRequestTest.m in Sources */, CF8B9AE61E4B7CCA00DC7AF6 /* HLTestCase.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ CF8B9ADD1E4B69B500DC7AF6 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = CF3627491D9368BD00C26AAF /* HLNetworking */; targetProxy = CF8B9ADC1E4B69B500DC7AF6 /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ CF3627561D9368BD00C26AAF /* Main.storyboard */ = { isa = PBXVariantGroup; children = ( CF3627571D9368BD00C26AAF /* Base */, ); name = Main.storyboard; sourceTree = ""; }; CF36275B1D9368BD00C26AAF /* LaunchScreen.storyboard */ = { isa = PBXVariantGroup; children = ( CF36275C1D9368BD00C26AAF /* Base */, ); name = LaunchScreen.storyboard; sourceTree = ""; }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ CF36275F1D9368BD00C26AAF /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_SUSPICIOUS_MOVES = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 10.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; }; CF3627601D9368BD00C26AAF /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_SUSPICIOUS_MOVES = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 10.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; name = Release; }; CF3627621D9368BD00C26AAF /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 7181179E3FED125878C5BA34 /* Pods-HLNetworking.debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; DEVELOPMENT_TEAM = 5TJBR4D2AC; HEADER_SEARCH_PATHS = "$(inherited)"; INFOPLIST_FILE = HLNetworking/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LIBRARY_SEARCH_PATHS = "$(inherited)"; OTHER_CFLAGS = "$(inherited)"; OTHER_LDFLAGS = ( "$(inherited)", "-framework", "\"CoreFoundation\"", "-framework", "\"CoreGraphics\"", "-framework", "\"Foundation\"", "-framework", "\"MobileCoreServices\"", "-framework", "\"Security\"", "-framework", "\"SystemConfiguration\"", ); PRODUCT_BUNDLE_IDENTIFIER = com.qkhl.HLNetworking; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; }; CF3627631D9368BD00C26AAF /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = 3D14D0F53EFCAA4AF53EEE33 /* Pods-HLNetworking.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; DEVELOPMENT_TEAM = 5TJBR4D2AC; HEADER_SEARCH_PATHS = "$(inherited)"; INFOPLIST_FILE = HLNetworking/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LIBRARY_SEARCH_PATHS = "$(inherited)"; OTHER_CFLAGS = "$(inherited)"; OTHER_LDFLAGS = ( "$(inherited)", "-framework", "\"CoreFoundation\"", "-framework", "\"CoreGraphics\"", "-framework", "\"Foundation\"", "-framework", "\"MobileCoreServices\"", "-framework", "\"Security\"", "-framework", "\"SystemConfiguration\"", ); PRODUCT_BUNDLE_IDENTIFIER = com.qkhl.HLNetworking; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release; }; CF8B9ADE1E4B69B500DC7AF6 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; INFOPLIST_FILE = HLNetworkingTests/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 10.2; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.-wangshiyu13.HLNetworkingTests"; PRODUCT_NAME = "$(TARGET_NAME)"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/HLNetworking.app/HLNetworking"; }; name = Debug; }; CF8B9ADF1E4B69B500DC7AF6 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; INFOPLIST_FILE = HLNetworkingTests/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 10.2; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.-wangshiyu13.HLNetworkingTests"; PRODUCT_NAME = "$(TARGET_NAME)"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/HLNetworking.app/HLNetworking"; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ CF3627451D9368BD00C26AAF /* Build configuration list for PBXProject "HLNetworking" */ = { isa = XCConfigurationList; buildConfigurations = ( CF36275F1D9368BD00C26AAF /* Debug */, CF3627601D9368BD00C26AAF /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; CF3627611D9368BD00C26AAF /* Build configuration list for PBXNativeTarget "HLNetworking" */ = { isa = XCConfigurationList; buildConfigurations = ( CF3627621D9368BD00C26AAF /* Debug */, CF3627631D9368BD00C26AAF /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; CF8B9AE01E4B69B500DC7AF6 /* Build configuration list for PBXNativeTarget "HLNetworkingTests" */ = { isa = XCConfigurationList; buildConfigurations = ( CF8B9ADE1E4B69B500DC7AF6 /* Debug */, CF8B9ADF1E4B69B500DC7AF6 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = CF3627421D9368BD00C26AAF /* Project object */; } ================================================ FILE: HLNetworking.xcodeproj/project.xcworkspace/contents.xcworkspacedata ================================================ ================================================ FILE: HLNetworking.xcodeproj/xcshareddata/xcschemes/HLNetworking.xcscheme ================================================ ================================================ FILE: HLNetworkingTests/HLAPIRequestTest.m ================================================ // // HLAPIRequestTest.m // HLNetworking // // Created by wangshiyu13 on 2017/2/9. // Copyright © 2017年 wangshiyu13. All rights reserved. // #import "HLTestCase.h" @interface HLAPIRequestTest : HLTestCase @end @implementation HLAPIRequestTest - (void)setUp { [super setUp]; } - (void)tearDown { [super tearDown]; } - (void)testGET { XCTestExpectation *expectation = [self expectationWithDescription:@"GET请求失败"]; [[HLAPIRequest request] .setMethod(GET) .setPath(@"get") .success(^(id result){ XCTAssertNotNil(result); [expectation fulfill]; }) .failure(^(NSError *error){ XCTAssertNil(error); }) start]; [self waitForExpectationsWithCommonTimeout]; } - (void)testGETWithParameters { XCTestExpectation *expectation = [self expectationWithDescription:@"GET请求失败"]; [[HLAPIRequest request] .setMethod(GET) .setCustomURL(@"https://httpbin.org/get") .setParams(@{@"key": @"value"}) .enableDefaultParams(NO) .success(^(id result){ XCTAssertTrue([result[@"args"][@"key"] isEqualToString:@"value"]); [expectation fulfill]; }).failure(^(NSError *error){ XCTAssertNil(error); }) start]; [self waitForExpectationsWithCommonTimeout]; } - (void)testPOSTWithForm { XCTestExpectation *expectation = [self expectationWithDescription:@"POST请求失败"]; [[HLAPIRequest request] .setMethod(POST) .setBaseURL(@"https://httpbin.org/") .setPath(@"post") .setParams(@{@"key": @"value"}) .setRequestType(RequestHTTP) .setResponseType(ResponseJSON) .success(^(id result){ XCTAssertTrue([result[@"form"][@"key"] isEqualToString:@"value"]); XCTAssertTrue([result[@"form"][@"global_param"] isEqualToString:@"global param value"]); XCTAssertTrue([result[@"headers"][@"Global-Header"] isEqualToString:@"global header value"]); [expectation fulfill]; }).failure(^(NSError *error){ XCTAssertNil(error); }) start]; [self waitForExpectationsWithCommonTimeout]; } - (void)testPOSTWithJSON { XCTestExpectation *expectation = [self expectationWithDescription:@"POST请求失败"]; [[HLAPIRequest request] .setMethod(POST) .setBaseURL(@"https://httpbin.org/") .setPath(@"post") .setParams(@{@"key": @"value"}) .setRequestType(RequestJSON) .success(^(id result){ XCTAssertTrue([result[@"json"][@"key"] isEqualToString:@"value"]); XCTAssertTrue([result[@"json"][@"global_param"] isEqualToString:@"global param value"]); XCTAssertTrue([result[@"headers"][@"Global-Header"] isEqualToString:@"global header value"]); [expectation fulfill]; }).failure(^(NSError *error){ XCTAssertNil(error); }) start]; [self waitForExpectationsWithCommonTimeout]; } - (void)testPOSTWithPlist { XCTestExpectation *expectation = [self expectationWithDescription:@"POST请求失败"]; [[HLAPIRequest request] .setMethod(POST) .setHeader(nil) .enableDefaultParams(NO) .setBaseURL(@"https://httpbin.org/") .setPath(@"post") .setParams(@{@"key1": @"value1", @"key2": @"value2"}) .setRequestType(RequestPlist) .success(^(id result){ NSString *data = @"\n\n\n\n\tkey1\n\tvalue1\n\tkey2\n\tvalue2\n\n\n"; XCTAssertTrue([result[@"data"] isEqualToString:data]); [expectation fulfill]; }).failure(^(NSError *error){ XCTAssertNil(error); }) start]; [self waitForExpectationsWithCommonTimeout]; } - (void)testPOSTWithFormData { XCTestExpectation *expectation1 = [self expectationWithDescription:@"POST formdata请求不成功"]; XCTestExpectation *expectation2 = [self expectationWithDescription:@"上传进度回调失败"]; // `NSData` form data. NSString *path = [[NSBundle bundleForClass:[self class]] pathForResource:@"testImage" ofType:@"jpg"]; UIImage *image = [UIImage imageWithContentsOfFile:path]; // NSData *fileData = UIImageJPEGRepresentation(image, 1.0); // `NSURL` form data. //NSString *path = [NSHomeDirectory() stringByAppendingString:@"/Documents/testImage.jpg"]; //NSURL *fileURL = [NSURL fileURLWithPath:path isDirectory:NO]; //NSError *error = nil; [[HLAPIRequest request] .setMethod(POST) .setHeader(nil) .enableDefaultParams(NO) .setBaseURL(@"https://httpbin.org/") .setPath(@"post") .setRequestType(RequestPlist) .formData(/** [HLFormDataConfig configWithData:fileData name:@"image" fileName:@"tempImage.jpg" mimeType:@"image/jpeg"] [HLFormDataConfig configWithFileURL:fileURL name:@"image" fileName:@"tempImage.jpg" mimeType:@"image/jpeg" error:&error] */ [HLFormDataConfig configWithImage:image name:@"image" fileName:@"tempImage.jpg" quality:1.0]) .progress(^(NSProgress *proc){ if (proc.fractionCompleted == 1.0) { [expectation2 fulfill]; } }) .success(^(id result){ XCTAssertNotNil(result); XCTAssertTrue(result[@"files"][@"image"] != nil); [expectation1 fulfill]; }).failure(^(NSError *error){ XCTAssertNil(error); }) start]; [self waitForExpectationsWithCommonTimeout]; } - (void)testResponseWithRAW { XCTestExpectation *expectation = [self expectationWithDescription:@"GET请求,HTTP解析失败"]; [[HLAPIRequest request] .setMethod(GET) .setPath(@"html") .setResponseType(ResponseHTTP) .success(^(id result){ XCTAssertNotNil(result); [expectation fulfill]; }).failure(^(NSError *error){ XCTAssertNil(error); }) start]; [self waitForExpectationsWithCommonTimeout]; } - (void)testResponseWithJSON { XCTestExpectation *expectation = [self expectationWithDescription:@"POST请求,JSON解析失败"]; [[HLAPIRequest request] .setMethod(POST) .setPath(@"https://httpbin.org/") .setPath(@"post") .setHeader(nil) .enableDefaultParams(NO) .setParams(@{@"key1": @"value1", @"key2": @"value2"}) .setResponseType(ResponseJSON) .success(^(id result){ XCTAssertTrue([result[@"form"][@"key1"] isEqualToString:@"value1"]); XCTAssertTrue([result[@"form"][@"key2"] isEqualToString:@"value2"]); [expectation fulfill]; }).failure(^(NSError *error){ XCTAssertNil(error); }) start]; [self waitForExpectationsWithCommonTimeout]; } - (void)testResponseWithXML { XCTestExpectation *expectation = [self expectationWithDescription:@"GET请求,XML解析失败"]; [[HLAPIRequest request] .setMethod(GET) .setHeader(nil) .setPath(@"xml") .enableDefaultParams(NO) .setResponseType(ResponseXML) .success(^(id result){ XCTAssertTrue([result isKindOfClass:[NSXMLParser class]]); [expectation fulfill]; }).failure(^(NSError *error){ XCTAssertNil(error); }) start]; [self waitForExpectationsWithCommonTimeout]; } - (void)testHEAD { XCTestExpectation *expectation = [self expectationWithDescription:@"HEAD请求失败"]; [[HLAPIRequest request] .setMethod(HEAD) .setHeader(nil) .setPath(@"get") .enableDefaultParams(NO) .success(^(id result){ [expectation fulfill]; }).failure(^(NSError *error){ XCTAssertNil(error); }) start]; [self waitForExpectationsWithCommonTimeout]; } - (void)testPUT { XCTestExpectation *expectation = [self expectationWithDescription:@"PUT请求失败"]; [[HLAPIRequest request] .setMethod(PUT) .setHeader(nil) .setPath(@"put") .setParams(@{@"key": @"value"}) .enableDefaultParams(NO) .success(^(id result){ XCTAssertTrue([result[@"form"][@"key"] isEqualToString:@"value"]); [expectation fulfill]; }).failure(^(NSError *error){ XCTAssertNil(error); }) start]; [self waitForExpectationsWithCommonTimeout]; } - (void)testDELETE { XCTestExpectation *expectation = [self expectationWithDescription:@"DELETE请求失败"]; [[HLAPIRequest request] .setMethod(DELETE) .setHeader(nil) .setPath(@"delete") .setParams(@{@"key": @"value"}) .enableDefaultParams(NO) .success(^(id result){ XCTAssertTrue([result[@"args"][@"key"] isEqualToString:@"value"]); [expectation fulfill]; }).failure(^(NSError *error){ XCTAssertNil(error); }) start]; [self waitForExpectationsWithCommonTimeout]; } - (void)testPATCH { XCTestExpectation *expectation = [self expectationWithDescription:@"PATCH请求失败"]; [[HLAPIRequest request] .setMethod(PATCH) .setHeader(nil) .setPath(@"patch") .setParams(@{@"key": @"value"}) .enableDefaultParams(NO) .success(^(id result){ XCTAssertTrue([result[@"form"][@"key"] isEqualToString:@"value"]); [expectation fulfill]; }).failure(^(NSError *error){ XCTAssertNil(error); }) start]; [self waitForExpectationsWithCommonTimeout]; } - (void)testUserAgnet { XCTestExpectation *expectation = [self expectationWithDescription:@"自定义user-agent请求失败"]; [[HLAPIRequest request] .setMethod(GET) .setHeader(nil) .setPath(@"user-agent") .enableDefaultParams(NO) .setHeader(@{@"User-Agent": @"XMNetworking Custom User Agent"}) .success(^(id result){ XCTAssertTrue([result[@"user-agent"] isEqualToString:@"XMNetworking Custom User Agent"]); [expectation fulfill]; }).failure(^(NSError *error){ XCTAssertNil(error); }) start]; [self waitForExpectationsWithCommonTimeout]; } - (void)testRequestWithFailure { XCTestExpectation *expectation = [self expectationWithDescription:@"请求没有失败"]; [[HLAPIRequest request] .setMethod(GET) .setCustomURL(@"https://httpbin.org/status/404") .setHeader(nil) .enableDefaultParams(NO) .success(^(id result){ XCTAssertNil(result); }).failure(^(NSError *error){ XCTAssertNotNil(error); [expectation fulfill]; }) start]; [self waitForExpectationsWithCommonTimeout]; } - (void)testTimeOut { XCTestExpectation *expectation = [self expectationWithDescription:@"请求未超时!"]; [[HLAPIRequest request] .setMethod(GET) .setCustomURL(@"https://kangzubin.cn/test/timeout.php") .setHeader(nil) .setTimeout(5.0) .enableDefaultParams(NO) .success(^(id result){ XCTAssertNil(result); }).failure(^(NSError *error){ XCTAssertNotNil(error); XCTAssertTrue(error.code == NSURLErrorTimedOut); [expectation fulfill]; }) start]; [self waitForExpectationsWithCommonTimeout]; } - (void)testCancelRunningRequest { XCTestExpectation *expectation = [self expectationWithDescription:@"请求没有手动取消!"]; HLAPIRequest *request = [[HLAPIRequest request] .setMethod(GET) .setCustomURL(@"https://kangzubin.cn/test/timeout.php") .setHeader(nil) .enableDefaultParams(NO) .success(^(id result){ XCTAssertNil(result); }).failure(^(NSError *error){ XCTAssertNotNil(error); XCTAssertTrue(error.code == NSURLErrorCancelled); [expectation fulfill]; }) start]; sleep(2); [request cancel]; XCTAssertNotNil(request.success); XCTAssertNotNil(request.failure); [self waitForExpectationsWithCommonTimeout]; } @end ================================================ FILE: HLNetworkingTests/HLManagerTests.m ================================================ // // HLManagerTests.m // HLNetworking // // Created by wangshiyu13 on 2017/2/9. // Copyright © 2017年 wangshiyu13. All rights reserved. // #import "HLTestCase.h" @interface HLManagerTests : HLTestCase @property (nonatomic, strong) HLNetworkManager *testManager2; @end @implementation HLManagerTests - (void)setUp { [super setUp]; self.testManager2 = [HLNetworkManager manager]; } - (void)tearDown { [super tearDown]; self.testManager2 = nil; } - (void)testCallbackQueue { XCTestExpectation *expectation1 = [self expectationWithDescription:@"The callback blocks should be called in main thread."]; [HLNetworkManager send:[HLAPIRequest request] .setMethod(GET) .setCustomURL(@"https://httpbin.org/get") .success(^(id result){ XCTAssertNotNil(result); XCTAssertTrue([NSThread isMainThread]); [expectation1 fulfill]; }) .failure(^(NSError *error){ XCTAssertNil(error); })]; XCTestExpectation *expectation2 = [self expectationWithDescription:@"The callback blocks should be called in a private thread."]; [self.testManager2 setupConfig:^(HLNetworkConfig * _Nonnull config) { config.request.callbackQueue = dispatch_get_global_queue(0, 0); config.request.apiVersion = nil; }]; [self.testManager2 send:[HLAPIRequest request] .setMethod(POST) .setBaseURL(@"https://httpbin.org") .setCustomURL(@"https://httpbin.org/post") .success(^(id result){ XCTAssertNotNil(result); XCTAssertTrue(![NSThread isMainThread]); [expectation2 fulfill]; }) .failure(^(NSError *error){ XCTAssertNil(error); })]; [self waitForExpectationsWithCommonTimeout]; } - (void)testSSLPinning { XCTestExpectation *expectation = [self expectationWithDescription:@"HLSSLPinningModeCertificate模式请求不成功!"]; NSString *certPath = [[NSBundle bundleForClass:[self class]] pathForResource:@"httpbin.org" ofType:@"cer"]; [HLNetworkManager setupConfig:^(HLNetworkConfig * _Nonnull config) { // Add SSL Pinning Certificate HLSecurityPolicyConfig *sConfig = [HLSecurityPolicyConfig policyWithPinningMode:HLSSLPinningModeCertificate]; sConfig.cerFilePath = certPath; config.defaultSecurityPolicy = sConfig; }]; [[HLAPIRequest request] .setMethod(GET) .setCustomURL(@"https://httpbin.org/get") .enableDefaultParams(NO) .success(^(id result){ XCTAssertNotNil(result); [expectation fulfill]; }) .failure(^(NSError *error){ XCTAssertNil(error); }) start]; [self waitForExpectationsWithCommonTimeout]; } - (void)testNetworkReachability { NSLog(@"%lu", (unsigned long)[HLNetworkManager reachabilityStatus]); XCTAssertTrue([HLNetworkManager reachabilityStatus] == HLReachabilityStatusReachableViaWWAN); } @end ================================================ FILE: HLNetworkingTests/HLRequestGroupTests.m ================================================ // // HLRequestGroupTests.m // HLNetworking // // Created by wangshiyu13 on 2017/2/9. // Copyright © 2017年 wangshiyu13. All rights reserved. // #import "HLTestCase.h" @interface HLRequestGroupTests : HLTestCase @property XCTestExpectation *groupExpectation; @end @implementation HLRequestGroupTests - (void)setUp { [super setUp]; } - (void)tearDown { [super tearDown]; } - (void)requestGroupAllDidFinished:(HLRequestGroup *)apiGroup { XCTAssertNotNil(apiGroup); [self.groupExpectation fulfill]; } - (void)testBatchRequest { self.groupExpectation = [self expectationWithDescription:@"group请求未完成"]; XCTestExpectation *expectation1 = [self expectationWithDescription:@"api1请求不成功"]; XCTestExpectation *expectation2 = [self expectationWithDescription:@"api2请求不成功"]; XCTestExpectation *expectation3 = [self expectationWithDescription:@"api3请求不成功"]; HLRequestGroup *group = [HLRequestGroup groupWithMode:HLRequestGroupModeBatch]; group.delegate = self; HLAPIRequest *reqeust1 = [HLAPIRequest request] .setMethod(GET) .setCustomURL(@"https://httpbin.org/get") .setParams(@{@"method": @"get"}) .success(^(id result){ XCTAssertTrue([result[@"args"][@"method"] isEqualToString:@"get"]); [expectation1 fulfill]; }) .failure(^(NSError *error){ XCTAssertNil(error); }); HLAPIRequest *reqeust2 = [HLAPIRequest request] .setMethod(POST) .setCustomURL(@"https://httpbin.org/post") .setParams(@{@"method": @"post"}) .success(^(id result){ XCTAssertTrue([result[@"form"][@"method"] isEqualToString:@"post"]); [expectation2 fulfill]; }) .failure(^(NSError *error){ XCTAssertNil(error); }); HLAPIRequest *reqeust3 = [HLAPIRequest request] .setMethod(PUT) .setCustomURL(@"https://httpbin.org/put") .setParams(@{@"method": @"put"}) .success(^(id result){ XCTAssertTrue([result[@"form"][@"method"] isEqualToString:@"put"]); [expectation3 fulfill]; }) .failure(^(NSError *error){ XCTAssertNil(error); }); [group addRequests:@[reqeust1, reqeust2, reqeust3]]; [group start]; [self waitForExpectationsWithCommonTimeout]; } - (void)testBatchRequestWithFailure { self.groupExpectation = [self expectationWithDescription:@"group请求未完成"]; XCTestExpectation *expectation1 = [self expectationWithDescription:@"api1请求不成功"]; XCTestExpectation *expectation2 = [self expectationWithDescription:@"api2请求成功"]; XCTestExpectation *expectation3 = [self expectationWithDescription:@"api3请求不成功"]; HLRequestGroup *group = [HLRequestGroup groupWithMode:HLRequestGroupModeBatch]; group.delegate = self; HLAPIRequest *reqeust1 = [HLAPIRequest request] .setMethod(GET) .setCustomURL(@"https://httpbin.org/get") .setParams(@{@"method": @"get"}) .success(^(id result){ XCTAssertTrue([result[@"args"][@"method"] isEqualToString:@"get"]); [expectation1 fulfill]; }) .failure(^(NSError *error){ XCTAssertNil(error); }); HLAPIRequest *reqeust2 = [HLAPIRequest request] .setMethod(GET) .setCustomURL(@"https://kangzubin.cn/test/timeout.php") .setTimeout(5.0) .success(^(id result){ XCTAssertNil(result); }) .failure(^(NSError *error){ XCTAssertTrue(error.code == NSURLErrorTimedOut); [expectation2 fulfill]; }); HLAPIRequest *reqeust3 = [HLAPIRequest request] .setMethod(PUT) .setCustomURL(@"https://httpbin.org/put") .setParams(@{@"method": @"put"}) .success(^(id result){ XCTAssertTrue([result[@"form"][@"method"] isEqualToString:@"put"]); [expectation3 fulfill]; }) .failure(^(NSError *error){ XCTAssertNil(error); }); [group addRequests:@[reqeust1, reqeust2, reqeust3]]; [group start]; [self waitForExpectationsWithCommonTimeout]; } - (void)testCancelBatchRequest { self.groupExpectation = [self expectationWithDescription:@"group请求未完成"]; XCTestExpectation *expectation1 = [self expectationWithDescription:@"api1请求不成功"]; XCTestExpectation *expectation2 = [self expectationWithDescription:@"api2请求成功"]; XCTestExpectation *expectation3 = [self expectationWithDescription:@"api3请求不成功"]; HLRequestGroup *group = [HLRequestGroup groupWithMode:HLRequestGroupModeBatch]; group.delegate = self; HLAPIRequest *reqeust1 = [HLAPIRequest request] .setMethod(GET) .setCustomURL(@"https://httpbin.org/get") .setParams(@{@"method": @"get"}) .success(^(id result){ XCTAssertTrue([result[@"args"][@"method"] isEqualToString:@"get"]); [expectation1 fulfill]; }) .failure(^(NSError *error){ XCTAssertNil(error); }); HLAPIRequest *reqeust2 = [HLAPIRequest request] .setMethod(GET) .setCustomURL(@"https://kangzubin.cn/test/timeout.php") .setTimeout(5.0) .success(^(id result){ XCTAssertNil(result); }) .failure(^(NSError *error){ XCTAssertTrue(error.code == NSURLErrorCancelled); [expectation2 fulfill]; }); HLAPIRequest *reqeust3 = [HLAPIRequest request] .setMethod(PUT) .setCustomURL(@"https://httpbin.org/put") .setParams(@{@"method": @"put"}) .success(^(id result){ XCTAssertTrue([result[@"form"][@"method"] isEqualToString:@"put"]); [expectation3 fulfill]; }) .failure(^(NSError *error){ XCTAssertNil(error); }); [group addRequests:@[reqeust1, reqeust2, reqeust3]]; [group start]; sleep(2); [reqeust2 cancel]; [self waitForExpectationsWithCommonTimeout]; } - (void)testChainRequest { self.groupExpectation = [self expectationWithDescription:@"group请求未完成"]; __block int i = 0; XCTestExpectation *expectation1 = [self expectationWithDescription:@"api1请求不成功"]; XCTestExpectation *expectation2 = [self expectationWithDescription:@"api2请求不成功"]; XCTestExpectation *expectation3 = [self expectationWithDescription:@"api3请求不成功"]; HLRequestGroup *group = [HLRequestGroup groupWithMode:HLRequestGroupModeChain]; group.delegate = self; HLAPIRequest *reqeust1 = [HLAPIRequest request] .setMethod(GET) .setCustomURL(@"https://httpbin.org/get") .setParams(@{@"method": @"get"}) .success(^(id result){ XCTAssertTrue([result[@"args"][@"method"] isEqualToString:@"get"]); XCTAssertEqual(i, 0); i++; [expectation1 fulfill]; }) .failure(^(NSError *error){ XCTAssertNil(error); }); HLAPIRequest *reqeust2 = [HLAPIRequest request] .setMethod(POST) .setCustomURL(@"https://httpbin.org/post") .setParams(@{@"method": @"post"}) .success(^(id result){ XCTAssertTrue([result[@"form"][@"method"] isEqualToString:@"post"]); XCTAssertEqual(i, 1); i++; [expectation2 fulfill]; }) .failure(^(NSError *error){ XCTAssertNil(error); }); HLAPIRequest *reqeust3 = [HLAPIRequest request] .setMethod(PUT) .setCustomURL(@"https://httpbin.org/put") .setParams(@{@"method": @"put"}) .success(^(id result){ XCTAssertTrue([result[@"form"][@"method"] isEqualToString:@"put"]); XCTAssertEqual(i, 2); i++; [expectation3 fulfill]; }) .failure(^(NSError *error){ XCTAssertNil(error); }); [group addRequests:@[reqeust1, reqeust2, reqeust3]]; [group start]; [self waitForExpectationsWithCommonTimeout]; } - (void)testChainRequestWithFailure1 { // XCTestExpectation *expectation = [self expectationWithDescription:@"The chain requests should fail."]; // // [XMCenter sendChainRequest:^(XMChainRequest * _Nonnull chainRequest) { // // [[[chainRequest onFirst:^(XMRequest * _Nonnull request) { // request.url = @"https://httpbin.org/get"; // request.httpMethod = kXMHTTPMethodGET; // request.parameters = @{@"method": @"get"}; // }] onNext:^(XMRequest * _Nonnull request, id _Nullable responseObject, BOOL * _Nonnull sendNext) { // if ([responseObject[@"args"][@"method"] isEqualToString:@"get"]) { // request.url = @"https://httpbin.org/post"; // request.httpMethod = kXMHTTPMethodPOST; // request.parameters = @{@"method": @"post"}; // } else { // *sendNext = NO; // } // }] onNext:^(XMRequest * _Nonnull request, id _Nullable responseObject, BOOL * _Nonnull sendNext) { // // your business validate logic code here. // *sendNext = NO; // }]; // // } onSuccess:^(NSArray * _Nonnull responseObjects) { // XCTAssertNil(responseObjects); // } onFailure:^(NSArray * _Nonnull errors) { // XCTAssertTrue(errors.count == 3); // XCTAssertTrue([errors[0][@"args"][@"method"] isEqualToString:@"get"]); // The success response for first request will return in errors array. // XCTAssertTrue([errors[1][@"form"][@"method"] isEqualToString:@"post"]); // The success response for second request will return in errors array. // XCTAssertTrue([errors[2] isKindOfClass:[NSNull class]]); // The third request will not sent, and return an [NSNull null] object. // } onFinished:^(NSArray * _Nullable responseObjects, NSArray * _Nullable errors) { // XCTAssertNil(responseObjects); // XCTAssertTrue(errors.count == 3); // XCTAssertTrue([errors[0][@"args"][@"method"] isEqualToString:@"get"]); // XCTAssertTrue([errors[1][@"form"][@"method"] isEqualToString:@"post"]); // XCTAssertTrue([errors[2] isKindOfClass:[NSNull class]]); // [expectation fulfill]; // }]; // // [self waitForExpectationsWithCommonTimeout]; } - (void)testChainRequestWithFailure2 { // XCTestExpectation *expectation = [self expectationWithDescription:@"The chain requests should fail."]; // // [XMCenter sendChainRequest:^(XMChainRequest * _Nonnull chainRequest) { // // [[chainRequest onFirst:^(XMRequest * _Nonnull request) { // request.url = @"https://httpbin.org/get"; // request.httpMethod = kXMHTTPMethodGET; // request.parameters = @{@"method": @"get"}; // }] onNext:^(XMRequest * _Nonnull request, id _Nullable responseObject, BOOL * _Nonnull sendNext) { // if ([responseObject[@"args"][@"method"] isEqualToString:@"get"]) { // request.url = @"https://kangzubin.cn/test/timeout.php"; // This interface will return in 30 seconds later. // request.httpMethod = kXMHTTPMethodGET; // request.timeoutInterval = 5.0; // } else { // *sendNext = NO; // } // }]; // // } onSuccess:^(NSArray * _Nonnull responseObjects) { // XCTAssertNil(responseObjects); // } onFailure:^(NSArray * _Nonnull errors) { // XCTAssertTrue(errors.count == 2); // XCTAssertTrue([errors[0][@"args"][@"method"] isEqualToString:@"get"]); // The success response for first request will return in errors array. // XCTAssertTrue(((NSError *)errors[1]).code == NSURLErrorTimedOut); // The Error info for second request. // } onFinished:^(NSArray * _Nullable responseObjects, NSArray * _Nullable errors) { // XCTAssertNil(responseObjects); // XCTAssertTrue(errors.count == 2); // XCTAssertTrue([errors[0][@"args"][@"method"] isEqualToString:@"get"]); // XCTAssertTrue(((NSError *)errors[1]).code == NSURLErrorTimedOut); // [expectation fulfill]; // }]; // // [self waitForExpectationsWithCommonTimeout]; } - (void)testCancelChainRequest { // XCTestExpectation *expectation1 = [self expectationWithDescription:@"The chain requests should succeed."]; // XCTestExpectation *expectation2 = [self expectationWithDescription:@"The Cancel block should be called."]; // // NSString *identifier = [XMCenter sendChainRequest:^(XMChainRequest * _Nonnull chainRequest) { // // [[chainRequest onFirst:^(XMRequest * _Nonnull request) { // request.url = @"https://httpbin.org/get"; // request.httpMethod = kXMHTTPMethodGET; // request.parameters = @{@"method": @"get"}; // }] onNext:^(XMRequest * _Nonnull request, id _Nullable responseObject, BOOL * _Nonnull sendNext) { // if ([responseObject[@"args"][@"method"] isEqualToString:@"get"]) { // request.url = @"https://kangzubin.cn/test/timeout.php"; // This interface will return in 30 seconds later. // request.httpMethod = kXMHTTPMethodGET; // } else { // *sendNext = NO; // } // }]; // // } onSuccess:^(NSArray * _Nonnull responseObjects) { // XCTAssertNil(responseObjects); // } onFailure:^(NSArray * _Nonnull errors) { // XCTAssertTrue(errors.count == 2); // XCTAssertTrue([errors[0][@"args"][@"method"] isEqualToString:@"get"]); // The success response for first request will return in errors array. // XCTAssertTrue(((NSError *)errors[1]).code == NSURLErrorCancelled); // The Error info for second request. // } onFinished:^(NSArray * _Nullable responseObjects, NSArray * _Nullable errors) { // XCTAssertNil(responseObjects); // XCTAssertTrue(errors.count == 2); // XCTAssertTrue([errors[0][@"args"][@"method"] isEqualToString:@"get"]); // XCTAssertTrue(((NSError *)errors[1]).code == NSURLErrorCancelled); // [expectation1 fulfill]; // }]; // // sleep(2); // // [XMCenter cancelRequest:identifier onCancel:^(id _Nullable request) { // XMChainRequest *chainRequest = request; // XCTAssertNotNil(chainRequest); // [expectation2 fulfill]; // }]; // // [self waitForExpectationsWithCommonTimeout]; // } @end ================================================ FILE: HLNetworkingTests/HLTaskRequestTest.m ================================================ // // HLTaskRequestTest.m // HLNetworking // // Created by wangshiyu13 on 2017/2/9. // Copyright © 2017年 wangshiyu13. All rights reserved. // #import "HLTestCase.h" @interface HLTaskRequestTest : HLTestCase @end @implementation HLTaskRequestTest - (void)setUp { [super setUp]; } - (void)tearDown { [super tearDown]; } - (void)testDownload { XCTestExpectation *expectation1 = [self expectationWithDescription:@"下载请求失败"]; XCTestExpectation *expectation2 = [self expectationWithDescription:@"下载进度回调失败"]; [[HLTaskRequest request] .setTaskType(Download) .setCustomURL(@"https://httpbin.org/image/png") .setFilePath([NSHomeDirectory() stringByAppendingString:@"/Documents/temp.png"]) .progress(^(NSProgress *proc){ if (proc.fractionCompleted == 1.0) { [expectation2 fulfill]; } }) .success(^(id result){ XCTAssertNotNil(result); XCTAssertTrue([[NSFileManager defaultManager] fileExistsAtPath:((NSURL *)result).path]); [expectation1 fulfill]; }).failure(^(NSError *error){ XCTAssertNil(error); }) start]; [self waitForExpectationsWithCommonTimeout]; } - (void)testUpload { NSString *path = [[NSBundle bundleForClass:[self class]] pathForResource:@"testImage" ofType:@"jpg"]; XCTestExpectation *expectation1 = [self expectationWithDescription:@"上传请求失败"]; // XCTestExpectation *expectation2 = [self expectationWithDescription:@"上传进度回调失败"]; [[HLTaskRequest request] .setTaskType(Upload) .setCustomURL(@"https://httpbin.org/post") .setFilePath(path) .progress(^(NSProgress *proc){ NSLog(@"%@", proc); if (proc.fractionCompleted == 1.0) { // [expectation2 fulfill]; } }) .success(^(id result){ XCTAssertNotNil(result); XCTAssertTrue(result[@"data"] != nil); [expectation1 fulfill]; }).failure(^(NSError *error){ XCTAssertNil(error); }) start]; [self waitForExpectationsWithCommonTimeout]; } @end ================================================ FILE: HLNetworkingTests/HLTestCase.h ================================================ // // HLTestCase.h // HLNetworking // // Created by wangshiyu13 on 2017/2/9. // Copyright © 2017年 wangshiyu13. All rights reserved. // #import #import "HLNetworking.h" @interface HLTestCase : XCTestCase @property (nonatomic, assign) NSTimeInterval networkTimeout; - (void)waitForExpectationsWithCommonTimeout; - (void)waitForExpectationsWithCommonTimeoutUsingHandler:(XCWaitCompletionHandler)handler; @end ================================================ FILE: HLNetworkingTests/HLTestCase.m ================================================ // // HLTestCase.m // HLNetworking // // Created by wangshiyu13 on 2017/2/9. // Copyright © 2017年 wangshiyu13. All rights reserved. // #import "HLTestCase.h" @implementation HLTestCase - (void)setUp { [super setUp]; self.networkTimeout = 20.0; // [HLNetworkLogger setupConfig:^(HLNetworkLoggerConfig * _Nonnull config) { // config.enableLocalLog = YES; // config.logAutoSaveCount = 5; // config.loggerType = HLNetworkLoggerTypePlist; // }]; // [HLNetworkLogger setDelegate:self]; // [HLNetworkLogger startLogging]; // setupNetwork [HLNetworkManager setupConfig:^(HLNetworkConfig * _Nonnull config) { config.request.baseURL = @"https://httpbin.org/"; config.policy.isBackgroundSession = NO; config.request.apiVersion = nil; config.request.defaultParams = @{@"global_param": @"global param value"}; config.request.defaultHeaders = @{@"global_header": @"global header value"}; }]; } - (void)tearDown { [super tearDown]; } - (void)waitForExpectationsWithCommonTimeout { [self waitForExpectationsWithCommonTimeoutUsingHandler:nil]; } - (void)waitForExpectationsWithCommonTimeoutUsingHandler:(XCWaitCompletionHandler)handler { [self waitForExpectationsWithTimeout:self.networkTimeout handler:handler]; } - (NSDictionary *)customInfoWithMessage:(HLDebugMessage *)message { NSMutableDictionary *dict = [NSMutableDictionary dictionary]; dict[@"Time"] = message.timeString; dict[@"RequestObject"] = [message.requestObject toDictionary]; dict[@"Response"] = [message.response toDictionary]; return [dict copy]; } - (NSDictionary *)customHeaderWithMessage:(HLNetworkLoggerConfig *)config { return @{@"AppInfo": @{@"OSVersion": [UIDevice currentDevice].systemVersion, @"DeviceType": [UIDevice currentDevice].hl_machineType, @"UDID": [UIDevice currentDevice].hl_udid, @"UUID": [UIDevice currentDevice].hl_uuid, @"MacAddressMD5": [UIDevice currentDevice].hl_macaddressMD5, @"ChannelID": config.channelID, @"AppKey": config.appKey, @"AppName": config.appName, @"AppVersion": config.appVersion, @"ServiceType": config.serviceType}}; } @end ================================================ FILE: HLNetworkingTests/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType BNDL CFBundleShortVersionString 1.0 CFBundleVersion 1 ================================================ FILE: LICENSE ================================================ Copyright (c) 2012-2017, HLNetworking (https://github.com/QianKun-HanLin) All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * The name of Pierre-Olivier Latour may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL PIERRE-OLIVIER LATOUR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: Podfile ================================================ source 'git@github.com:CocoaPods/Specs.git' platform :ios, '8.0' target 'HLNetworking' do pod 'AFNetworking', '~> 3.1.0' pod 'YYModel', '~> 1.0.4' end ================================================ FILE: README.md ================================================ ![HLNetworking: High-level network request manager based on AFNetworking](https://raw.githubusercontent.com/QianKun-HanLin/HLNetworking/master/loge.png) #### 基于AFNetworking的高阶网络请求管理器 [![License MIT](https://img.shields.io/badge/license-MIT-green.svg?style=flat)](https://github.com/wangshiyu13/HLQRCodeScanner/blob/master/LICENSE) [![CI Status](https://img.shields.io/badge/build-2.0.2-brightgreen.svg)](https://travis-ci.org/wangshiyu13/HLNetworking) [![CocoaPods](https://img.shields.io/badge/platform-iOS-lightgrey.svg)](http://cocoapods.org/?q=HLNetworking) [![Support](https://img.shields.io/badge/support-iOS%208%2B-blue.svg)](https://www.apple.com/nl/ios/) ## 简介 ![](http://p1.bqimg.com/4851/18e86cfdfaccc59c.png) HLNetworking整体结构如图所示,是一套基于[AFNetworking 3.1.0](https://github.com/AFNetworking/AFNetworking)封装的网络库,提供了更高层次的抽象和更方便的调用方式。 如果您使用的是1.x.x版本,请查看[旧版本说明](https://github.com/QianKun-HanLin/HLNetworking/blob/master/README_old.md) ## 特性 - 离散式的请求设计,方便进行组件化 - 支持全局配置请求的公共信息 - 提供大多数网络访问方式和相应的序列化类型 - 提供api请求结果映射接口,可以自行转换为相应的数据格式 - api请求支持多种回调方式(block,delegate) - api配置简单,通过block链式调用组装api,配合APICenter中的宏可以极大减少离散式api的设置代码 - 支持批量请求、链式请求等特殊需求 - 可随时取消未完成的网络请求,支持断点续传 - 提供常用的formData拼接方式,可自行扩展 - 提供请求前网络状态检测,重复请求检测,避免不必要的请求 - 提供debug回调用于调试 ##使用方法 ### 头文件的导入 * 如果是通过 CocoaPods 安装,则: ```objc #import ``` * 如果是手动下载源码安装,则: ```objc #import "HLNetworking.h" ``` ### 全局网络配置 ```objc [HLNetworkManager setupConfig:^(HLNetworkConfig * _Nonnull config) { config.request.baseURL = @"https://httpbin.org/"; config.request.apiVersion = nil; }]; ``` 通过调用`HLNetworkManager`的`+setupConfig:`方法,修改block中传入的`HLNetworkConfig`对象来配置全局网络请求信息,其中可修改的参数如下: - **tips**:提示相关参数 - **generalErrorTypeStr**:出现网络请求时使用的错误提示文字,该文字在failure block中的NSError对象返回;默认为:`服务器连接错误,请稍候重试` - **frequentRequestErrorStr**:用户频繁发送同一个请求,使用的错误提示文字;默认为:`请求发送速度太快, 请稍候重试` - **networkNotReachableErrorStr**:网络请求开始时,会先检测相应网络域名的Reachability,如果不可达,则直接返回该错误提示;默认为:`网络不可用,请稍后重试` - **isNetworkingActivityIndicatorEnabled**:请求时是否显示网络指示器(状态栏),默认为 `YES` - **request**:请求相关参数 - **apiCallbackQueue**:自定义的请求队列,如果不设置则自动使用HLNetworkManager默认的队列,该参数默认为 `nil` - **defaultParams**:默认的parameters,可以在HLAPI中选择是否使用,默认开启,该参数不会被覆盖,HLAPI中使用`setParams()`后,请求的params中依然会有该参数,默认为 `nil` - **defaultHeaders**:默认的header,可以在HLAPI中覆盖,默认为 `nil` - **baseURL**:全局的baseURL,HLAPI的baseURL会覆盖该参数,默认为 `nil` - **apiVersion**:api版本,用于拼接在请求的Path上,默认为infoPlist中的`CFBundleShortVersionString`,格式为`v{version}{r}`,审核版本为r,例:http://www.baidu.com/v5/s?ie=UTF-8&wd=abc,默认为 `nil` - **isJudgeVersion**:是否为审核版本,作用于apiVersion,存储在NSUserDefaults中,key为isR,默认为 `NO` - **userAgent**:UserAgent,request header中的UA,默认为 `nil` - **maxHttpConnectionPerHost**:每个Host的最大连接数,默认为 `5` - **requestTimeoutInterval**:请求超时时间,默认为 `15` 秒 - **policy**:网络策略相关参数 - **AppGroup**:后台模式所用的GroupID,该选项只对Task有影响,默认为 `nil` - **isBackgroundSession**:是否为后台模式,该选项只对Task有影响,默认为 `NO` - **isErrorCodeDisplayEnabled**:出现网络请求错误时,是否在请求错误的文字后加上`{code}`,默认为YES - **cachePolicy**:请求缓存策略,默认为 `NSURLRequestUseProtocolCachePolicy` - **URLCache**:URLCache设置,默认为 `[NSURLCache sharedURLCache]` - **defaultSecurityPolicy**:默认的安全策略配置,该配置在debug模式下默认为`HLSSLPinningModeNone`,release模式下默认为`HLSSLPinningModePublicKey`,其中详细参数如下: - **SSLPinningMode**:SSL Pinning证书的校验模式,默认为 `HLSSLPinningModeNone` - **allowInvalidCertificates**:是否允许使用Invalid 证书,默认为 `NO` - **validatesDomainName**:是否校验在证书 CN 字段中的 domain name,默认为 `YES` - **cerFilePath**:cer证书文件路径,默认为 `nil` - **enableReachability**:是否启用reachability,baseURL为domain,默认为 `NO` - **enableGlobalLog**:是否开启网络debug日志,该选项会在控制台输出所有网络回调日志,并且在Release模式下无效 ### Request相关 `HLNetworking`通过Request发送请求,Request分为`HLURLRequest`、`HLAPIRequest`、`HLTaskRequest`,`HLURLRequest`为基类,`HLAPIRequest`为RestfulAPI参数类、`HLTaskRequest`为用于上传下载任务类 #### 组装api ```objc // 组装请求 HLAPIRequest *get = [HLAPIRequest request].setMethod(GET) .setPath(@"get") .setParams(@{@"user_id": @1}) .setDelegate(self); // 手动拼接formData上传 HLAPIRequest *formDataRequest = [HLAPIRequest request].formData(^(id formData) { [formData appendPartWithHeaders:@{@"contentType": @"html/text"} body:[NSData data]]; }); // 使用HLFormDataConfig对象拼接上传 [HLAPIRequest request].formData([HLFormDataConfig configWithData:imageData name:@"avatar" fileName:@"fileName" mimeType:@"type"]); ``` #### 组装task ```objc HLTaskRequest *task = [[HLTaskRequest request].setDelegate(self) // 设置Task类型,Upload/Download .setTaskType(Upload) // 设置下载或者上传的本地文件路径 .setFilePath([[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"Boom2.dmg"]) // 设置下载或者上传的地址 .setCustomURL(@"https://dl.devmate.com/com.globaldelight.Boom2/Boom2.dmg") start]; ``` #### block方式接收请求 ```objc // block接收请求 [get.success(^(id result) { NSLog(@"\napi 1 --- 已回调 \n----"); }) .progress(^(NSProgress *proc){ NSLog(@"当前进度:%@", proc); }) .failure(^(NSError *error){ NSLog(@"\napi1 --- 错误:%@", error); }) .debug(^(HLDebugMessage *message){ NSLog(@"\n debug参数:\n \ sessionTask = %@\n \ api = %@\n \ error = %@\n \ originRequest = %@\n \ currentRequest = %@\n \ response = %@\n", message.sessionTask, message.api, message.error, message.originRequest, message.currentRequest, message.response); }) start]; ``` #### delegate方式接收请求 ```objc // 当前类遵守HLAPIResponseDelegate协议 // 在初始化方法中设置当前类为回调监听 [HLNetworkManager registerResponseObserver:self]; // 在这个宏中写入需要监听的api HLObserverRequests(self.api1, self.api2) // 或者用-requestAPIs这个代理方法,这两个完全等效 - (NSArray <__kindof HLURLRequest *>*)observerRequests { return [NSArray arrayWithObjects:self.api1, self.api2, self.api3, self.api4, nil]; } // 在下面三个代理方法中获取回调结果 // 进度的回调 - (void)requestProgress:(nullable NSProgress *)progress atRequest:(nullable HLURLRequest *)request { NSLog(@"\n%@------RequestProgress--------%@\n", request.hashKey, progress); NSLog(@"%@", [NSThread currentThread]); } // 请求成功的回调 - (void)requestSucess:(nullable id)responseObject atRequest:(nullable HLURLRequest *)request { NSLog(@"\n%@------RequestSuccessDelegate\n", request.hashKey); NSLog(@"%@", [NSThread currentThread]); } // 请求失败的回调 - (void)requestFailure:(nullable NSError *)error atRequest:(nullable HLURLRequest *)request { NSLog(@"\n%@------RequestFailureDelegate------%@\n", request.hashKey, error); NSLog(@"%@", [NSThread currentThread]); } // 切记在dealloc中释放当前控制器 - (void)dealloc { [HLNetworkManager removeResponseObserver:self]; } ``` **注意1:**设置请求URL时,`setCustomURL`的优先级最高,其次是API中的`setBaseURL`,最后才是全局config中的`baseURL`,另无论是哪种`baseURL`都需要配合`setPath`使用。 **注意2:**一次请求必须有`{customURL}`或者`{config.baseURL | api.baseURL}``{api.path}`,如果`{customURL}`的参数错写成`{api.path}`中的无host urlString,也会被自动识别成`{api.path}`。 **注意3:**一个请求对象的回调 block (success/failure/progress/debug) 是非必需的(默认为 `nil`)。另外,需要注意的是,success/failure/debug等回调 Block 会在 config 设置的 `apiCallbackQueue ` 队列中被执行,但 progress 回调 Block 将在 NSURLSession 自己的队列中执行,而不是 `apiCallbackQueue `,但是所有的回调结果都会回落到主线程。 **注意4:**请求的delegate回调之所以这样设置,是为了可以跨类获取请求回调,因此使用起来稍微麻烦一些,如果只需要在当前类拿到回调,使用block方式即可。 **注意5:**HLAPIRequest 同样支持其他 HTTP 方法,比如:`HEAD`, `DELETE`, `PUT`, `PATCH` 等,使用方式与上述类似,不再赘述。 **注意6:**HLTaskRequest目前支持上传下载功能,下载已支持断点续传,其中上传是指使用AFNetworking的`uploadTaskWithRequest:fromFile:progress:completionHandler`的方法;如果需要使用POST中的formData拼接方式上传,请参考API相关的formData设置 详见 `HLNetworkConfig`、`HLSecurityPolicyConfig`、`HLAPIRequest`、`HLAPIType` 、`HLNetworkManager` 、`HLFormDataConfig`、`HLDebugMessage` 等几个文件中的代码和注释,可选参数基本可以覆盖大多数需求。 #### 请求的生命周期方法 ```objc // 在api组装时设置当前类为代理 [HLAPIRequest request].setDelegate(self) [HLTaskRequest request].setDelegate(self) // 请求即将发出的代理方法 - (void)requestWillBeSent:(HLURLRequest *)request { NSLog(@"\n%@---willBeSent---", request.hashKey); } // 请求已经发出的代理方法 - (void)requestDidSent:(HLURLRequest *)request { NSLog(@"\n%@---didSent---", request.hashKey); } ``` #### 自定义请求结果处理逻辑 ```objc // 指定的类需要遵守HLObjReformerProtocol协议 [HLAPIRequest request].setObjReformerDelegate(self); /** 一般用来进行JSON -> Model 数据的转换工作。返回的id,如果没有error,则为转换成功后的Model数据。如果有error, 则直接返回传参中的responseObject @param api 调用的api @param responseObject 请求的返回 @param error 请求的错误 @return 整理过后的请求数据 */ - (id)reformerObject:(id)responseObject andError:(NSError *)error atRequest:(HLAPIRequest *)request { if (responseObject) { // 在这里处理获得的数据 // 自定义reformer方法 MyModel *model = [MyReformer reformerWithResponse:responseObject]; return model; } else { // 在这里处理异常 return nil; } } ``` #### 取消一个网络请求 ```objc // 通过api取消网络请求 [self.api1 cancel]; // 通过HLNetworkManager取消网络请求 [HLNetworkManager cancel: self.api1]; ``` **注意:**如果请求已经发出,将无法取消,取消可以注销对应的回调block,但是delegate不会被注销。 ### 批量请求 #### 无序请求 HLNetworking 支持同时发一组批量请求,这组请求在业务逻辑上相关,但请求本身是互相独立的,请求时并行执行,`- requestGroupAllDidFinished` 会在所有请求都结束时才执行,每个请求的结果由API自身管理。注:`HLRequestGroup `类做了特殊处理,自身即为`HLURLRequest`及其子类的容器,因此直接`group[index]`即可获取相应的`HLURLRequest`对象,也可以直接遍历;回调中的 `group `中元素的顺序与每个无序请求 `HLURLRequest` 对象的先后顺序不保证一致。 ```obc HLRequestGroup *group = [HLRequestGroup groupWithMode:HLRequestGroupModeBatch]; // 添加单个api [group add:[HLAPI API]]; // 添加apis集合 [group addRequests:@[api1, api2, api3, nil]]; [group start]; group.delegate = self; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.5), dispatch_get_main_queue(), ^{ // 使用cancel取消 [group cancel]; }); // group全部完成之后调用 - (void)requestGroupAllDidFinished:(HLRequestGroup *)group { NSLog(@"%@", group); } ``` #### 链式请求 HLNetworking 同样支持发一组链式请求,这组请求之间互相依赖,下一请求是否发送以及请求的参数可以取决于上一个请求的结果,请求时串行执行,`- chainRequestsAllDidFinished` 会在所有请求都结束时才执行,每个请求的结果由API自身管理。注:`HLRequestGroup`类做了特殊处理,自身即为`HLURLRequest`及其子类的容器,因此直接`group[index]`即可获取相应的`HLURLRequest`对象,也可以直接遍历;回调中的 `group `中元素的顺序与每个链式请求 `HLURLRequest` 对象的先后顺序一致。 ```objc HLRequestGroup *group = [HLRequestGroup groupWithMode:HLRequestGroupModeChian]; group.delegate = self; // 设置每次发送几个请求,每次发出的请求之间无依赖 group.maxRequestCount = 1; [group addRequests:@[self.api1, self.api2, self.api3, self.api4, self.api5]]; [group start]; for (id obj in group) { NSLog(@"%@", obj); } HLAPIRequest *api = group[0]; // group[0] == self.api1 NSLog(@"%@", api); dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.5), dispatch_get_main_queue(), ^{ // 使用cancel取消 [group cancel]; }); // group全部完成之后调用 - (void)requestGroupAllDidFinished:(HLRequestGroup *)group { NSLog(@"%@", group); } ``` ### 网络可连接性检查 ```objc HLNetworkManager提供了八个方法和四个属性用于获取网络的状态,分别如下: // reachability的状态 typedef NS_ENUM(NSUInteger, HLReachabilityStatus) { HLReachabilityStatusUnknown, HLReachabilityStatusNotReachable, HLReachabilityStatusReachableViaWWAN, HLReachabilityStatusReachableViaWiFi }; // 通过sharedMager单例,获取当前reachability状态 + (HLReachabilityStatus)reachabilityStatus; // 通过sharedMager单例,获取当前是否可访问网络 + (BOOL)isReachable; // 通过sharedMager单例,获取当前是否使用数据流量访问网络 + (BOOL)isReachableViaWWAN; // 通过sharedMager单例,获取当前是否使用WiFi访问网络 + (BOOL)isReachableViaWiFi; // 通过sharedMager单例,开启默认reachability监视器,block返回状态 + (void)listening:(void(^)(HLReachabilityStatus status))listener; // 通过sharedMager单例,停止reachability监视器监听domain + (void)stopListening; // 监听给定的域名是否可以访问,block内返回状态 - (void)listeningWithDomain:(NSString *)domain listeningBlock:(void (^)(HLReachabilityStatus))listener; // 停止给定域名的网络状态监听 - (void)stopListeningWithDomain:(NSString *)domain; ``` **注意:**reachability的监听domain默认为[HLNetworking sharedManager].config.baseURL,当然你也可以通过对象方法自定义domain。 ### HTTPS 请求的本地证书校验(SSL Pinning) 在你的应用程序包里添加 (pinned) 相应的 SSL 证书做校验有助于防止中间人攻击和其他安全漏洞。`HLNetworking`的`config`属性和`HLAPI`里有对AFNetworking 的 `AFSecurityPolicy` 安全模块的封装,你可以通过配置`config`内`defaultSecurityPolicy`属性,用于校验本地保存的证书或公钥可信任。 ```objc // SSL Pinning typedef NS_ENUM(NSUInteger, HLSSLPinningMode) { // 不校验Pinning证书 HLSSLPinningModeNone, // 校验Pinning证书中的PublicKey HLSSLPinningModePublicKey, // 校验整个Pinning证书 HLSSLPinningModeCertificate }; // 生成策略 HLSecurityPolicyConfig *securityPolicy = [HLSecurityPolicyConfig policyWithPinningMode:HLSSLPinningModePublicKey]; // 是否允许使用Invalid 证书,默认为 NO securityPolicy.allowInvalidCertificates = NO; // 是否校验在证书 CN 字段中的 domain name,默认为 YES securityPolicy.validatesDomainName = YES; //cer证书文件路径 securityPolicy.cerFilePath = [[NSBundle mainBundle] pathForResource:@"myCer" ofType:@"cer"]; // 设置默认的安全策略 [HLNetworkManager setupConfig:^(HLNetworkConfig * _Nonnull config) { config.defaultSecurityPolicy = securityPolicy; }]; // 针对特定API的安全策略 self.api1.setSecurityPolicy(securityPolicy); ``` **注意:**Request中的安全策略会在此request请求时覆盖默认安全策略,并且与request相同baseURL的安全策略都会被覆盖。 **注意1:**Task的resume信息记录在沙盒中`Cache/com.qkhl.HLNetworking/downloadDict中`。 ### Center相关 - ``HLAPICenter``提供一种离散式API的组织模版,其核心理念是通过category分散APICenter内的API对象; - ``HLBaseObjReformer``提供了基于YYModel的JSON->Model的模版; - 通过``HLAPIMacro``中定义的宏,可以快速设置模块所需的API #### 范例 - 根据API相关中的设置,配置HLNetworkManager的相关Config - 根据模块创建``HLAPICenter``的category,例如``HLAPICenter+home`` - 在HLAPICenter+home.h中使用HLStrongProperty(name)宏,name为方法名,形如: ```objc #import "HLAPICenter.h" @interface HLAPICenter (home) HLStrongProperty(home) @end ``` - 在HLAPICenter+home.m中使用HLStrongSynthesize(name, api)宏,name为方法名,api为API对象,形如: ```objc #import "HLAPICenter+home.h" @implementation HLAPICenter (home) HLStrongSynthesize(home, [HLAPIRequest request] .setMethod(GET) // 根据需要设置Path、BaseURL、CustomURL .setPath(@"index.php?r=home") // 如果该api对应的model可以直接通过yymodel转换的话,则指定需转换的模型类型名 .setResponseClass(@"HLHomeModel") // 这里使用self.defaultReformer即通过yymodel转换 .setObjReformerDelegate(self.defaultReformer)) @end ``` - 然后就可以愉快的使用了,在控制器中```#import "HLAPICenter+home.h"```,按如下方法使用即可: ```objc - (void)testHome { [HLAPICenter.home.setParams(@{@"user_id": @self.myUserID}) .success(^(HLHomeModel *model) { self.model = model; }).failure(^(NSError *obj){ NSLog(@"----%@", obj); }) start]; } ``` ### Logger相关 - `HLNetworkLogger`提供了记录网络请求信息日志的功能,可自定义日志结构,日志头部信息,日志存储类型等 #### 配置Logger 可选参数如下: - **channelID**:渠道ID - **appKey**:app标志 - **appName**:app名字 - **appVersion**:app版本 - **serviceType**:服务名 - **enableLocalLog**:是否开启本地日志 - **logAutoSaveCount**:日志自动保存数,默认为50次保存一次 - **loggerLevel**:日志等级,该选项暂时无效 - **loggerType**:日志保存类型,可选JSON或者Plist - **logFilePath**:只读,默认为`sandbox/Library/Cache/com.qkhl.HLNetworking/log/{timestamp}.log` - 范例 ```objc [HLNetworkLogger setupConfig:^(HLNetworkLoggerConfig *config) { config.enableLocalLog = YES; config.logAutoSaveCount = 50; config.loggerType = HLNetworkLoggerTypeJSON; }]; [HLNetworkLogger startLogging]; ``` #### 默认Logger信息 - `HLNetworkLogger`默认提供的log信息为`HLDebugMessage`对象,包括: - `requestObject` api/task请求对象, - `sessionTask` NSURLSessionTask对象, - `response` HLURLResponse对象, - `queue` dispatch_queue_t对象, - 具体信息请参考`HLDebugMessage`,`HLURLResponse `,`HLURLResult`这三个文件中的注释 - `HLNetworkLogger`通过管理`debugInfoArray`数组来存储信息,该数组的首元素为当前APP信息,默认如下: - @{@"AppInfo": @{@"OSVersion": [UIDevice currentDevice].systemVersion, - @"DeviceType": [UIDevice currentDevice].hl_machineType, - @"UDID": [UIDevice currentDevice].hl_udid, - @"UUID": [UIDevice currentDevice].hl_uuid, - @"MacAddressMD5": [UIDevice currentDevice].hl_macaddressMD5, - @"ChannelID": _config.channelID, - @"AppKey": _config.appKey, - @"AppName": _config.appName, - @"AppVersion": _config.appVersion, - @"ServiceType": _config.serviceType}} #### 自定义Logger信息 - `HLNetworkLogger`提供自定义log信息内容的方法,该方法每发一次请求,回调时都会调用一次: ```objc // 设置当前类为logger代理,并将当前类遵守HLNetworkCustomLoggerDelegate协议 [HLNetworkLogger setDelegate:self]; // 根据传入的message信息和其他信息组装字典数据 - (NSDictionary *)customInfoWithMessage:(HLDebugMessage *)message { return [message toDictionary]; } // 根据传入的config信息和其他信息组装字典 - (NSDictionary *)customHeaderWithMessage:(HLNetworkLoggerConfig *)config { return @{@"AppInfo": @{@"OSVersion": [UIDevice currentDevice].systemVersion, @"DeviceType": [UIDevice currentDevice].hl_machineType, @"UDID": [UIDevice currentDevice].hl_udid, @"UUID": [UIDevice currentDevice].hl_uuid, @"MacAddressMD5": [UIDevice currentDevice].hl_macaddressMD5, @"ChannelID": config.channelID, @"AppKey": config.appKey, @"AppName": config.appName, @"AppVersion": config.appVersion, @"ServiceType": config.serviceType}}; } ``` ### 更新日志 **2.0.2** ``` 新增: 1. Request组装在线程安全状态 修复: 1. 修复了请求结束时progressBlock没有释放的问题 ``` ## 环境要求 该库需运行在 iOS 8.0 和 Xcode 7.0以上环境. ## 集成方法 HLNetworking 可以在[CocoaPods](http://cocoapods.org)中获取,将以下内容添加进你的Podfile中后,运行`pod install`即可安装: ```ruby pod "HLNetworking" ``` 如果你只需要用到网络相关,可以这样: ```ruby pod "HLNetworking/Core" ``` 目前有两个模块可供选择: - HLNetworking/Core - HLNetworking/Center 其中`Core`包含网络请求相关的所有代码,`Center`依赖于`Core` ## 作者 wangshiyu13, wangshiyu13@163.com ## 开源协议 HLNetworking is available under the MIT license. See the LICENSE file for more info. ================================================ FILE: README_old.md ================================================ ![HLNetworking: Multi paradigm network request manager based on AFNetworking](https://raw.githubusercontent.com/QianKun-HanLin/HLNetworking/master/loge.png) #### 基于AFNetworking的高阶网络请求管理器 [![License MIT](https://img.shields.io/badge/license-MIT-green.svg?style=flat)](https://github.com/wangshiyu13/HLQRCodeScanner/blob/master/LICENSE) [![CI Status](https://img.shields.io/badge/build-1.3.2-brightgreen.svg)](https://travis-ci.org/wangshiyu13/HLQRCodeScanner) [![CocoaPods](https://img.shields.io/badge/platform-iOS-lightgrey.svg)](http://cocoapods.org/?q= HLQRCodeScanner) [![Support](https://img.shields.io/badge/support-iOS%208%2B-blue.svg)](https://www.apple.com/nl/ios/) ## 简介 ![](http://p1.bpimg.com/4851/448c29b352237037.png) HLNetworking整体结构如图所示,是一套基于[AFNetworking 3.1.0](https://github.com/AFNetworking/AFNetworking)封装的网络库,提供了更高层次的抽象和更方便的调用方式。 ## 特性 - 离散式的请求设计,方便进行组件化 - 支持全局配置请求的公共信息 - 提供大多数网络访问方式和相应的序列化类型 - 提供api请求结果映射接口,可以自行转换为相应的数据格式 - api请求支持多种回调方式(block,delegate) - api配置简单,通过block链式调用组装api,配合APICenter中的宏可以极大减少离散式api的设置代码 - 支持批量请求、链式请求等特殊需求 - 可随时取消未完成的网络请求,支持断点续传 - 提供常用的formData拼接方式,可自行扩展 - 提供请求前网络状态检测,重复请求检测,避免不必要的请求 - 提供debug回调用于调试 ##使用方法 ### 头文件的导入 * 如果是通过 CocoaPods 安装,则: ```objc #import ``` * 如果是手动下载源码安装,则: ```objc #import "HLNetworking.h" ``` ### 全局网络配置 ```objc [HLAPIManager setupConfig:^(HLNetworkConfig * _Nonnull config) { config.request.baseURL = @"https://httpbin.org/"; config.request.apiVersion = nil; }]; ``` 通过调用`HLAPIManager`的`+setupConfig:`方法,修改block中传入的`HLNetworkConfig`对象来配置全局网络请求信息,其中可修改的参数如下: - **tips**:提示相关参数 - **generalErrorTypeStr**:出现网络请求时使用的错误提示文字,该文字在failure block中的NSError对象返回;默认为:`服务器连接错误,请稍候重试` - **frequentRequestErrorStr**:用户频繁发送同一个请求,使用的错误提示文字;默认为:`请求发送速度太快, 请稍候重试` - **networkNotReachableErrorStr**:网络请求开始时,会先检测相应网络域名的Reachability,如果不可达,则直接返回该错误提示;默认为:`网络不可用,请稍后重试` - **isNetworkingActivityIndicatorEnabled**:请求时是否显示网络指示器(状态栏),默认为 `YES` - **request**:请求相关参数 - **apiCallbackQueue**:自定义的请求队列,如果不设置则自动使用HLAPIManager默认的队列,该参数默认为 `nil` - **defaultParams**:默认的parameters,可以在HLAPI中选择是否使用,默认开启,该参数不会被覆盖,HLAPI中使用`setParams()`后,请求的params中依然会有该参数,默认为 `nil` - **defaultHeaders**:默认的header,可以在HLAPI中覆盖,默认为 `nil` - **baseURL**:全局的baseURL,HLAPI的baseURL会覆盖该参数,默认为 `nil` - **apiVersion**:api版本,用于拼接在请求的Path上,默认为infoPlist中的`CFBundleShortVersionString`,格式为`v{version}{r}`,审核版本为r,例:http://www.baidu.com/v5/s?ie=UTF-8&wd=abc,默认为 `nil` - **isJudgeVersion**:是否为审核版本,作用于apiVersion,存储在NSUserDefaults中,key为isR,默认为 `NO` - **userAgent**:UserAgent,request header中的UA,默认为 `nil` - **maxHttpConnectionPerHost**:每个Host的最大连接数,默认为 `5` - **requestTimeoutInterval**:请求超时时间,默认为 `15` 秒 - **policy**:网络策略相关参数 - **AppGroup**:后台模式所用的GroupID,该选项只对Task有影响,默认为 `nil` - **isBackgroundSession**:是否为后台模式,该选项只对Task有影响,默认为 `NO` - **isErrorCodeDisplayEnabled**:出现网络请求错误时,是否在请求错误的文字后加上`{code}`,默认为YES - **cachePolicy**:请求缓存策略,默认为 `NSURLRequestUseProtocolCachePolicy` - **URLCache**:URLCache设置,默认为 `[NSURLCache sharedURLCache]` - **defaultSecurityPolicy**:默认的安全策略配置,该配置在debug模式下默认为`HLSSLPinningModeNone`,release模式下默认为`HLSSLPinningModePublicKey`,其中详细参数如下: - **SSLPinningMode**:SSL Pinning证书的校验模式,默认为 `HLSSLPinningModeNone` - **allowInvalidCertificates**:是否允许使用Invalid 证书,默认为 `NO` - **validatesDomainName**:是否校验在证书 CN 字段中的 domain name,默认为 `YES` - **cerFilePath**:cer证书文件路径,默认为 `nil` - **enableReachability**:是否启用reachability,baseURL为domain,默认为 `NO` - **enableGlobalLog**:是否开启网络debug日志,该选项会在控制台输出所有网络回调日志,并且在Release模式下无效 ### API相关 #### 组装api ```objc // 组装请求 HLAPI *get = [HLAPI API].setMethod(GET) .setPath(@"get") .setParams(@{@"user_id": @1}) .setDelegate(self); // 手动拼接formData上传 HLAPI *formData = [HLAPI API].formData(^(id formData) { [formData appendPartWithHeaders:@{@"contentType": @"html/text"} body:[NSData data]]; }); // 使用HLFormDataConfig对象拼接上传 [HLAPI API].formData([HLFormDataConfig configWithData:imageData name:@"avatar" fileName:@"fileName" mimeType:@"type"]); ``` #### block方式接收请求 ```objc // block接收请求 [get.success(^(id result) { NSLog(@"\napi 1 --- 已回调 \n----"); }) .progress(^(NSProgress *proc){ NSLog(@"当前进度:%@", proc); }) .failure(^(NSError *error){ NSLog(@"\napi1 --- 错误:%@", error); }) .debug(^(HLDebugMessage *message){ NSLog(@"\n debug参数:\n \ sessionTask = %@\n \ api = %@\n \ error = %@\n \ originRequest = %@\n \ currentRequest = %@\n \ response = %@\n", message.sessionTask, message.api, message.error, message.originRequest, message.currentRequest, message.response); }) start]; ``` #### delegate方式接收请求 ```objc // 当前类遵守HLAPIResponseDelegate协议 // 在初始化方法中设置当前类为回调监听 [HLAPIManager registerResponseObserver:self]; // 在这个宏中写入需要监听的api HLObserverAPIs(self.api1, self.api2) // 或者用-requestAPIs这个代理方法,这两个完全等效 - (NSArray *)requestAPIs { return [NSArray arrayWithObjects:self.api1, self.api2, self.api3, self.api4, nil]; } // 在下面三个代理方法中获取回调结果 // 这是成功的回调 - (void)requestSucessWithResponseObject:(id)responseObject atAPI:(HLAPI *)api { NSLog(@"\n%@------RequestSuccessDelegate\n", api); NSLog(@"%@", [NSThread currentThread]); } // 这是失败的回调 - (void)requestFailureWithResponseError:(NSError *)error atAPI:(HLAPI *)api { NSLog(@"\n%@------RequestFailureDelegate\n", api); NSLog(@"%@", [NSThread currentThread]); } // 这是进度的回调 - (void)requestProgress:(NSProgress *)progress atAPI:(HLAPI *)api { NSLog(@"\n%@------RequestProgress\n", api); NSLog(@"%@", [NSThread currentThread]); } // 切记在dealloc中释放当前控制器 - (void)dealloc { [HLAPIManager removeResponseObserver:self]; } ``` **注意1:**设置请求URL时,`setCustomURL`的优先级最高,其次是API中的`setBaseURL`,最后才是全局config中的`baseURL`,另无论是哪种`baseURL`都需要配合`setPath`使用。 **注意2:**一次请求必须有`{customURL}`或者`{config.baseURL | api.baseURL}``{api.path}`,如果`{customURL}`的参数错写成`{api.path}`中的无host urlString,也会被自动识别成`{api.path}`。 **注意3:**一个请求对象的回调 block (success/failure/progress/debug) 是非必需的(默认为 `nil`)。另外,需要注意的是,success/failure/debug等回调 Block 会在 config 设置的 `apiCallbackQueue ` 队列中被执行,但 progress 回调 Block 将在 NSURLSession 自己的队列中执行,而不是 `apiCallbackQueue `,但是所有的回调结果都会回落到主线程。 **注意4:**请求的delegate回调之所以这样设置,是为了可以跨类获取请求回调,因此使用起来稍微麻烦一些,如果只需要在当前类拿到回调,使用block方式即可。 **注意5:**HLAPI 同样支持其他 HTTP 方法,比如:`HEAD`, `DELETE`, `PUT`, `PATCH` 等,使用方式与上述类似,不再赘述。 详见 `HLNetworkConfig`、`HLSecurityPolicyConfig`、`HLAPI`、`HLAPIType` 、`HLAPIManager` 、`HLFormDataConfig`、`HLDebugMessage` 等几个文件中的代码和注释,可选参数基本可以覆盖大多数需求。 #### 请求的生命周期方法 ```objc // 在api组装时设置当前类为代理 [HLAPI API].setDelegate(self) // 请求即将发出的代理方法 - (void)requestWillBeSent { NSLog(@"willBeSent"); } // 请求已经发出的代理方法 - (void)requestDidSent { NSLog(@"didSent"); } ``` #### 自定义请求结果处理逻辑 ```objc // 指定的类需要遵守HLObjReformerProtocol协议 [HLAPI API].setObjReformerDelegate(self); /** 一般用来进行JSON -> Model 数据的转换工作。返回的id,如果没有error,则为转换成功后的Model数据。如果有error, 则直接返回传参中的responseObject @param api 调用的api @param responseObject 请求的返回 @param error 请求的错误 @return 整理过后的请求数据 */ - (nullable id)objReformerWithAPI:(HLAPI *)api andResponseObject:(id)responseObject andError:(NSError * _Nullable)error { if (responseObject) { // 在这里处理获得的数据 // 自定义reformer方法 MyModel *model = [MyReformer reformerWithResponse:responseObject]; return model; } else { // 在这里处理异常 return nil; } } ``` #### 取消一个网络请求 ```objc // 通过api取消网络请求 [self.api1 cancel]; // 通过HLAPIManager取消网络请求 [HLAPIManager cancel: self.api1]; ``` **注意:**如果请求已经发出,将无法取消,取消可以注销对应的回调block,但是delegate不会被注销。 ### 批量请求 #### 无序请求 HLNetworking 支持同时发一组批量请求,这组请求在业务逻辑上相关,但请求本身是互相独立的,请求时并行执行,`- apiGroupAllDidFinished` 会在所有请求都结束时才执行,每个请求的结果由API自身管理。注:`HLAPIGroup `类做了特殊处理,自身即为`HLAPI`的容器,因此直接`group[index]`即可获取相应的`HLAPI`对象,也可以直接遍历;回调中的 `apiGroup `中元素的顺序与每个无序请求 `HLAPI` 对象的先后顺序不保证一致。 ```obc HLAPIGroup *group = [HLAPIGroup groupWithMode:HLAPIGroupModeBatch]; // 添加单个api [group add:[HLAPI API]]; // 添加apis集合 [group addAPIs:@[api1, api2, api3, nil]]; [group start]; batch.delegate = self; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.5), dispatch_get_main_queue(), ^{ // 使用cancel取消 [group cancel]; }); // group全部完成之后调用 - (void)apiGroupAllDidFinished:(HLAPIGroup *)apiGroup { NSLog(@"%@", apiGroup); } ``` #### 链式请求 HLNetworking 同样支持发一组链式请求,这组请求之间互相依赖,下一请求是否发送以及请求的参数可以取决于上一个请求的结果,请求时串行执行,`- chainRequestsAllDidFinished` 会在所有请求都结束时才执行,每个请求的结果由API自身管理。注:`HLAPIGroup `类做了特殊处理,自身即为`HLAPI`的容器,因此直接`group[index]`即可获取相应的`HLAPI`对象,也可以直接遍历;回调中的 `apiGroup `中元素的顺序与每个链式请求 `HLAPI` 对象的先后顺序一致。 ```objc HLAPIGroup *group = [HLAPIGroup groupWithMode:HLAPIGroupModeChian]; group.delegate = self; // 设置每次发送几个请求,每次发出的请求之间无依赖 group.maxRequestCount = 1; [group addAPIs:@[self.api1, self.api2, self.api3, self.api4, self.api5]]; [group start]; for (id obj in group) { NSLog(@"%@", obj); } HLAPI *api = group[0]; // group[0] == self.api1 NSLog(@"%@", api); dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.5), dispatch_get_main_queue(), ^{ // 使用cancel取消 [group cancel]; }); // group全部完成之后调用 - (void)apiGroupAllDidFinished:(HLAPIGroup *)apiGroup { NSLog(@"%@", apiGroup); } ``` ### 网络可连接性检查 ```objc HLAPIManager提供了八个方法和四个属性用于获取网络的状态,分别如下: // reachability的状态 typedef NS_ENUM(NSUInteger, HLReachabilityStatus) { HLReachabilityStatusUnknown, HLReachabilityStatusNotReachable, HLReachabilityStatusReachableViaWWAN, HLReachabilityStatusReachableViaWiFi }; // 通过sharedMager单例,获取当前reachability状态 + (HLReachabilityStatus)reachabilityStatus; // 通过sharedMager单例,获取当前是否可访问网络 + (BOOL)isReachable; // 通过sharedMager单例,获取当前是否使用数据流量访问网络 + (BOOL)isReachableViaWWAN; // 通过sharedMager单例,获取当前是否使用WiFi访问网络 + (BOOL)isReachableViaWiFi; // 通过sharedMager单例,开启默认reachability监视器,block返回状态 + (void)listening:(void(^)(HLReachabilityStatus status))listener; // 通过sharedMager单例,停止reachability监视器监听domain + (void)stopListening; // 监听给定的域名是否可以访问,block内返回状态 - (void)listeningWithDomain:(NSString *)domain listeningBlock:(void (^)(HLReachabilityStatus))listener; // 停止给定域名的网络状态监听 - (void)stopListeningWithDomain:(NSString *)domain; ``` **注意:**reachability的监听domain默认为[HLNetworking sharedManager].config.baseURL,当然你也可以通过对象方法自定义domain。 ### HTTPS 请求的本地证书校验(SSL Pinning) 在你的应用程序包里添加 (pinned) 相应的 SSL 证书做校验有助于防止中间人攻击和其他安全漏洞。`HLNetworking`的`config`属性和`HLAPI`里有对AFNetworking 的 `AFSecurityPolicy` 安全模块的封装,你可以通过配置`config`内`defaultSecurityPolicy`属性,用于校验本地保存的证书或公钥可信任。 ```objc // SSL Pinning typedef NS_ENUM(NSUInteger, HLSSLPinningMode) { // 不校验Pinning证书 HLSSLPinningModeNone, // 校验Pinning证书中的PublicKey HLSSLPinningModePublicKey, // 校验整个Pinning证书 HLSSLPinningModeCertificate }; // 生成策略 HLSecurityPolicyConfig *securityPolicy = [HLSecurityPolicyConfig policyWithPinningMode:HLSSLPinningModePublicKey]; // 是否允许使用Invalid 证书,默认为 NO securityPolicy.allowInvalidCertificates = NO; // 是否校验在证书 CN 字段中的 domain name,默认为 YES securityPolicy.validatesDomainName = YES; //cer证书文件路径 securityPolicy.cerFilePath = [[NSBundle mainBundle] pathForResource:@"myCer" ofType:@"cer"]; // 设置默认的安全策略 [HLAPIManager setupConfig:^(HLNetworkConfig * _Nonnull config) { config.defaultSecurityPolicy = securityPolicy; }]; // 针对特定API的安全策略 self.api1.setSecurityPolicy(securityPolicy); ``` **注意:**API中的安全策略会在此api请求时覆盖默认安全策略,并且与api相同baseURL的安全策略都会被覆盖。 ### Task相关 HLTask目前支持上传下载功能,已支持断点续传,其中上传是指流上传,即使用UPLOAD方法;如果需要使用POST中的formData拼接方式上传,请参考API相关的formData设置 #### config设置 ```objc [HLTaskManager setupConfig:^(HLNetworkConfig * _Nonnull config) { config.baseURL = @"https://httpbin.org"; config.isBackgroundSession = NO; }]; [HLTaskManager registerResponseObserver:self]; ``` #### 链式调用组装Task ```objc HLTask *task = [[HLTask task].setDelegate(self) // 设置Task类型,Upload/Download .setTaskType(Upload) // 设置下载或者上传的本地文件路径 .setFilePath([[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"Boom2.dmg"]) // 设置下载或者上传的地址 .setCustomURL(@"https://dl.devmate.com/com.globaldelight.Boom2/Boom2.dmg") start]; ``` #### Task的生命周期方法 ```objc [HLTask task].setDelegate(self) #pragma mark - task request delegate // 请求即将发出 - (void)requestWillBeSentWithTask:(HLTask *)task { } // 请求已经发出 - (void)requestDidSentWithTask:(HLTask *)task { } ``` #### 请求回调代理 ``` [HLTaskManager shared].responseDelegate = self; #pragma mark - task reponse protocol // 设置监听的task HLObserverTasks(self.task1) // 等同于HLObserverTasks(...) - (NSArray *)requestTasks { return [NSArray arrayWithObjects:self.task1, nil]; } // 下载/上传进度回调 - (void)requestProgress:(nullable NSProgress *)progress atTask:(nullable HLTask *)task { NSLog(@"\n进度=====\n当前任务:%@\n当前进度:%@", task.customURL, progress); } // 任务完成回调 - (void)requestSucessWithResponseObject:(nonnull id)responseObject atTask:(nullable HLTask *)task { NSLog(@"\n完成=====\n当前任务:%@\n对象:%@", task, responseObject); } // 任务失败回调 - (void)requestFailureWithResponseError:(nullable NSError *)error atTask:(nullable HLTask *)task { NSLog(@"\n失败=====\n当前任务:%@\n错误:%@", task, error); } ``` ### 批量上传/下载任务 #### 无序任务 HLNetworking 支持同时发一组批量上传/下载任务,这组请求在业务逻辑上相关,但请求本身是互相独立的,请求时并行执行,`- taskGroupAllDidFinished` 会在所有请求都结束时才执行,每个请求的结果由API自身管理。注:`HLTaskGroup `类做了特殊处理,自身即为`HLTask`的容器,因此直接`group[index]`即可获取相应的`HLAPI`对象,也可以直接遍历;回调中的 `taskGroup `中元素的顺序与每个无序请求 `HLAPI` 对象的先后顺序不保证一致。 ```obc HLTaskGroup *group = [HLTaskGroup groupWithMode:HLTaskGroupModeBatch]; group.delegate = self; [group addTasks:self.taskArray]; [group start]; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.5), dispatch_get_main_queue(), ^{ // 使用cancel取消 [group cancel]; }); // group全部完成之后调用 - (void)apiGroupAllDidFinished:(HLAPIGroup *)apiGroup { NSLog(@"%@", apiGroup); } ``` #### 链式任务 HLNetworking 同样支持发一组链式请求,这组请求之间互相依赖,下一请求是否发送以及请求的参数可以取决于上一个请求的结果,请求时串行执行,`- chainRequestsAllDidFinished` 会在所有请求都结束时才执行,每个请求的结果由API自身管理。注:`HLAPIGroup `类做了特殊处理,自身即为`HLAPI`的容器,因此直接`group[index]`即可获取相应的`HLAPI`对象,也可以直接遍历;回调中的 `apiGroup `中元素的顺序与每个链式请求 `HLAPI` 对象的先后顺序一致。 ```objc HLTaskGroup *group = [HLTaskGroup groupWithMode: HLTaskGroup ModeChian]; group.delegate = self; // 设置每次发送几个请求,每次发出的请求之间无依赖 group.maxRequestCount = 1; [group addTasks:@[self.task1, self.task2, self.task3, self.task4, self.task5]]; [group start]; for (id obj in group) { NSLog(@"%@", obj); } HLTask *task = group[0]; // group[0] == self.task1 NSLog(@"%@", api); dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.5), dispatch_get_main_queue(), ^{ // 使用cancel取消 [group cancel]; }); // group全部完成之后调用 - (void)apiGroupAllDidFinished:(HLAPIGroup *)apiGroup { NSLog(@"%@", apiGroup); } ``` **注意1:**Task的resume信息记录在沙盒中`Cache/com.qkhl.HLNetworking/downloadDict中`。 ### Center相关 - ``HLAPICenter``提供一种离散式API的组织模版,其核心理念是通过category分散APICenter内的API对象; - ``HLBaseObjReformer``提供了基于YYModel的JSON->Model的模版; - 通过``HLAPIMacro``中定义的宏,可以快速设置模块所需的API #### 范例 - 根据API相关中的设置,配置HLAPIManager的相关Config - 根据模块创建``HLAPICenter``的category,例如``HLAPICenter+home`` - 在HLAPICenter+home.h中使用HLStrongProperty(name)宏,name为方法名,形如: ```objc #import "HLAPICenter.h" @interface HLAPICenter (home) HLStrongProperty(home) @end ``` - 在HLAPICenter+home.m中使用HLStrongSynthesize(name, api)宏,name为方法名,api为API对象,形如: ```objc #import "HLAPICenter+home.h" @implementation HLAPICenter (home) HLStrongSynthesize(home, [HLAPI API] .setMethod(GET) // 根据需要设置Path、BaseURL、CustomURL .setPath(@"index.php?r=home") // 如果该api对应的model可以直接通过yymodel转换的话,则指定需转换的模型类型名 .setResponseClass(@"HLHomeModel") // 这里使用self.defaultReformer即通过yymodel转换 .setObjReformerDelegate(self.defaultReformer)) @end ``` - 然后就可以愉快的使用了,在控制器中```#import "HLAPICenter+home.h"```,按如下方法使用即可: ```objc - (void)testHome { [HLAPICenter.home.setParams(@{@"user_id": @self.myUserID}) .success(^(HLHomeModel *model) { self.model = model; }).failure(^(NSError *obj){ NSLog(@"----%@", obj); }) start]; } ``` ### Logger相关 - `HLNetworkLogger`提供了记录网络请求信息日志的功能,可自定义日志结构,日志头部信息,日志存储类型等 #### 配置Logger 可选参数如下: - **channelID**:渠道ID - **appKey**:app标志 - **appName**:app名字 - **appVersion**:app版本 - **serviceType**:服务名 - **enableLocalLog**:是否开启本地日志 - **logAutoSaveCount**:日志自动保存数,默认为50次保存一次 - **loggerLevel**:日志等级,该选项暂时无效 - **loggerType**:日志保存类型,可选JSON或者Plist - **logFilePath**:只读,默认为`sandbox/Library/Cache/com.qkhl.HLNetworking/log/{timestamp}.log` - 范例 ```objc [HLNetworkLogger setupConfig:^(HLNetworkLoggerConfig *config) { config.enableLocalLog = YES; config.logAutoSaveCount = 50; config.loggerType = HLNetworkLoggerTypeJSON; }]; [HLNetworkLogger startLogging]; ``` #### 默认Logger信息 - `HLNetworkLogger`默认提供的log信息为`HLDebugMessage`对象,包括: - `requestObject` api/task请求对象, - `sessionTask` NSURLSessionTask对象, - `response` HLURLResponse对象, - `queue` dispatch_queue_t对象, - 具体信息请参考`HLDebugMessage`,`HLURLResponse `,`HLURLResult`这三个文件中的注释 - `HLNetworkLogger`通过管理`debugInfoArray`数组来存储信息,该数组的首元素为当前APP信息,默认如下: - @{@"AppInfo": @{@"OSVersion": [UIDevice currentDevice].systemVersion, - @"DeviceType": [UIDevice currentDevice].hl_machineType, - @"UDID": [UIDevice currentDevice].hl_udid, - @"UUID": [UIDevice currentDevice].hl_uuid, - @"MacAddressMD5": [UIDevice currentDevice].hl_macaddressMD5, - @"ChannelID": _config.channelID, - @"AppKey": _config.appKey, - @"AppName": _config.appName, - @"AppVersion": _config.appVersion, - @"ServiceType": _config.serviceType}} #### 自定义Logger信息 - `HLNetworkLogger`提供自定义log信息内容的方法,该方法每发一次请求,回调时都会调用一次: ```objc // 设置当前类为logger代理,并将当前类遵守HLNetworkCustomLoggerDelegate协议 [HLNetworkLogger setDelegate:self]; // 根据传入的message信息和其他信息组装字典数据 - (NSDictionary *)customInfoWithMessage:(HLDebugMessage *)message { return [message toDictionary]; } // 根据传入的config信息和其他信息组装字典 - (NSDictionary *)customHeaderWithMessage:(HLNetworkLoggerConfig *)config { return @{@"AppInfo": @{@"OSVersion": [UIDevice currentDevice].systemVersion, @"DeviceType": [UIDevice currentDevice].hl_machineType, @"UDID": [UIDevice currentDevice].hl_udid, @"UUID": [UIDevice currentDevice].hl_uuid, @"MacAddressMD5": [UIDevice currentDevice].hl_macaddressMD5, @"ChannelID": config.channelID, @"AppKey": config.appKey, @"AppName": config.appName, @"AppVersion": config.appVersion, @"ServiceType": config.serviceType}}; } ``` ### 更新日志 **1.3.2** ``` 新增: 1. 将AFNetworking相关抽取为HLAPIEngine类,提供基础的网络功能 2. HLTask加入成功、失败、进度的Block 修复: 1. 精简HLAPIManager和HLTaskManager内部代码结构 ``` **1.3.1** ``` 修复: 1. 修复了HLNetworkLogger setDelegate方法调用错误的bug 2. 修复了HLTask缺少toDictionary方法的错误 ``` **1.3.0** ``` 新增: 1. HLNetworkLogger类,用于记录日志,控制台打印全局日志,本地日志记录,默认为50条请求保存一次,可自定义info和header代理 2. 网络链接不好的情况下自动重试的功能 3. HLAPIGroup类,统一chain和batch,通过构造方法的HLAPIGroupMode区分类型(chain, batch),提供maxRequestCount属性,可以控制chainRequest每次的并行请求数,默认为1 4. HLTaskGroup,用法与HLAPIGroup一样,用于管理一组task请求 移除 1. chain和batch类 修复: 1. 修复了链式请求 请求重复时的线程调度问题 2. 修复了某些情况下并发请求会导致线程死锁的问题 3. 优化内部调用结构 ``` **1.2.2** ``` 新增: 1. 拆分了HLNetworkConfig内的参数,现分为tips、request、policy、defaultSecurityPolicy、enableReachability这五个大选项 修复: 1. 修复了HLObserverAPIs(...)和HLObserverTasks(...)内传入nil引起的崩溃错误 2. 修复了HLAPI中setResponseClass方法传入无效类名引起的崩溃错误,当该类名无效时,HLBaseObjReformer将不会做任何操作,直接返回nil 3. 修复了HLAPI中setCustomURL方法传入无效urlString引起的崩溃错误 ``` ## 环境要求 该库需运行在 iOS 8.0 和 Xcode 7.0以上环境. ## 集成方法 HLNetworking 可以在[CocoaPods](http://cocoapods.org)中获取,将以下内容添加进你的Podfile中后,运行`pod install`即可安装: ```ruby pod "HLNetworking" ``` 如果你只需要用到API相关,可以这样: ```ruby pod "HLNetworking/API" ``` 目前有四个模块可供选择: - HLNetworking/Core - HLNetworking/API - HLNetworking/Task - HLNetworking/Center 其中`Core`包含`API`和`Task`的所有代码,`API`和`Task`相互独立,`Center`则依赖于`API` ## 作者 wangshiyu13, wangshiyu13@163.com ## 开源协议 HLNetworking is available under the MIT license. See the LICENSE file for more info.