iOS

【iOS开发】NSURLProtocol的使用

2016-12-28  本文已影响333人  xiacheng

参考文章:
iOS开发之--- NSURLProtocol
NSURLProtocol

NSURLProtocol 是一个抽象类,它是一个抽象类,你可以通过子类化来定义新的或已经存在的URL加载行为。
利用这个类,可以用来实现:

  1. 通过让网页来请求自定义的特定的url,来实现H5与原生应用的交互
  2. 对发出请求的header进行格式化
  3. 创建本地代理服务,用于数据变化时对URL请求进行更改
    ...

如何使用
1、注册你的NSURLProtocol 子类
当请求被加载时,系统会向每一个注册过的protocol询问:“Hey你能控制这个请求吗?”第一个通过 +canInitWithRequest: 回答为 YES 的protocol就会控制该请求。URL protocol会被以注册顺序的反序访问,所以当在-application:didFinishLoadingWithOptions:方法中调用 [NSURLProtocol registerClass:[MyURLProtocol class]];时,你自己写的protocol比其他内建的protocol拥有更高的优先级。

2、实现+canInitWithRequest: 方法
这个方法主要是说明你是否打算处理这个request,如果是返回yes,否则返回NO。
tips: 因为我们处理时的思路一般先拦截请求,然后对请求进行一定的修改或处理,然后利用NSURLSesson或者NSURLConnection来真正的发送请求。这时就没必要再对其进行处理,不然会造成死循环。所以,要有一个标示来标示这个request是否已经被我们处理过了。一般使用的方法是在- (void)startLoading方法里用
[NSURLProtocol setProperty:@YES forKey:URLProtocolHandledKey inRequest:mutableReqeust];方法来为这个request加一个property,在+canInitWithRequest:`方法里判断有没有这个property。
如下:

+ (BOOL)canInitWithRequest:(NSURLRequest *)request
{
    //只处理host里面包含@“baidu”的请求
    NSString *urlStr = [request URL].host;
    if ([urlStr containsString:@"www.google.com"]) {
        if ([NSURLProtocol propertyForKey:URLProtocolHandledKey inRequest:request]) {
            return NO;
        }
        return YES;
    }
    return NO;
}

3、实现 +canonicalRequestForRequest
这个方法返回一个请求,即是我们修改过的请求。

+ (NSURLRequest *) canonicalRequestForRequest:(NSURLRequest *)request {
    NSMutableURLRequest *mutableReqeust = [request mutableCopy];
    mutableReqeust = [self redirectHostInRequset:mutableReqeust];
    return mutableReqeust;
}
+(NSMutableURLRequest*)redirectHostInRequset:(NSMutableURLRequest*)request
{
    if ([request.URL host].length == 0) {
        return request;
    }
    
    NSString *originUrlString = [request.URL absoluteString];
    NSString *originHostString = [request.URL host];
    NSRange hostRange = [originUrlString rangeOfString:originHostString];
    if (hostRange.location == NSNotFound) {
        return request;
    }
    //定向到百度搜索
    NSString *ip = @"www.baidu.com";
    NSString *urlString = [originUrlString stringByReplacingCharactersInRange:hostRange withString:ip];
    NSURL *url = [NSURL URLWithString:urlString];
    request.URL = url;
    return request;
}

4、实现开始、停止请求方法

- (void)startLoading
{
    NSMutableURLRequest *mutableReqeust = [[self request] mutableCopy];
    //标示改request已经处理过了,防止无限循环
    [NSURLProtocol setProperty:@YES forKey:URLProtocolHandledKey inRequest:mutableReqeust];
    self.connection = [NSURLConnection connectionWithRequest:mutableReqeust delegate:self];
}
//停止请求
- (void)stopLoading
{
    [self.connection cancel];
}

5、将请求的结果通过client返回给URL Loading System
因为这里我作的是NSURLConnect来做的请求,所以在NSURLConnectDataDelegate 方法里面来做这件事,如果你是你的NSURLSession,方法类似。

- (nullable NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)request redirectResponse:(nullable NSURLResponse *)response
{
    return request;
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
    [self.client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageAllowed];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
    [self.client URLProtocol:self didLoadData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    [self.client URLProtocolDidFinishLoading:self];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
    [self.client URLProtocol:self didFailWithError:error];
}

一个简单的Demo
上面即是NSURLProtocol 使用的介绍。
ps:在研究这个问题的时候,看到好多地方提到URL Loading System,现在网络请求只是会用,具体的实现还不是很懂,后面要找时间研究一下。

上一篇下一篇

猜你喜欢

热点阅读