2003
01 02 03 04 05 06 07 08 09 10 11 12
2006
01 02 03 04 05 06 07 08 09 10 11 12
2007
01 02 03 04 05 06 07 08 09 10 11 12
2008
01 02 03 04 05 06 07 08 09 10 11 12
2009
01 02 03 04 05 06 07 08 09 10 11 12
2010
01 02 03 04 05 06 07 08 09 10 11 12
2011
01 02 03 04 05 06 07 08 09 10 11 12
2017
01 02 03 04 05 06 07 08 09 10 11 12
2018
01 02 03 04 05 06 07 08 09 10 11 12
 
Jun
25
2007

The bug of WebResourceLoadDelegate and how to fix it

之前因為幫一個無聊的點滑鼠比賽寫 Mac 連點程式,摸了一下 WebKit。話說這 WebKit 還真好用,一個晚上就讓我寫出一個簡單的連點程式。但也讓我發現了這 WebKit 的一些問題,紀錄於此。

想用 WebKit 抓 WebView 上的某張圖片,除了用 javascript 去算他的座標,再從 View 中剪裁下來,或者是利用 DOM 來取得圖片 URL 以外,還有一個方法:WebResourceLoadDelegate。

To get image in WebView, you can calculate the element’s dimension using javascript and then “crop” the region of the view, or grab the URL of image using DOM related API. However, there’s another way: WebResourceLoadDelegate.事實上有些時候真的非用 WebResourceLoadDelegate 不可。從 View 中剪裁下來若是遇到動態 GIF 那只能抓到一個 frame;而有些圖片是動態生成的,光取得 URL 也抓不到同樣的。

Actually, you have to use WebResourceLoadDelegate in some situations: if you’re dealing with animated GIF, cropping it off the View only get you one frame of the GIF. Furthermore, some images were generated dynamically. Get the URL doesn’t mean that you can get the same image in WebView.

這時就得利用 WebResourceLoadDelegate 了。但奇怪的是,- (void) webView: (WebView *)sender resource:(id)identifier didFinishLoadingFromDataSource:(WebDataSource *)dataSource 裡面的 dataSource 所挾帶的 request 並不見得是這個正在 loading 的這個 resouce 的 request!想要知道這個目前正在 loading 的 resource 的 URL,必須這樣寫:

Fortunately, Apple provides API called WebResourceLoadDelegate that solve the problem. BUT if you read the document carefully and do some experiment with WebResourceLoadDelegate, you’ll find some annoying bugs.

- (id)webView:(WebView *)sender identifierForInitialRequest:(NSURLRequest *)request fromDataSource:(WebDataSource *)dataSource { return [request URL]; } - (void) webView: (WebView *)sender resource:(id)identifier didFinishLoadingFromDataSource:(WebDataSource *)dataSource { NSString *url = [identifier absoluteString]; if ([url hasPrefix: @"http://www.example.org/image?"]) { WebResource *image = [dataSource subresourceForURL: url]; // Ooops! The key url isn't exist. Failed to retreive the data. NSData *d = [image data]; } }

上面的程式碼,你會發覺到了 WebResource *image = [dataSource subresourceForURL: url]; 這一步,居然會沒有這個 URL 的 subresource!搞什麼,這個 Delegate 明明叫做 didFinishLoadingFromDataSource 啊。這就是我認為 WebKit 有問題的地方。 修正的方法是利用 [NSObject performSelector:withObject:afterDelay:] 延遲 0.1 秒以後,再做 [dataSource subresourceForURL: url]。沒有意外的話,應該就可以順利讀取到了。

 
 

Write Concisely