2013-04-27 113 views
5

UIWebView不會自動支持處理Passbook .pkpass文件。UIWebView委託獲取MIME類型

在此technical note中,Apple建議通過UIWebViewDelegate方法執行檢查以嗅出MIME類型並相應地處理它。

要使用一個UIWebView添加通行證,實施適當的 UIWebViewDelegate方法來識別當與 MIME類型的應用/ vnd.apple.pkpass

然而視圖負載的數據,我在能夠提供MIME類型的UIWebView Delegate Protocol Reference內找不到任何內容。

我可以直接使用NSURLConnection委託直接成功下載和處理文件,但是我希望實現的是如果用戶在UIWebView中瀏覽時單擊添加到存摺按鈕,就可以正確處理通行證。由於我不知道鏈接,許多提供商不會將其鏈接後綴爲.pkpass擴展名,所以遵循Apple關於檢查MIME類型的建議似乎是最好的選擇。

我曾嘗試加入以下

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)newRequest 
               navigationType:(UIWebViewNavigationType)navigationType 
{ 

    NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:[newRequest URL]]; 

    // Spoof iOS Safari headers for sites that sniff the User Agent 
    [req addValue:@"Mozilla/5.0 (iPhone; CPU iPhone OS 6_1 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10A5376e Safari/8536.25" forHTTPHeaderField:@"User-Agent"]; 

    NSURLConnection *conn = [NSURLConnection connectionWithRequest:newRequest delegate:self]; 

    return YES; 
} 

NSURLConnection代表:

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response 
{ 
    NSString *mime = [response MIMEType]; 

    if ([mime isEqualToString:@"application/vnd.apple.pkpass"] && ![_data length]) { 

     _data = nil; // clear any old data 
     _data = [[NSMutableData alloc] init]; 

     [_webPanel stopLoading]; 
    } 
} 

-(void)connection:(NSURLConnection*)connection didReceiveData:(NSData*)data 
{ 
    [_data appendData:data]; 
    NSLog(@"Size: %d", [_data length]); 
} 

-(void)connectionDidFinishLoading:(NSURLConnection*)connection 
{ 

    if ([_data length]) { 

     PKAddPassesViewController *pkvc = [PassKitAPI presentPKPassFileFromData:_data]; 
     pkvc.delegate = self; 
     [self presentViewController:pkvc 
          animated:YES 
         completion:nil]; 
    } 
} 

NSURLConnection代表正常工作時的連接直接調用,無需UIWebView。但是,當我嘗試從UIWebView委託中啓動NSURLConnection時,傳遞下載失敗,因爲只有80%左右的.pkpass正在下載(我在_data變量和Content-Length標頭中出現了隨機的字節不匹配)。

所以,我的問題:

  1. 是否有更簡單的方式來獲得一個MIME型的保持,直接從UIWebView委託方法?
  2. 如果不是,那麼我是否會以正確的方式開放並行NSURLConnection?或者有更好的方法嗎?
  3. 如果NSURLConnection是要走的路,那麼可能導致它停止下載完整文件?
+0

你找到了一個解決方案?如果是,你可以分享嗎? – 2013-09-29 14:09:11

+0

不 - 我在WWDC與Apple工程師討論過,他們告訴我沒有解決方案。我有一些針對文檔和UIWebView代表的開放bug報告。 – PassKit 2013-09-29 16:29:30

+0

你有沒有想過這一個?我將不得不進行此操作,並且希望不必再次手動打開服務器。 – MrTristan 2014-09-07 19:23:17

回答

0
- (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType { 

    NSURL *url = request.URL; 
    NSURLRequest *req = [NSURLRequest requestWithURL:url]; 
    NSURLConnection *conn = [NSURLConnection connectionWithRequest:req delegate:self]; 
    [conn start]; 
    return YES; 
} 

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{ 

    NSString *mime = [response MIMEType]; 
    NSLog(@"%@",mime); 

} 
+0

雖然這可行,但由於每次請求都下載了兩次,所以開銷很大。你的代碼也停在MIME類型 - 我的問題是,MIME類型application/vnd.apple.pkpass不直接被UIWebView支持,所以我需要有條件地(有效地)通過NSURLConnection下載這些文件,而不是不加區分地下載所有東西在平行下。 – PassKit 2013-09-08 01:40:01

+0

你能解釋以上兩點1)下載兩次,2)停止MIME類型。在我的代碼中,所有這些代表只打一次電話。 shouldStartLoadWithRequest,didReceiveResponse,webViewDidStartLoad,webViewDidFinishLoad。 – Zeeshan 2013-09-08 22:51:06

+0

當這些委託方法觸發時,UIWebView也在下載文件(但最終會拋棄它,因爲它不知道如何自然處理它)。使用NSURLConnection需要兩個獨立的請求到服務器的相同的資源(原始從UIWebView +第二種形式NSURLConnection)。 .pkpass文件需要CPU密集型生成,最多可以重達500kb。理想情況下,我應該能夠訪問原始UIWebView請求中的數據,但錯誤委託會丟棄此數據。 – PassKit 2013-09-09 02:23:47

0

你可以嘗試繼承NSURLProtocol和處理響應信息解析在那裏。

- (void)URLProtocol:(NSURLProtocol *)protocol didReceiveResponse:(NSURLResponse *)response cacheStoragePolicy:(NSURLCacheStoragePolicy)policy 

不要忘了還利用這些鉤子約子資源。

+1

你能提供一些更詳細的方法嗎?似乎唯一避免雙重加載資源的方法是獨佔地使用UIWebview或NSURLConnection,但要像後面那樣做很多工作。 – PassKit 2013-10-08 00:48:12

+0

在你的NSURLProtocol中,你會得到每一個子資源製作的請求。你也可以點擊每一個響應。您可以根據mainDocumentURL和請求的URL(有時)檢查您是否是子資源。響應信息有一個MIMEType屬性,您可以查看。 – cynistersix 2013-10-09 15:47:01

0

只需用js

let contentType = webView.stringByEvaluatingJavaScript(from: "document.contentType;")