UIWebView委托获取MIME类型

问题描述:

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

- (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

你可以尝试继承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

只需用js

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