XMNetwoking 是咱们团队开源的一个网络库,详见:GitHubphp
XMNetworking 是一个轻量的、简单易用但功能强大的网络库,基于 AFNetworking 3.0 封装。
其中,XM
前缀是咱们团队 Xcode-Men 的缩写。英文文档ios
XMNetworking.pnggit
如上图所示,XMNetworking 采用中心化的设计思想,由 XMCenter
统一发起并管理全部的 XMRequest
请求,并可经过 XMCenter
给全部请求配置回调线程、公共 Server URL、Header、Parameter 等信息,同时也能够 Block 注入的方式实现自定义的响应结果处理逻辑,如数据模型转换、业务错误码判断、网络缓存等。另外增长了 XMEgine
这一层是为了隔离底层第三方库依赖,便于之后切换其余底层网络库或本身实现底层逻辑。github
在你工程的 Podfile
文件中添加以下一行,并执行 pod install
或 pod update
。api
pod 'XMNetworking'
注意: XMNetworking
已经包含了 AFNetworking
3.1.0 的源代码,因此你工程里的 Podfile
文件不能再添加 pod AFNetworking
去导入 AFNetworking
,不然会有冲突!缓存
与 CocoaPods 不一样的是,Carthage 是一个去中心化的第三方依赖库管理工具,它自动帮你编译所依赖的第三方库并以 framework 形式提供给你。安全
你能够经过 Homebrew 执行如下命令来安装 Carthage:服务器
$ brew update $ brew install carthage
成功安装完 Carthage 后,在你工程的 Cartfile
文件中添加以下一行:网络
github "kangzubin/XMNetworking"
而后执行 carthage update --platform ios
命令生成 framework 包,并把生成的 XMNetworking.framework
拖拽到你的工程中。session
注意: XMNetworking
已经包含了 AFNetworking
3.1.0 的源代码,因此你无需经过 Carthage 生成 AFNetworking.framework
导到你工程中,不然会有冲突!
下载 XMNetworking
子文件夹的全部内容,并把其中的源文件添加(拖放)到你的工程中。
#import <XMNetworking/XMNetworking.h>
#import "XMNetworking.h"
[XMCenter setupConfig:^(XMConfig *config) { config.generalServer = @"general server address"; config.generalHeaders = @{@"general-header": @"general header value"}; config.generalParameters = @{@"general-parameter": @"general parameter value"}; config.generalUserInfo = nil; config.callbackQueue = dispatch_get_main_queue(); #ifdef DEBUG config.consoleLog = YES; #endif }];
你能够调用 XMCenter
的 +setupConfig:
类方法,经过修改传入的 XMConfig
对象来配置全局网络请求的公共信息,包括以下:
server
属性为 nil
,且其 useGeneralServer
为 YES
(默认),那么该请求的服务端地址 server
将会取 XMCenter 中 generalServer
的值。useGeneralParameters
属性为 YES
(默认),而且 XMCenter 的公共参数 generalParameters
不为空,那么这些公共参数会自动加到该请求的 parameters
中。useGeneralHeaders
属性为 YES
(默认),而且 XMCenter 的公共请求头 generalHeaders
不为空,那么这些公共请求头会自动加到该请求的 headers
中。nil
,若是一个 XMRequest 请求对象的 userInfo
属性为 nil
(默认)而该字段不为 nil
,那么该字段会自动赋值给 XMRequest
对象的 userInfo
。而 userInfo
属性可用于区分具备相同上下文信息的不一样请求。NULL
(默认),那么会在一个私有的并发队列(子线程)中执行回调 Block。BOOL
值,用于表示是否在控制台输出请求和响应的信息,默认为 NO
。另外,你能够经过调用 XMCenter
的如下两个类方法来随时修改全局公共的 header 和 parameter:
+ (void)setGeneralHeaderValue:(nullable NSString *)value forField:(NSString *)field; + (void)setGeneralParameterValue:(nullable NSString *)value forKey:(NSString *)key;
[XMCenter sendRequest:^(XMRequest *request) { request.url = @"http://example.com/v1/foo/bar"; //request.server = @"http://example.com/v1/"; //request.api = @"foo/bar"; request.parameters = @{@"param1": @"value1", @"param2": @"value2"}; request.headers = @{@"User-Agent": @"Custom User Agent"}; request.httpMethod = kXMHTTPMethodGET; } onSuccess:^(id responseObject) { NSLog(@"onSuccess: %@", responseObject); } onFailure:^(NSError *error) { NSLog(@"onFailure: %@", error); } onFinished:^(id responseObject, NSError *error) { NSLog(@"onFinished"); }];
注意1:能够经过如下两种方法设置一个请求对象的 URL 地址,但当 server
、api
和 url
三个属性被同时赋值时,url
的优先级比较高,而此时 server
、api
的值会被忽略。
request.url = @"http://example.com/v1/foo/bar";
// 若是 request.server 为 `nil`,且 request.useGeneralServer 为 `YES`,那么此时 request.server 会取 XMCenter.generalServer 的值。 request.server = @"http://example.com/v1/"; request.api = @"foo/bar";
注意2:一个请求对象的回调 Block (success/failure/finished/progress) 是非必需的(默认为 nil
),XMCenter 提供了多个设置不一样回调 Block 参数的方法用于发送请求。另外,须要注意的是,success/faillure/finished 等回调 Block 会在 XMCenter 设置的 callbackQueue
队列中被执行,但 progress 回调 Block 将在 NSURLSession 本身的队列中执行,而不是 callbackQueue
。
[XMCenter sendRequest:^(XMRequest *request) { //request.server = @"http://example.com/v1/"; // 可选,若是为空则读取 XMCenter.generalServer request.api = @"foo/bar"; request.parameters = @{@"param1": @"value1", @"param2": @"value2"}; request.httpMethod = kXMHTTPMethodPOST; // 可选,默认为 `POST` request.requestType = kXMRequestNormal; // 可选,默认为 `Normal` } onSuccess:^(id responseObject) { NSLog(@"onSuccess: %@", responseObject); } onFailure:^(NSError *error) { NSLog(@"onFailure: %@", error); }];
XMRequest 一样支持其余 HTTP 方法,好比:HEAD
, DELETE
, PUT
, PATCH
等,使用方式与上述相似,再也不赘述。
详见 XMConst
、XMRequest
和 XMCenter
等几个文件中的代码和注释。
// `NSData` form data. UIImage *image = [UIImage imageNamed:@"testImage"]; NSData *fileData1 = UIImageJPEGRepresentation(image, 1.0); // `NSURL` form data. NSString *path = [NSHomeDirectory() stringByAppendingString:@"/Documents/testImage.png"]; NSURL *fileURL2 = [NSURL fileURLWithPath:path isDirectory:NO]; [XMCenter sendRequest:^(XMRequest *request) { request.server = @"http://example.com/v1/"; request.api = @"foo/bar"; request.requestType = kXMRequestUpload; [request addFormDataWithName:@"image[]" fileName:@"temp.jpg" mimeType:@"image/jpeg" fileData:fileData1]; [request addFormDataWithName:@"image[]" fileURL:fileURL2]; // see `XMUploadFormData` for more details. } onProgress:^(NSProgress *progress) { // the progress block is running on the session queue. if (progress) { NSLog(@"onProgress: %f", progress.fractionCompleted); } } onSuccess:^(id responseObject) { NSLog(@"onSuccess: %@", responseObject); } onFailure:^(NSError *error) { NSLog(@"onFailure: %@", error); } onFinished:^(id responseObject, NSError *error) { NSLog(@"onFinished"); }];
[XMCenter sendRequest:^(XMRequest *request) { request.url = @"http://example.com/v1/testDownFile.zip"; request.downloadSavePath = [NSHomeDirectory() stringByAppendingString:@"/Documents/"]; request.requestType = kXMRequestDownload; } onProgress:^(NSProgress *progress) { // the progress block is running on the session queue. if (progress) { NSLog(@"onProgress: %f", progress.fractionCompleted); } } onSuccess:^(id responseObject) { NSLog(@"onSuccess: %@", responseObject); } onFailure:^(NSError *error) { NSLog(@"onFailure: %@", error); }];
XMRequest
中有两个属性 requestSerializerType
和 responseSerializerType
分别用于设置请求参数和响应结果的序列化类型。
其中,XMRequestSerializerType
和 XMResponseSerializerType
枚举的定义以下:
typedef NS_ENUM(NSInteger, XMRequestSerializerType) { kXMRequestSerializerRAW = 0, // default kXMRequestSerializerJSON = 1, kXMRequestSerializerPlist = 2, };
typedef NS_ENUM(NSInteger, XMResponseSerializerType) { kXMResponseSerializerRAW = 0, kXMResponseSerializerJSON = 1, // default kXMResponseSerializerPlist = 2, kXMResponseSerializerXML = 3, };
详见 AFURLRequestSerialization.h
和 AFURLResponseSerialization.h
获取更多细节。
一般地,一个请求成功结束时,会执行 success block,当有错误发生时,执行 failure block。然而,开发中更常见的状况是,即便是一个请求成功结束,咱们也须要进一步处理,好比验证响应结果数据、判断与服务端商量好的业务错误码类型等,再决定执行 success block 仍是 failure block。
如今,你能够调用 [XMCenter setResponseProcessBlock:...]
方法以 Block 注入的方式设置自定义的处理逻辑,当请求成功结束时,这个 Block 会在 success block 被执行前调用,若是传入 *error
参数被赋值,则接下来会执行 failure block。
[XMCenter setResponseProcessBlock:^(XMRequest *request, id responseObject, NSError *__autoreleasing *error) { // 自定义响应结果处理逻辑,若是 `*error` 被赋值,则接下来会执行 failure block。 }];
XMNetworking 支持同时发一组批量请求,这组请求在业务逻辑上相关,但请求自己是互相独立的,success block 会在全部请求都成功结束时才执行,而一旦有一个请求失败,则会执行 failure block。注:回调 Block 中的 responseObjects
和 errors
中元素的顺序与每一个 XMRequest 对象在 batchRequest.requestArray
中的顺序一致。
[XMCenter sendBatchRequest:^(XMBatchRequest *batchRequest) { XMRequest *request1 = [XMRequest request]; request1.url = @"server url 1"; // set other properties for request1 XMRequest *request2 = [XMRequest request]; request2.url = @"server url 2"; // set other properties for request2 [batchRequest.requestArray addObject:request1]; [batchRequest.requestArray addObject:request2]; } onSuccess:^(NSArray<id> *responseObjects) { NSLog(@"onSuccess: %@", responseObjects); } onFailure:^(NSArray<id> *errors) { NSLog(@"onFailure: %@", errors); } onFinished:^(NSArray<id> *responseObjects, NSArray<id> *errors) { NSLog(@"onFinished"); }];
[XMCenter sendBatchRequest:...]
方法会返回刚发起的新的 XMBatchRequest
对象,你能够保存这个对象,并在必要的时候调用它的 -cancelWithBlock:
方法取消这组批量请求。
XMNetworking 一样支持发一组链式请求,这组请求之间互相依赖,下一请求是否发送以及请求的参数取决于上一个请求的结果,success block 会在全部的链式请求都成功结束时才执行,而中间一旦有一个请求失败,则会执行 failure block。注:回调 Block 中的 responseObjects
和 errors
中元素的顺序与每一个链式请求 XMRequest
对象的前后顺序一致。
[XMCenter sendChainRequest:^(XMChainRequest *chainRequest) { [[[[chainRequest onFirst:^(XMRequest *request) { request.url = @"server url 1"; // set other properties for request }] onNext:^(XMRequest *request, id responseObject, BOOL *sendNext) { NSDictionary *params = responseObject; if (params.count > 0) { request.url = @"server url 2"; request.parameters = params; } else { *sendNext = NO; } }] onNext:^(XMRequest *request, id responseObject, BOOL *sendNext) { request.url = @"server url 3"; request.parameters = @{@"param1": @"value1", @"param2": @"value2"}; }] onNext: ...]; } onSuccess:^(NSArray<id> *responseObjects) { NSLog(@"onSuccess: %@", responseObjects); } onFailure:^(NSArray<id> *errors) { NSLog(@"onFailure: %@", errors); } onFinished:^(NSArray<id> *responseObjects, NSArray<id> *errors) { NSLog(@"onFinished"); }];
[XMCenter sendChainRequest:...]
方法会返回刚发起的新的 XMChainRequest
对象,你能够保存这个对象,并在必要的时候调用它的 -cancelWithBlock:
方法取消这组链式请求。
当调用 [XMCenter sendRequest:...]
方法发送一个网络请求时,该方法会返回一个用于惟一标识该请求对象的 identifier
(若是请求发送失败,该值为 0
)。在必要的时候,你能够经过这个 identifier
来取消当前网络请求(若是一个请求已经结束,这时再用 identifier
来取消该请求时,会直接忽略)。
// send a request NSUInteger identifier = [XMCenter sendRequest:^(XMRequest *request) { request.server = @"https://kangzubin.cn/"; request.api = @"test/index.php"; request.httpMethod = kXMHTTPMethodGET; request.timeoutInterval = 10; request.retryCount = 1; } onFailure:^(NSError *error) { NSLog(@"onFailure: %@", error); }]; // your business code sleep(2); // cancel the running request by identifier with cancel block [XMCenter cancelRequest:identifier onCancel:^(XMRequest *request) { NSLog(@"onCancel"); }];
注意:调用 XMCenter cancelRequest:onCancel:
方法取消一个网络请求时,被取消的请求对象(若是存在)会以参数的形式传给 cancel block,另外 cancel block 是在当前调用 cancelRequest:
方法的线程中执行,并非 XMCenter 的 callbackQueue
。
咱们提供了两种方法用于获取网络的可链接性,分别以下:
[XMCenter isNetworkReachable]; // 该方法会返回一个 Bool 值用于表示当前网络是否可链接。
[[XMEngine sharedEngine] networkReachability]; // 该方法会返回一个当前网络的状态值,-1 表示 `Unknown`,0 表示 `NotReachable,1 表示 `WWAN`,2 表示 `WiFi`
详见 AFNetworkReachabilityManager
获取更多细节.
在你的应用程序包里添加 (pinned) 相应的 SSL 证书作校验有助于防止中间人攻击和其余安全漏洞。很是方便的是,AFNetworking 的 AFSecurityPolicy
安全模块能够经过校验本地保存的证书或公钥帮助咱们评估服务器是否可信任以及创建安全链接。
咱们在 XMEngine
中暴露了一个 AFHTTPSessionManager
对象叫 sessionManager
,你能够经过修改该对象的 securityPolicy
类型,以开启 SSL Pinning 功能,并把大家服务器对应的 .cer
证书或者公钥放到你的工程中。
[XMEngine sharedEngine].sessionManager.securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];
详见 AFSecurityPolicy
获取更多细节.
详见 XMNetworking Documents Link.
XMNetworking 的代码结构很是简洁和紧凑,只包含了 4 个核心文件:XMConst.h
用于定义全局常量枚举和 Block,XMRequest
,XMCenter
和 XMEngine
则是核心类的声明和实现,具体的代码结构以下图所示:
Architecture.png
XMNetworking 使用 MIT 许可证,详情见 LICENSE 文件。
文/XcodeMen(简书做者) 原文连接:http://www.jianshu.com/p/a5c5e9aa5913