參考文章:
iOS開發(fā)之--- NSURLProtocol
NSURLProtocol
NSURLProtocol 是一個抽象類巩检,它是一個抽象類悔详,你可以通過子類化來定義新的或已經(jīng)存在的URL加載行為竹宋。
利用這個類海蔽,可以用來實現(xiàn):
- 通過讓網(wǎng)頁來請求自定義的特定的url脚仔,來實現(xiàn)H5與原生應(yīng)用的交互
- 對發(fā)出請求的header進(jìn)行格式化
- 創(chuàng)建本地代理服務(wù)汁掠,用于數(shù)據(jù)變化時對URL請求進(jìn)行更改
...
如何使用
1炬太、注冊你的NSURLProtocol 子類
當(dāng)請求被加載時屏富,系統(tǒng)會向每一個注冊過的protocol詢問:“Hey你能控制這個請求嗎?”第一個通過 +canInitWithRequest: 回答為 YES 的protocol就會控制該請求养叛。URL protocol會被以注冊順序的反序訪問种呐,所以當(dāng)在-application:didFinishLoadingWithOptions:
方法中調(diào)用 [NSURLProtocol registerClass:[MyURLProtocol class]];
時,你自己寫的protocol比其他內(nèi)建的protocol擁有更高的優(yōu)先級弃甥。
2爽室、實現(xiàn)+canInitWithRequest:
方法
這個方法主要是說明你是否打算處理這個request,如果是返回yes淆攻,否則返回NO阔墩。
tips: 因為我們處理時的思路一般先攔截請求嘿架,然后對請求進(jìn)行一定的修改或處理,然后利用NSURLSesson或者NSURLConnection來真正的發(fā)送請求啸箫。這時就沒必要再對其進(jìn)行處理耸彪,不然會造成死循環(huán)。所以忘苛,要有一個標(biāo)示來標(biāo)示這個request是否已經(jīng)被我們處理過了蝉娜。一般使用的方法是在- (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召川、實現(xiàn) +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荧呐、實現(xiàn)開始、停止請求方法
- (void)startLoading
{
NSMutableURLRequest *mutableReqeust = [[self request] mutableCopy];
//標(biāo)示改request已經(jīng)處理過了纸镊,防止無限循環(huán)
[NSURLProtocol setProperty:@YES forKey:URLProtocolHandledKey inRequest:mutableReqeust];
self.connection = [NSURLConnection connectionWithRequest:mutableReqeust delegate:self];
}
//停止請求
- (void)stopLoading
{
[self.connection cancel];
}
5坛增、將請求的結(jié)果通過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 使用的介紹庵楷。