iOS開發(fā)-UIWebView和WKWebView監(jiān)聽url的改變

一提到webView監(jiān)聽或者攔截url,許多人可能都會想到在以下下兩個方法中攔截

  • UIWebView
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType;
  • WKWebView
// 頁面開始加載
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation;
或者
// 在發(fā)送請求之前,決定是否跳轉(zhuǎn)
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler;

這兩種情況可以處理一般情況下的問題,但是特殊情況下,比如手機百度首頁是多個頁面同時開始加載,然后再次點擊跳轉(zhuǎn)的時候就不會再調(diào)用以上的方法,或者點擊網(wǎng)頁返回上一頁的時候也不會調(diào)用以上的方法,這個時候我們可以采用下面的方式

  • UIWebView
  1. 繼承NSURLCache類,并重寫- (NSCachedURLResponse *)cachedResponseForRequest:(NSURLRequest *)request方法
.h
@interface XLURLCache: NSURLCache

@end

.m
@implementation XLURLCache

- (NSCachedURLResponse *)cachedResponseForRequest:(NSURLRequest *)request {
   // 可以在此處進(jìn)行攔截并執(zhí)行相應(yīng)的操作
   NSLog(@"url-------%@",request.URL.absoluteString);
   if ([request.URL.absoluteString isEqualToString:@""]) {
        NSURLResponse *response = [[NSURLResponse alloc] initWithURL:request.URL MIMEType:@"text/plain" expectedContentLength:1 textEncodingName:nil];
        NSCachedURLResponse *cachedResponse = [[NSCachedURLResponse alloc] initWithResponse:response data:[NSData dataWithBytes:" " length:1]];
        [super storeCachedResponse:cachedResponse forRequest:request];
    }
   return [super cachedResponseForRequest:request];
}

@end
  1. 在AppDelegate中添加以下代碼
// 緩存路徑 可以是Documents或者tmp文件夾
NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject; // the path to the cache file
NSUInteger discCapacity = 10*1024*1024;
NSUInteger memoryCapacity = 512*1024;
XLURLCache *cache = [[XLURLCache alloc] initWithMemoryCapacity: memoryCapacity
                                        diskCapacity: discCapacity diskPath:path];
[NSURLCache setSharedURLCache:cache];
  1. 然后,webView在加載新頁面的時候就會走1中的方法了,不過有個缺點就是網(wǎng)頁中圖片鏈接之類的也會調(diào)用1中的方法,調(diào)用次數(shù)會比較多
  • WKWebView
    WKWebView的方法比較簡單,我們只需要用KVO監(jiān)聽URL屬性的變化就能達(dá)到目的如下
[webView addObserver:self forKeyPath:@"URL" options:NSKeyValueObservingOptionNew context:nil];
// KVO 接收到通知時的方法
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
    if ([keyPath isEqualToString:@"URL"]) {
        // 可以在這里進(jìn)行攔截并做相應(yīng)的處理
        NSLog(@"URL------%@",_webView.URL.absoluteString);
    }
}

這里我們會發(fā)現(xiàn),那為什么UIWebView我們不去用KVO的監(jiān)聽來實現(xiàn)呢?其實,我在寫文章的時候也嘗試了一下UIWebView的KVO但發(fā)現(xiàn)無論是監(jiān)聽request屬性還是request.URL亦或request.URL.absoluteString都沒有調(diào)用KVO的監(jiān)聽回調(diào).

通過查看源碼我們可以發(fā)現(xiàn)UIWebView的request屬性.NSURLRequest的URL屬性,NSURL的absoluteString 以及WKWebView的URL屬性都是被關(guān)鍵字readonly修飾的,而KVO的原理是什么呢?

對于每個被觀察的 property(屬性),重寫其 setter 方法 。
在重寫的 setter 方法中調(diào)用以下方法通知觀察者 :
-willChangeValueForKey:
-didChangeValueForKey:

readonly導(dǎo)致了該屬性沒有setter方法,也就無法被KVO監(jiān)聽.但是為什么WKWebView的URL屬性能被監(jiān)聽到呢? 個人推測可能是一下兩個方案的一種

// 1.自己寫一個方法幫助系統(tǒng)補齊原本應(yīng)該在setter中實現(xiàn)的兩個觀察者方法 如下
- (void)ownSetURL:(NSURL *)URL {
  [self willChangeValueForKey:@"URL"];
   _URL = URL;
  [self didChangeValueForKey:@"URL"];
}


// 2.
- (void)ownSetURL:(NSURL *)URL {
  [self setValue:URL forKey:@"URL"];
}

至此,問題解決

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容