iOS H5容器的一些探究(二):iOS下的黑魔法NSURLProto
一、前言
NSURLProtocol是iOS中的一部分。如果開發者自定義的一個NSURLProtocol並且註冊到app中,那麼在這個自定義的NSURLProtocol中我們可以攔截UIWebView,基於系統的NSURLConnection或者NSURLSession進行封裝的網路請求,然後做到自定義的response返回。非常強大。
二、NSURLProtocol的使用流程
2.1、在AppDelegate中註冊自定義的NSURLProtocol。
比如我這邊自定義的NSURLProtocol叫做YXNSURLProtocol。
@interface YXNSURLProtocol : NSURLProtocol
@end
在系統載入的時候,把自定義的YXNSURLProtocol註冊到URL載入系統中,這樣 所有的URL請求都有機會進入我們自定義的YXNSURLProtocol進行攔截處理。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[NSURLProtocol registerClass:[YXNSURLProtocol class]];
}
載入完成後,當產生URL請求的同時,會依次進入NSURLProtocol的以下相關方法進行處理,下面我們依次來講一下每一個方法的作用。
2.2、NSURLProtocol中的幾個方法
2.2.1、是否進入自定義的NSURLProtocol載入器
+ (BOOL)canInitWithRequest:(NSURLRequest *)request{
BOOL intercept = YES;
NSLog(@"YXNSURLProtocol==%@",request.URL.absoluteString);
if (intercept) {
}
return intercept;
}
如果返回YES則進入該自定義載入器進行處理,如果返回NO則不進入該自定義選擇器,使用系統預設行為進行處理。
如果這一步驟返回YES。則會進入2.3的方法中。
2.2.2、重新設定NSURLRequest的資訊
+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request {
return request;
}
在這個方法中,我們可以重新設定或者修改request的資訊。比如請求重定向或者新增頭部資訊等等。如果沒有特殊需求,直接返回request就可以了。但是因為這個方法在會在一次請求中被呼叫多次(暫時我也不知道什麼原因為什麼需要回撥多洗),所以request重定向和新增頭部資訊也可以在開始載入中startLoading方法中重新設定。
2.2.3、這個方法主要是用來判斷兩個request是否相同,如果相同的話可以使用快取資料,通常呼叫父類的實現即可
+ (BOOL)requestIsCacheEquivalent:(NSURLRequest *)a toRequest:(NSURLRequest *)b{
return [super requestIsCacheEquivalent:a toRequest:b];
}
這個方法基本不常用。
2.2.4、被攔截的請求開始執行的地方
(void)startLoading{
}
這個函式使我們重點使用的函式。
2.2.5、結束載入URL請求
(void)stopLoading{
}
2.3、NSURLProtocolClient中的幾個方法
上面的NSURLProtocol定義了一系列載入的流程。而在每一個流程中,我們作為使用者該如何使用URL載入系統,則是NSURLProtocolClient中幾個方法該做的事情。
@protocol NSURLProtocolClient <NSObject>
//請求重定向
- (void)URLProtocol:(NSURLProtocol *)protocol wasRedirectedToRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse;
// 響應快取是否合法
- (void)URLProtocol:(NSURLProtocol *)protocol cachedResponseIsValid:(NSCachedURLResponse *)cachedResponse;
//剛接收到Response資訊
- (void)URLProtocol:(NSURLProtocol *)protocol didReceiveResponse:(NSURLResponse *)response cacheStoragePolicy:(NSURLCacheStoragePolicy)policy;
//資料載入成功
- (void)URLProtocol:(NSURLProtocol *)protocol didLoadData:(NSData *)data;
//資料完成載入
- (void)URLProtocolDidFinishLoading:(NSURLProtocol *)protocol;
//資料載入失敗
- (void)URLProtocol:(NSURLProtocol *)protocol didFailWithError:(NSError *)error;
//為指定的請求啟動驗證
- (void)URLProtocol:(NSURLProtocol *)protocol didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge;
//為指定的請求取消驗證
- (void)URLProtocol:(NSURLProtocol *)protocol didCancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge;
@end
三、實現一個地址重定向的Demo
這個Demo實現的功能是在UIWebView中所有跳轉到sina首頁的請求,都重定位到sohu首頁。
3.1、第一步,新建一個UIWebView,載入sina首頁
_webView = [[UIWebView alloc] initWithFrame:self.view.bounds];
_webView.delegate = self;
[self.view addSubview:_webView];
NSURL *url = [[NSURL alloc] initWithString:@""];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[_webView loadRequest:request];
3.2、自定義一個NSURLProtocol
@interface YXNSURLProtocolTwo : NSURLProtocol
@end
3.3、在AppDelegate中,進行註冊
(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[NSURLProtocol registerClass:[YXNSURLProtocolTwo class]];
return YES;
}
3.4、在canInitWithRequest方法中攔截/
+ (BOOL)canInitWithRequest:(NSURLRequest *)request{
NSLog(@"canInitWithRequest url-->%@",request.URL.absoluteString);
//看看是否已經處理過了,防止無限迴圈
if ([NSURLProtocol propertyForKey:URLProtocolHandledKey inRequest:request]) {
return NO;
}
NSString *urlString = request.URL.absoluteString;
if([urlString isEqualToString:@"/"]){
return YES;
}
return NO;
}
3.5、在startLoading中進行方法重定向
(void)startLoading{
NSMutableURLRequest * request = [self.request mutableCopy];
// 標記當前傳入的Request已經被攔截處理過,
//防止在最開始又繼續攔截處理
[NSURLProtocol setProperty:@(YES) forKey:URLProtocolHandledKey inRequest:request];
self.connection = [NSURLConnection connectionWithRequest:[self changeSinaToSohu:request] delegate:self];
}
//把所用url中包括sina的url重定向到sohu
- (NSMutableURLRequest *)changeSinaToSohu:(NSMutableURLRequest *)request{
NSString *urlString = request.URL.absoluteString;
if ([urlString isEqualToString:@"/"]) {
urlString = @"";
request.URL = [NSURL URLWithString:urlString];
}
return request;
}
你也可以選擇在+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request
替換request。效果都是一樣的。
3.6、因為新建了一個NSURLConnection *connection,所以要實現他的代理方法,如下
(void) connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
[self.client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
}
- (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];
}
透過以上幾步,我們就可以實現最簡單的url重定向,WebView載入新浪首頁,卻跳轉到了搜狐首頁。
四、小結
透過自定義的NSURLProtocol,我們拿到使用者請求的request之後,我們可以做很多事情。比如:
1、自定義請求和響應
2、網路的快取處理(H5離線包 和 網路圖片快取)
3、重定向網路請求
4、為測試提供資料Mocking功能,在沒有網路的情況下使用本地資料返回。
5、過濾掉一些非法請求
6、快速進行測試環境的切換
7、攔截圖片載入請求,轉為從本地檔案載入
8、可以攔截UIWebView,基於系統的NSURLConnection或者NSURLSession進行封裝的網路請求。目前WKWebView無法被NSURLProtocol攔截。
9、當有多個自定義NSURLProtocol註冊到系統中的話,會按照他們註冊的反向順序依次呼叫URL載入流程。當其中有一個NSURLProtocol攔截到請求的話,後續的NSURLProtocol就無法攔截到該請求。
五、聯絡方式
如果覺得對你還有些用,就關注小編+喜歡這一篇文章。你的支援是我繼續的動力。
下篇文章預告:iOS 面向切面程式設計的實現與實戰案例
文章來源於網路,如有侵權,請聯絡小編刪除。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/3705/viewspace-2818660/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- iOS H5容器的一些探究(二):iOS下的黑魔法NSURLProtocoliOSH5Protocol
- iOS H5容器的一些探究(一):UIWebView和WKWebView的比較和選擇iOSH5UIWebView
- iOS - Tips - 黑魔法iOS
- iOS的一些常用程式碼(二)iOS
- iOS Block探究iOSBloC
- iOS RunLoop 探究iOSOOP
- 關於IOS物件的小事的探究iOS物件
- iOS - 對 block 實現的探究iOSBloC
- iOS 深入探究 AutoreleasePooliOS
- iOS - Block探究系列一iOSBloC
- [IOS]H5效能iOSH5
- iOS之Wifi開發探究iOSWiFi
- iOS底層原理探究-RunloopiOSOOP
- iOS開發必會的座標系探究iOS
- iOS倒數計時的探究與選擇iOS
- iOS開發者的一些前端感悟iOS前端
- iOS-UITableViewCell的一些事iOSUIView
- iOS 定時器耗電探究iOS定時器
- 探究 iOS 記憶體問題iOS記憶體
- iOS-效能優化深入探究iOS優化
- iOS底層原理探究-RuntimeiOS
- 在杭州的iOS面試(二)iOS面試
- iOS與H5互動iOSH5
- 玩轉iOS開發:iOS中的GCD開發(二)iOSGC
- axios的一些常見用法iOS
- iOS自己使用的一些小方法iOS
- iOS一些自己常用的工具方法iOS
- iOS block的一些自我見解iOSBloC
- IOS input auto focus 解決方案探究iOS
- iOS底層原理 - Block本質探究iOSBloC
- iOS下的UDP廣播iOSUDP
- iOS 開發中的『庫』(二)iOS
- h5 ios 樣式錯亂H5iOS
- iOS開發-使用Safari除錯iOS APP H5頁面iOS除錯APPH5
- 檢測iOS的APP效能的一些方法iOSAPP
- 玩轉iOS開發:iOS中的NSOperation開發(二)iOS
- Flutter系列一:探究Flutter App在iOS宿主App中的整合FlutterAPPiOS
- 自學 iOS 開發的一些經驗iOS