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:
-webView:shouldStartLoadWithRequest:navigationType:
, so it's a bit annoying.How do you handle such requests?
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.