Skip to main content

How to handle app URLs in a UIWebView?



I recently found that my UIWebView was choking on ITMS links. Specifically, from the UIWebView in my app, if I navigate to a site such as this one and click the "Available on the App Store" link, UIWebView would error out with "Error Domain=WebKitErrorDomain Code=101 The URL can't be shown."





After a bit of Googling, I realized that I needed to catch requests for app links and have iOS handle them. I started out by looking to see if the scheme starts with "itms" in -webView:shouldStartLoadWithRequest:navigationType: , but realized that there might be other kinds of app links that the system can handle. So I came up with this, instead:







- (void)webView:(UIWebView *)wv didFailLoadWithError:(NSError *)error {

// Give iOS a chance to open it.

NSURL *url = [NSURL URLWithString:[error.userInfo objectForKey:@"NSErrorFailingURLStringKey"]];

if ([error.domain isEqual:@"WebKitErrorDomain"]

&& error.code == 101

&& [[UIApplication sharedApplication]canOpenURL:url])

{

[[UIApplication sharedApplication]openURL:url];

return;

}



// Normal error handling…

}







I have two questions about this:





  1. Is this sane? I'm specifically checking for the error domain and error code and fetching the URL string from the userInfo. Is that stuff likely to remain?



  2. This does work for the above-linked app store link, but when I switch back to my app, there appears to have been a subsequent failed request that failed with "Frame load interrupted". how can I get rid of that? It doesn't happen when I have the OS handle the request from -webView:shouldStartLoadWithRequest:navigationType: , so it's a bit annoying.







How do you handle such requests?



Source: Tips4all

Comments

  1. Here's what I came up with. In webView:shouldStartLoadWithRequest:navigationType:, I ask the OS to handle any non-http and non-https requests that it can, like so:

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

    // Determine if we want the system to handle it.
    NSURL *url = request.URL;
    if (![url.scheme isEqual:@"http"] && ![url.scheme isEqual:@"https"]) {
    if ([[UIApplication sharedApplication]canOpenURL:url]) {
    [[UIApplication sharedApplication]openURL:url];
    return NO;
    }
    }
    return YES;
    }


    This works very well except for the bloody "Frame Load Interrupted" error. I had thought that by returning false from webView:shouldStartLoadWithRequest:navigationType: that the web view would not load the request and therefore there would be no errors to handle. But even though I return NO above, I still "Frame Load Interrupted" error. Why is that?

    Anyway, I'm assuming it can be ignored in -webView:didFailLoadWithError::

    - (void)webView:(UIWebView *)wv didFailLoadWithError:(NSError *)error {
    // Ignore NSURLErrorDomain error -999.
    if (error.code == NSURLErrorCancelled) return;

    // Ignore "Fame Load Interrupted" errors. Seen after app store links.
    if (error.code == 102 && [error.domain isEqual:@"WebKitErrorDomain"]) return;

    // Normal error handling…
    }


    And now iTunes URLs work properly, as do mailto:s and app links.

    ReplyDelete
  2. Starting with Theory's code, examine the URL for "itms" scheme(s) (this method can be called multiple times due to redirects). Once you see an "itms" scheme, stop the webView from loading and open the URL with Safari. My WebView happens to be in a NavigationController, so I pop out of that after opening Safari (less flashing).

    - (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request
    navigationType:(UIWebViewNavigationType)navigationType
    {
    if ([[[request URL] scheme] isEqualToString:@"itms-apps"]) {
    [webView stopLoading];
    [[UIApplication sharedApplication] openURL:[request URL]];
    [self.navigationController popViewControllerAnimated:YES];
    return NO;
    } else {
    return YES;
    }
    }

    ReplyDelete
  3. Does it help if you register your app for handling itms: links?

    e.g.
    http://inchoo.net/iphone-development/launching-application-via-url-scheme/

    You may start with scheme http but then get an itms redirect, which could fail if your app is not registered as handling that scheme.

    ReplyDelete
  4. Its been almost a year since this post. I also came across the same problem and luckily figured out the possible solution to "Frame Load Interrupted" problem. I turns out that setting UIWebView's delegate to nil if it passes the condition of not being http or https solves the problem.

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

    // Determine if we want the system to handle it.
    NSURL *url = request.URL;
    if (![url.scheme isEqual:@"http"] && ![url.scheme isEqual:@"https"]) {
    webView.delegate = nil;
    if ([[UIApplication sharedApplication]canOpenURL:url]) {
    [[UIApplication sharedApplication]openURL:url];
    return NO;
    }
    }
    return YES;
    }

    ReplyDelete

Post a Comment

Popular posts from this blog

[韓日関係] 首相含む大幅な内閣改造の可能性…早ければ来月10日ごろ=韓国

div not scrolling properly with slimScroll plugin

I am using the slimScroll plugin for jQuery by Piotr Rochala Which is a great plugin for nice scrollbars on most browsers but I am stuck because I am using it for a chat box and whenever the user appends new text to the boxit does scroll using the .scrollTop() method however the plugin's scrollbar doesnt scroll with it and when the user wants to look though the chat history it will start scrolling from near the top. I have made a quick demo of my situation http://jsfiddle.net/DY9CT/2/ Does anyone know how to solve this problem?

Why does this javascript based printing cause Safari to refresh the page?

The page I am working on has a javascript function executed to print parts of the page. For some reason, printing in Safari, causes the window to somehow update. I say somehow, because it does not really refresh as in reload the page, but rather it starts the "rendering" of the page from start, i.e. scroll to top, flash animations start from 0, and so forth. The effect is reproduced by this fiddle: http://jsfiddle.net/fYmnB/ Clicking the print button and finishing or cancelling a print in Safari causes the screen to "go white" for a sec, which in my real website manifests itself as something "like" a reload. While running print button with, let's say, Firefox, just opens and closes the print dialogue without affecting the fiddle page in any way. Is there something with my way of calling the browsers print method that causes this, or how can it be explained - and preferably, avoided? P.S.: On my real site the same occurs with Chrome. In the ex