4

I have a programatically crated UIWebView, and it is used to browse a iPhone-style site stored on my server. In this website, there are a few links to files users can download into my application. Right now, I'm trying to detect this with:

- (BOOL) webView:(UIWebView *) webView shouldStartLoadWithRequest:(NSURLRequest *) request navigationType:(UIWebViewNavigationType) navigationType
{
    url = [request URL];
    NSString *mimeType = [request valueForHTTPHeaderField:@"Content-Type"];
    NSLog(@"Content-type: %@", mimeType);
    if(mimeType == @"application/zip" || mimeType == @"application/x-zip" || mimeType == @"application/octet-stream")
    {
        NSLog(@"Downloading file!");
        [NSThread detachNewThreadSelector:@selector(download:) toTarget:self withObject:@"/tmp/file.ipa"];
        return NO;
    }
    return YES;
}

However, when this method is called, the content-type header is almost always (null), so I never am able to download a file.

How would you do this correctly?

Jack
  • 13,571
  • 6
  • 76
  • 98
Grant Paul
  • 5,852
  • 2
  • 33
  • 36

3 Answers3

3

You're trying to detect a Content-Type from an NSURLRequest which has not yet been made. You won't know the Content-Type until after the request is made using NSURLConnection. In this case, I'd probably just look at the file extension of the URL path.

Ben Gottlieb
  • 85,404
  • 22
  • 176
  • 172
  • 1
    The issue with that is the URLs are stored in a system that does not have filenames, it shows up more as http://example.com/some/stuff/32f3121a234ae32423 – Grant Paul Oct 12 '09 at 15:54
  • I believe if you use an httpMethod of "HEAD", then you'll just get headers. However, this will require a content call after the initial tap. – Ben Gottlieb Oct 12 '09 at 16:52
2

----------Swift 4+-------

Example for audio/mp3 detect -

Step 1: Use delegate

class ViewController : WKUIDelegate,WKNavigationDelegate {

Step 2: Setting WebKit

 func setWebView() {
        let webConfiguration = WKWebViewConfiguration()
        webView = WKWebView(frame: .zero, configuration: webConfiguration)
        webView.uiDelegate = self
        webView.navigationDelegate = self
        view = webView

        let myURL = URL(string: "https://www.bossmobi.guru/files/download/type/320/id/197255")//your audio url
        let myRequest = URLRequest(url: myURL!)
        webView.load(myRequest)
    }

Step 3: Get audio MIME type from webkit delegate.

 func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse, decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) {
        print( #function + "url is \(String(describing: webView.url))"  + "Mimetype" + "\(navigationResponse.response.mimeType ?? "NotAvailable")")
        if let _ = navigationResponse.response.mimeType?.range(of: "audio/mpeg") {
            print("MP3 is audio url \(String(describing: webView.url))")
            webView.stopLoading()
        }
        decisionHandler(.allow)
    }

---------ObjC----------

WKWebView setup

  NSString *urlString = @"https://www.bossmobi.guru/files/download/type/320/id/197255";

    WKWebViewConfiguration *theConfiguration = [[WKWebViewConfiguration alloc] init];
    WKWebView *_demoWKWebView = [[WKWebView alloc] initWithFrame:self.view.frame configuration:theConfiguration];
    _demoWKWebView.navigationDelegate = self;
    _demoWKWebView.UIDelegate = self;
    NSURL *nsurl=[NSURL URLWithString:urlString];
    NSURLRequest *nsrequest=[NSURLRequest requestWithURL:nsurl];
    [_demoWKWebView loadRequest:nsrequest];
    [self.view addSubview:_demoWKWebView];

WKWebView delegate

-(void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler {
    //NSLog(@"decidePolicyForNavigation---Response  %@",webView.URL);
    if ([navigationResponse.response.MIMEType isEqualToString:@"audio/mpeg"]) {
        NSLog(@"MP3  audio url is %@",webView.URL);
    }
    decisionHandler(WKNavigationResponsePolicyAllow);
}
Jack
  • 13,571
  • 6
  • 76
  • 98
0

So here's the problem: UIWebView doesn't download anything it can't display, and it doesn't know how to display a ZIP file. It will always fail before the Content-Type is filled in.

So, what to do? I don't know if your server-side app runs on more than the iPhone, but you could register a custom URL scheme with links like myapplication://example.com/stuff/yourhexurlgoeshere. You can create a custom URL handler for the myapplication scheme. A couple of seconds of Googling produced this site, which explains how to do it.

This has an additional benefit because if you, say, emailed such a link to another user, they could tap on it in Mail and have it open in your application.

Alex
  • 26,829
  • 3
  • 55
  • 74
  • Is there a method to just get the returned headers, via something like a NSURLConnection? Then I could manually scan for the zip file myself, but I would prefer if I did not have to download the entire page twice, just to check the headers. – Grant Paul Oct 12 '09 at 16:44
  • Not really, `webView:shouldStartLoadWithRequest:` is expecting you to return a value. You'd have to freeze your whole application for potentially several seconds to do a synchronous `NSURLRequest` to get the headers. It's a surprisingly tough problem. – Alex Oct 12 '09 at 17:20
  • However, I could just return YES no matter what after firing off an asyncronous one, and then have it start the download potentially a few seconds late (which is perfectly fine). But, how would I just get the headers? – Grant Paul Oct 12 '09 at 21:57
  • This is true. If you kick off an `NSURLConnection`, the delegate method `connection:didReceiveResponse:` gives you an `NSURLResponse`, which will have the MIME type. Kaboom. – Alex Oct 13 '09 at 03:10