需求前提:
最近公司有這樣一個需求,要用webView加載網(wǎng)頁游戲劣针,由于蘋果方面不支持webView通過url從服務(wù)器端加載游戲括眠,于是html,js等資源文件就放到了本地項目里面,通過webView加載html來實現(xiàn)交互痕鳍。
但是html/js文件里有指向http/https的請求停团,這樣webView就加載不出來本地資源了医男,因此我們需要攔截http網(wǎng)絡(luò)請求随闪,把這些url攔截到滑绒,然后構(gòu)建成我們可以響應(yīng)的方式闷堡。
攔截準(zhǔn)備:
假設(shè)我們本地服務(wù)器的端口為1000,服務(wù)器名為:localhost疑故,協(xié)議是http
那么需要攔截的URL為:http://localhost:1000
實現(xiàn)思路:
攔截URL有如下兩種方式:
- 猜想1:webView自己的代理方法攔截URL
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType;
嘗試攔截 https://www.baidu.com杠览, 此代理方法確實攔截到了這個url,但是攔截不到內(nèi)部圖片等具體資源的url纵势,因此猜想1失效踱阿。
- 猜想2:NSURLProtocol攔截 ~ 可以攔截的網(wǎng)絡(luò)請求包括NSURLSession管钳,NSURLConnection以及UIWebVIew,(WKWebView需要特定的方式實現(xiàn)才能做到url被攔截软舌,后續(xù)補充)
嘗試攔截 https://www.baidu.com才漆, 此代理方法攔截到了所有資源的url,因此猜想2可行葫隙。
實現(xiàn)流程:
一、在想要攔截的地方先注冊:
[NSURLProtocol registerClass:[CustomURLProtocol class]];
不想攔截則取消注冊:
[NSURLProtocol unregisterClass:[CustomURLProtocol class]];
二躏仇、攔截網(wǎng)絡(luò)請求恋脚,NSURLProtocol會依次執(zhí)行下列方法:
1.該方法會拿到request的對象,我們可以通過該方法的返回值來篩選request是否需要被NSURLProtocol做攔截處理焰手。
+ (BOOL)canInitWithRequest:(NSURLRequest *)request
{
NSString *monitorStr = request.URL.absoluteString;
// NSLog(@"monitorStr=%@",monitorStr);
// 只處理 http://localhost:1000/... 的請求
if ( ([request.URL.absoluteString hasPrefix:@"http://localhost:1000”]))
{
//看看是否已經(jīng)處理過了糟描,防止無限循環(huán)
if ([NSURLProtocol propertyForKey:URLProtocolHandledKey inRequest:request]) {
return NO;
}
return YES;
}
return NO;
}
2.在該方法中,我們可以對request進行處理书妻。例如修改請求頭部信息等船响。最后返回一個處理后的request實例。例如我們攔截到 https://www.baidu.com躲履, 而通過修改request见间,將url指向http://www.reibang.com。 類似于webView代理方法攔截工猜,將其指向一個新的url米诉。如果不修改,則返回request本身篷帅。
+ (NSURLRequest *) canonicalRequestForRequest:(NSURLRequest *)request {
// NSMutableURLRequest *mutableReqeust = [request mutableCopy];
// mutableReqeust = [self redirectHostInRequset:mutableReqeust];
return request;
}
3.在該方法中史侣,把(處理過的或者不需處理的)request重新發(fā)送出去。我們要做的就是修改響應(yīng)體response魏身,騙過服務(wù)器惊橱,按我們拼接響應(yīng)的方式去響應(yīng)。以下為拼接響應(yīng)體代碼箭昵。
- (void)startLoading
{
//1.獲取資源文件路徑 ajkyq/index.html
NSURL *url = [self request].URL;
NSString *resourcePath = url.path;
resourcePath = [resourcePath substringFromIndex:1];//把第一個/去掉
//2.讀取資源文件內(nèi)容
NSString *path = [[NSBundle mainBundle] pathForResource:resourcePath ofType:nil];
NSFileHandle *file = [NSFileHandle fileHandleForReadingAtPath:path];
NSData *data = [file readDataToEndOfFile];
[file closeFile];
//3.拼接響應(yīng)Response
NSInteger dataLength = data.length;
NSString *mimeType = [self getMIMETypeWithCAPIAtFilePath:path];
NSString *httpVersion = @"HTTP/1.1";
NSHTTPURLResponse *response = nil;
if (dataLength > 0) {
response = [self jointResponseWithData:data dataLength:dataLength mimeType:mimeType requestUrl:url statusCode:200 httpVersion:httpVersion];
} else {
response = [self jointResponseWithData:[@"404" dataUsingEncoding:NSUTF8StringEncoding] dataLength:3 mimeType:mimeType requestUrl:url statusCode:404 httpVersion:httpVersion];
}
//4.響應(yīng)
[[self client] URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
[[self client] URLProtocol:self didLoadData:data];
[[self client] URLProtocolDidFinishLoading:self];
}
#pragma mark - 拼接響應(yīng)Response
-(NSHTTPURLResponse *)jointResponseWithData:(NSData *)data dataLength:(NSInteger)dataLength mimeType:(NSString *)mimeType requestUrl:(NSURL *)requestUrl statusCode:(NSInteger)statusCode httpVersion:(NSString *)httpVersion
{
NSDictionary *dict = @{@"Content-type":mimeType,
@"Content-length":[NSString stringWithFormat:@"%ld",dataLength]};
NSHTTPURLResponse *response = [[NSHTTPURLResponse alloc] initWithURL:requestUrl statusCode:statusCode HTTPVersion:httpVersion headerFields:dict];
return response;
}
備注:以上為NSURLProtocol實現(xiàn)攔截URL的流程税朴,目前只適用于UIWebView,至于WKWebView攔截URL的實現(xiàn)方式后續(xù)會補充(蘋果做了一些操作家制,導(dǎo)致用不能用以上方式攔截WKWebView的URL)掉房。我列舉了幾篇文章,思路是相通的慰丛。我會盡快把我寫的demo上傳到github卓囚,和大家分享。
1.http://www.reibang.com/p/02781c0bbca9 NSURLProtocol全攻略
2.https://github.com/liujinlongxa/NSURLProtocolDemo/blob/master/NSURLProtocolDemo/MySessionURLProtocol.m NSURLProtocolDemo
3.https://github.com/rnapier/RNCachingURLProtocol/blob/master/RNCachingURLProtocol.m 基于緩存的NSURLProtocol
4.https://github.com/yeatse/NSURLProtocol-WebKitSupport 基于WKWebKit的NSURLProtocol攔截
5.http://www.cnblogs.com/goodboy-heyang/p/5193741.html iOS開發(fā)之網(wǎng)絡(luò)編程--獲取文件的MIMEType