JKNetworking_ 0.2.9.3

JKNetworking_ 0.2.9.3

jack 维护。



 
依赖项
AFNetworking>= 0
JKDataHelper>= 0
 

  • 作者
  • xindizhiyin2014

JKNetworking

CI Status Version License Platform

示例

要运行示例项目,请克隆仓库,并首先从 Example 目录运行 pod install

需求

安装

JKNetworking 通过 CocoaPods 提供。要安装它,只需将以下行添加到您的 Podfile 中

pod 'JKNetworking_'

作者

xindizhiyin2014, [email protected]

前言

此网络请求框架主要参考了YTKNetwork的实现思路,结合本工程进行了进一步的封装,该框架更适用于大规模业务、较为复杂的app。

基本组成

JKNetworking脑图

具体功能

基本功能

支持进行正常的GET、POST、PUT、DELETE、HEAD,PATH等网络请求,可以实现文件的上传和下载等功能。大多数网络请求都能实现。

高级功能

1)支持链式网络请求

   指的不是链式网络请求,就是一个请求结束之后,再执行下一个网络请求。一个网络请求开始的前提必须是上一个网络请求成功结束。允许提前结束链式网络请求。

2)支持类组队列的网络请求

  组队列发送网络请求,一组网络请求异步发送,可以指定某些请求是必须要成功的请求,只有当指定的请求都成功时,才会执行组队列的成功回调;如果指定的任意一个请求失败,则会执行组队列的失败回调。如果没有指定必须成功的请求,那么只要有一个请求成功,那么等到所有的请求执行完,执行组队列的成功回调;如果所有的请求都失败了,则执行组队列的失败回调。

3)支持启动时的网络请求依赖

  支持启动时所有的网络请求都依赖于一个单独的网络请求,或者链式组合请求,或者类组队列组合网络请求。只有在依赖的网络请求执行完成后,其他的网络请求才会执行。这通常用于APP有启动配置的情况。

4)支持网络请求的取消

   支持网络请求的取消有两种情况,第一种是网络请求尚在网络请求池中但尚未发送,直接将此网络请求从请求池中移除;第二种是网络请求已发送但尚未收到返回。此时移除对应的回调,待网络请求返回时不再执行额外逻辑,节省资源,避免出错。

5)支持mock

  支持对网络请求进行mock配置,能拦截指定接口,并重定向到指定mock平台或本地服务器等,以实现高效的并行开发。

6)支持资源文件下载优先走cdn

   如果项目中的资源文件已配置在cdn,可以使用优先使用cdn资源的选项。

7)支持网络请求安全策略配置

  可以实现网络请求安全策略的配置,支持全局配置和局部配置(针对某些特定的网络请求)。

8)支持文件下载时断点续传,后台下载

支持下载文件时的断点续传;支持文件下载时app进入后台,仍然可以下载,方便大文件的下载。

扩展型功能

1)支持请求加签

  能够支持不同规则的网络请求加签。甚至是同一个应用中能够支持多套网络请求加签规则。

2)支持接口缓存

  能够支持对接口返回数据的缓存,设置缓存时间等,甚至在一个应用中可以支持多套缓存框架,替换某一个时能够做到平稳过渡。

3)支持域名动态更换

   支持域名动态更换,肯定也支持域名的全局更换了,避免由于域名问题给app使用带来麻烦。可以支持多套域名更换及系统,能够做到平滑的过渡到某个系统。

4)全局配置网络请求指示器

  能够全局的配置网络请求指示器,网络请求开始,自动出现,网络请求结束自动消失,同时对于某一个或者某一些可以配置自定义的网络请求指示器。

5)请求url配置公共参数

  支持在发送网络请求前,能够对url添加公共的path,以及公共query参数。既能够实现全局配置,也可以对某些,某个请求单独配置。

6)支持在子线程处理数据解析过程

数据解析转换为模型是一个耗时操作,将该过程放在子线程执行,可以降低主线程时间消耗,减少卡顿概率

使用教程

1) 全局配置

[JKNetworkConfig sharedConfig].baseUrl = @"https://abcd.com";
   [[JKNetworkConfig sharedConfig] configRequestHelper:[JKRequestHelper new]];
    //JKRequestHelper 是JKRequestHelperProtocol协议的实现者,如果只是实现基本功能,这一行代码不需要

1)普通的网络请求

GET请求

JKRequest *request = [JKRequest new];
request.requestUrl = @"/a1";
[request startWithCompletionBlockWithSuccess:^(__kindof JKRequest * request) {
NSLog(@"AAA %@",request.responseJSONObject);
} failure:^(__kindof JKRequest * request) {

}];

POST请求


JKRequest *request = [JKRequest new];
request.requestUrl = @"/a2";
request.requestMethod = JKRequestMethodPOST;
request.requestArgument = @{@"name":@"jack"};
[request startWithCompletionBlockWithSuccess:^(__kindof JKRequest * request) {
NSLog(@"BBB %@",request.responseJSONObject);
} failure:^(__kindof JKRequest * request) {

}];

下载请求

JKDownloadRequest *downloadRequest = [JKDownloadRequest initWithUrl:@"http://g.hiphotos.baidu.com/image/pic/item/c2cec3fdfc03924590b2a9b58d94a4c27d1e2500.jpg"];
downloadRequest.backgroundPolicy = JKDownloadBackgroundRequire;// 下载文件有三种下载策略,大家感兴趣的话可以搜下JKDownloadBackgroundPolicy 这个枚举
[downloadRequest downloadWithProgress:^(NSProgress * _Nonnull downloadProgress) {
NSLog(@"progress %@",downloadProgress.localizedDescription);
} success:^(__kindof JKRequest * request) {
NSLog(@"success %@",downloadRequest.downloadedFilePath);
} failure:^(__kindof JKRequest * request) {
NSLog(@"failure");
}];

组合网络请求

BatchRequest

JKRequest *request1 = [JKRequest new];
request1.requestUrl = @"/a1";
JKRequest *request2 = [JKRequest new];
request2.requestUrl = @"/a2";
request2.requestMethod = JKRequestMethodPOST;
request2.requestArgument = @{@"name":@"jack"};
JKBatchRequest *batchRequest = [[JKBatchRequest alloc] init];
[batchRequest addRequestsWithArray:@[request1,request2]];
[batchRequest startWithCompletionBlockWithSuccess:^(JKBatchRequest * _Nonnull batchRequest) {
JKRequest *requestA = batchRequest.requestArray.firstObject;
JKRequest *requestB = batchRequest.requestArray.lastObject;
NSLog(@"AAA %@",requestA.responseJSONObject);
NSLog(@"BBB %@",requestB.responseJSONObject);

} failure:^(JKBatchRequest * _Nonnull batchRequest) {

}];

ChainRequest

1)正常用法

JKRequest *request1 = [JKRequest new];
request1.requestUrl = @"/a1";
request1.responseSerializerType = JKResponseSerializerTypeJSON;
JKRequest *request2 = [JKRequest new];
request2.requestUrl = @"/a2";
request2.requestMethod = JKRequestMethodPOST;
request2.responseSerializerType = JKResponseSerializerTypeJSON;
request2.requestArgument = @{@"name":@"jack"};
JKChainRequest *chainRequest = [JKChainRequest new];
[chainRequest addRequest:request1];
[chainRequest addRequest:request2];
[chainRequest startWithCompletionBlockWithSuccess:^(JKChainRequest * _Nonnull chainRequest) {

} failure:^(JKChainRequest * _Nonnull chainRequest) {

}];

2)提前结束

JKRequest *request1 = [JKRequest new];
request1.requestUrl = @"/a1";
request1.responseSerializerType = JKResponseSerializerTypeJSON;
JKRequest *request2 = [JKRequest new];
request2.requestUrl = @"/a2";
request2.requestMethod = JKRequestMethodPOST;
request2.responseSerializerType = JKResponseSerializerTypeJSON;
request2.requestArgument = @{@"name":@"jack"};
JKChainRequest *chainRequest = [JKChainRequest new];
[JKChainRequest configNormalRequest:request1 success:^(__kindof JKRequest * _Nonnull request) {
	// 此处,如果传入参数为NO,那么chainRequest会执行failure 回调;如果传入YES,那么chainRequest会执行success 回调
    [request1 inAdvanceCompleteGroupRequestWithResult:YES];
} failure:^(__kindof JKRequest * _Nonnull request) {

}];

[JKChainRequest configNormalRequest:request2 success:^(__kindof JKRequest * _Nonnull request) {
 // 此处用来处理子网络请求的逻辑
} failure:^(__kindof JKRequest * _Nonnull request) {

}];

[chainRequest addRequest:request1];
[chainRequest addRequest:request2];
[chainRequest startWithCompletionSuccess:^(JKChainRequest * _Nonnull chainRequest) {
    
} failure:^(JKChainRequest * _Nonnull chainRequest) {
                
}];

PriorityFirstRequest 添加一个网络请求,可以是单独的网络请求也可以是组合请求,所有请求必须在该优先级网络请求完成后才能执行。

1)JKRequest

- (void)priorityFirstRequest
{
  JKRequest *request = [JKRequest new];
  request.requestUrl = @"/a1";
  request.responseSerializerType = JKResponseSerializerTypeJSON;
  [[JKNetworkAgent sharedAgent] addPriorityFirstRequest:request];
}
  1. JKChainRequest
- (void)priorityFirstRequest2
{
	JKRequest *request1 = [JKRequest new];
	request1.requestUrl = @"/a3";
	request1.responseSerializerType = JKResponseSerializerTypeJSON;
	JKRequest *request2 = [JKRequest new];
	request2.requestUrl = @"/a2";
	request2.requestMethod = JKRequestMethodPOST;
	request2.responseSerializerType = JKResponseSerializerTypeJSON;
	request2.requestArgument = @{@"name":@"jack"};
	JKChainRequest *chainRequest = [JKChainRequest new];
	[chainRequest addRequest:request1];
	[chainRequest addRequest:request2];
	[[JKNetworkAgent sharedAgent] addPriorityFirstRequest:chainRequest];
}

  1. JKBatchRequest
- (void)priorityFirstRequest3
{
	JKRequest *request1 = [JKRequest new];
	request1.requestUrl = @"/a3";
	request1.responseSerializerType = JKResponseSerializerTypeJSON;
	JKRequest *request2 = [JKRequest new];
	request2.requestUrl = @"/a2";
	request2.requestMethod = JKRequestMethodPOST;
	request2.responseSerializerType = JKResponseSerializerTypeJSON;
	request2.requestArgument = @{@"name":@"jack"};
	JKBatchRequest *batchRequest = [JKBatchRequest new];
   [batchRequest addRequestsWithArray:@[request1,request2]];
   [[JKNetworkAgent sharedAgent] addPriorityFirstRequest:batchRequest];
}

mock

需要对JKMockManager进行配置,因为这个功能不常用,感兴趣的可以查看JKMockManager.m配置字典。有两种mock方式:一种是对使用该网络请求库的请求进行mock,另一种是对所有网络请求进行mock,下面展示的是第二种方式的部分代码。

对使用该网络请求框架的请求进行mock

- (void)mockRequest
{
[JKNetworkConfig sharedConfig].baseUrl = @"https://www.baidu.com";
[JKNetworkConfig sharedConfig].mockBaseUrl = @"https://123.com/mock/17";
[JKNetworkConfig sharedConfig].isMock = YES;
NSDictionary *config = @{@"GET,/a1":@{}};
[JKMockManager initMockConfig:config];
JKRequest *request = [JKRequest new];
request.requestUrl = @"/a1";
request.responseSerializerType = JKResponseSerializerTypeJSON;
[request startWithCompletionBlockWithSuccess:^(__kindof JKRequest * request) {
NSLog(@"AAA %@",request.responseJSONObject);
} failure:^(__kindof JKRequest * request) {

}];
}

对所有网络请求进行mock

- (void)mockRequest1
{
[JKNetworkConfig sharedConfig].mockBaseUrl = @"https://123.com/mock/17";
[JKNetworkConfig sharedConfig].isMock = YES;
NSDictionary *config = @{@"GET,/a1":@{}};
[JKMockManager initMockConfig:config];
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
configuration.protocolClasses = @[[JKMockURLProtocol class]];
AFHTTPSessionManager *sessionManager = [[AFHTTPSessionManager alloc] initWithSessionConfiguration:configuration];
AFHTTPRequestSerializer *requestSerializer = [AFHTTPRequestSerializer serializer];
sessionManager.securityPolicy = [AFSecurityPolicy defaultPolicy];
sessionManager.responseSerializer = [AFHTTPResponseSerializer serializer];
NSMutableURLRequest *request = [requestSerializer requestWithMethod:@"GET" URLString:@"https://www.baidu.com/a1" parameters:nil error:nil];
NSURLSessionTask *dataTask = [sessionManager dataTaskWithRequest:request uploadProgress:nil downloadProgress:nil completionHandler:^(NSURLResponse * _Nonnull response, id _Nullable responseObject, NSError * _Nullable error) {
NSLog(@"AAA %@",responseObject);
}];
[dataTask resume];

}

使用外部URL发起网络请求框架

1)单个外部网络请求

// 拼接从AppStore获取更新信息的网址
    NSString *requestUrl = [NSString stringWithFormat:@"https://itunes.apple.com/lookup?id=%@", appId];
    JKRequest *request = [[JKRequest alloc] init];
    request.customRequestUrl = requestUrl;
    request.requestMethod = JKRequestMethodGET;
    request.requestSerializerType = JKRequestSerializerTypeHTTP;
    request.responseSerializerType = JKResponseSerializerTypeJSON;
    [request startWithCompletionSuccess:^(__kindof JKRequest * _Nonnull request) ....

2)一组外部网络请求,如果是同一个供应商,一般域名相同,可以定义一个JKRequest子类,初始化时将请求的baseUrl进行配置。

向请求添加签名

一般情况下接口都需要添加签名,不同的签名规则,需要创建不同的JKRequest子类 进行签名需要操作的步骤如下:

1)请求对象配置是否需要签名

    JKRequest *request = [[JKRequest alloc] init];
	request.useSignature = YES;
   // 子类可以封装在内部初始化中

2)实现JKRequestHelperProtocol中的方法,具体如下:

- (void)signatureRequest:(__kindof JKRequest *)request;
// 在内部实现中,根据request的类根据不同的签名规则进行签名

备注:如果app中只有一个请求的签名规则和项目中的不太一样,那么没有必要创建子类,可以将签名后的url,赋值给request的customRequestUrl属性。

实现接口缓存

实现接口缓存需要实现以下操作步骤:

1)如果是客户端开发人员需要指定哪些网络请求需要缓存,需要手动指定如下:

 JKRequest *request = [[JKRequest alloc] init];
 request.ignoreCache = NO;// 这个属性默认是NO,也可以不用指定
 request.cacheTimeInSeconds = 30;//cacheTimeInSeconds大于0的时候才会对返回内容进行缓存
   

2)如果API有下发指定哪些接口需要缓存,API下发的需要缓存的接口可能与客户端开发者指定的有冲突,重叠。具体需要根据业务讨论一个优先级规则。需要实现JKRequestHelperProtocol中如下方法:

- (void)judgeToChangeCachePolicy:(__kindof JKRequest *)request;
//内部根据条件判断是否需要改变相应网络请求的缓存配置

3)具体实现缓存的操作,实现JKRequestHelperProtocol协议方法如下:

/// load Cache data of the request
/// @param request request
- (id)loadCacheDataOfRequest:(__kindof JKRequest *)request error:(NSError **)error

/// save the request's reponse to cache
/// @param request request
- (void)saveResponseToCacheOfRequest:(__kindof JKRequest *)request

/// clear the the request's response from cache
/// @param request request
- (void)clearResponseFromCacheOfRequest:(__kindof JKRequest *)request

动态更换域名

实现不动态更换域名,需要实现JKRequestHelperProtocol中的如下方法:

/// get the baseUrl of the request
/// @param request request
- (NSString *)baseUrlOfRequest:(__kindof JKRequest *)request

在请求URL配置公共参数

需要实现JKRequestHelperProtocol中的如下方法:

/// this is the url append or filter func
/// @param originUrl originUrl
/// @param request request
- (NSString *)filterUrl:(NSString *)originUrl withRequest:(__kindof JKRequest *)request;

将网络请求返回数据解析放在子线程执行

网络请求成功后,数据转换成模型是一个耗时操作,将该操作放在子线程执行可以减少主线程的拥堵,具体操作如下:

/// start the request
/// @param parseBlock the block used to parse response, exec not in mainThread
/// @param successBlock successBlock
/// @param failureBlock failureBlock
- (void)startWithCompletionParse:(nullable id(^)(__kindof JKRequest *request, NSRecursiveLock *lock))parseBlock
                         success:(nullable void(^)(__kindof JKRequest *request))successBlock
                         failure:(nullable void(^)(__kindof JKRequest *request))failureBlock;

备注:JKRequest或者其子类的对象调用该方法,并在parseBlock中将数据解析然后返回,这个返回值会赋给request的parsedData,开发者可以接着在successBlock中使用这个数据刷新UI(successBlock已经返回到主线程),如果用到了block中的变量,需要使用block中传递过来的lock进行加锁和解锁。另一个需要注意的点是这个parseBlock是在并发子线程执行,不能调用任何与UI相关的API。

网络请求根据业务决定执行成功逻辑或者失败逻辑

有时候网络请求成功了,但是返回的数据相关的code代表业务失败,需要执行业务失败的逻辑,为了避免在网络成功的回调中执行失败的逻辑,因此需要实现JKRequestHelperProtocol中的如下方法:

/// validate the request is business success or not,only if the request is network successed will be called
/// @param request request
/// @param error error
- (BOOL)validateBusinessSuccess:(__kindof JKRequest *)request error:(NSError * _Nullable __autoreleasing *)error;

技术交流,QQ扫描下方二维码

交流

许可协议

JKNetworking遵循MIT许可协议。更多详情见LICENSE文件。