http://www.cocoachina.com/ios/20150626/12161.htmljavascript
本文譯者:candeladiao,原文:URL filtering for UIWebView on the iPhone
說明:譯者在作app開發時,由於頁面的javascript文件比較大致使加載速度很慢,因此想把javascript文件打包在app裏,當UIWebView須要加載該腳本時就從app本地讀取,但UIWebView並不支持加載本地資源。最後從下文中找到了解決方法,第一次翻譯,不免有誤,你們多多指教。css
iCab Mobile(一款iOS平臺的網頁瀏覽器)要實現一個攔截管理器來過濾頁面上的廣告及其餘東西。它有一個簡單的基於URL過濾規則的列表(一般由用戶維護),當頁面包含的資源(圖片、js以及css等),文件的URL存在於規則列表中時,資源就不會被加載。html
但看一下UIWebView類的API,會發現咱們沒有辦法知道UIWebView正在加載什麼資源,更糟的是,當你但願過濾掉某些資源文件的時候,沒有方法能夠強制UIWebView不去加載這些文件,java
攔截器看起來貌似沒有可能實現。ios
固然仍是有解決方案的,不然這篇文件就沒什麼卵用。git
正如上面所說,實現攔截器不能靠UIWebView,由於UIWebView沒有提供任何有用的API。github
對UIWebView的全部請求,要找到一個能中斷全部HTTP 請求的切入點,咱們須要先了解一下Cocoa的URL Loading System,由於UIWebView是使用URL Loading System從web端取數據的。咱們須要的切入點NSURLCache類就是URL Loading System的一部分。雖然目前iOS系統不會在磁盤上緩存任何數據(後面的iOS系統版本或許會有不一樣),所以在UIWebView開始加載前,NSURLCache管理的緩存數據一般爲空,但UIWebView仍然會檢測所請求資源文件是否存在於緩存。因此咱們須要作的只是繼承NSURLCache並重載其方法:web
1
|
- (NSCachedURLResponse*)cachedResponseForRequest:(NSURLRequest*)request
|
UIWebView請求全部資源時都會調用這個方法。由於咱們只須要在這個方法裏判斷請求的URL是不是咱們想攔截的。若是是則建立一個沒有內容的假response,不然只需調用super方法便可。瀏覽器
以下是實現細節:緩存
1.繼承NSURLCache:
FilteredWebCache.h:
1
2
3
4
|
@interface FilteredWebCache : NSURLCache
{
}
@end
|
子類的主要代碼
FilteredWebCache.m:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
#import "FilteredWebCache.h"
#import "FilterManager.h"
@implementation FilteredWebCache
- (NSCachedURLResponse*)cachedResponseForRequest:(NSURLRequest*)request
{
NSURL *url = [request URL];
BOOL blockURL = [[FilterMgr sharedFilterMgr] shouldBlockURL:url];
if
(blockURL) {
NSURLResponse *response =
[[NSURLResponse alloc] initWithURL:url
MIMEType:@
"text/plain"
expectedContentLength:1
textEncodingName:nil];
NSCachedURLResponse *cachedResponse =
[[NSCachedURLResponse alloc] initWithResponse:response
data:[NSData dataWithBytes:
" "
length:1]];
[
super
storeCachedResponse:cachedResponse forRequest:request];
[cachedResponse release];
[response release];
}
return
[
super
cachedResponseForRequest:request];
}
@end
|
首先判斷URL是否需攔截(判斷經過FilterManager類實現,類實如今此不列出)。若是須要,建立一個無內容的響應對象並把它存在cache中。有人可能會認爲只須要返回假的響應對象就夠了,不必緩存它。但這樣會因響應對象被系統釋放而致使app crash。不知道爲什麼爲會這樣,多是iOS的bug(Mac OS X 10.5.x也存在一樣問題,而10.4.x及更早的系統上沒有問題),也多是URL Loading System內部類之間的依賴所致。因此咱們先緩存響應對象。確保全部響應都是真實存在於緩存中,這也iOS但願的,最重要的是不會crash.
更新:由於假的響應是以大於0的大小來初始化的,看起來結緩存它也是必要的。
2.建立新的緩存:
接下來須要建立一個新的緩存並告訴iOS系統使用新的緩存代替默認的,這樣當URL Loading System檢測資源緩存時纔會調用上面的代碼。這要在任意UIWebView開始加載頁面前作,顯然應該放在app啓動的時候:
1
2
3
4
5
6
7
8
|
NSString *path = ...
// the path to the cache file
NSUInteger discCapacity = 10*1024*1024;
NSUInteger memoryCapacity = 512*1024;
FilteredWebCache *cache =
[[FilteredWebCache alloc] initWithMemoryCapacity: memoryCapacity
diskCapacity: discCapacity diskPath:path];
[NSURLCache setSharedURLCache:cache];
[cache release];
|
這裏須要提供一個緩存存儲路徑。緩存文件由NSURLCache對象自動生成,咱們無需事先建立文件,但要定義緩存文件所存位置(必須是應用程序「沙盒」內,如「tmp」目錄或是「Document」目錄)
這就是實現UIWebView基於URL進行請求過濾的全部內容,看起來其實並不複雜
注:若是過濾規則在app運行過程當中會改變,你須要從緩存中刪除假的響應。NSURLCache提供了刪除方法,因此這不是問題。若是過濾規則不會改變,則無需關心