web-dev-qa-db-ja.com

UIWebViewでアプリのURLを処理する方法は?

最近、私のUIWebViewがITMSリンクで窒息していることがわかりました。具体的には、アプリのUIWebViewから this one などのサイトに移動し、「App Storeで利用可能」リンクをクリックすると、UIWebViewは「Error Domain = WebKitErrorDomain Code = 101 URLを表示できません。」

少しグーグルで調べた後、アプリリンクのリクエストをキャッチし、iOSで処理する必要があることに気付きました。スキームが-webView:shouldStartLoadWithRequest:navigationType:の「itms」で始まるかどうかを調べることから始めましたが、システムが処理できる他の種類のアプリリンクがあるかもしれないことに気付きました。だから、代わりにこれを思いついた:

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

これについて2つの質問があります。

  1. これは正気ですか?エラードメインとエラーコードを具体的にチェックし、userInfoからURL文字列を取得しています。そのようなものは残る可能性が高いですか?
  2. これは、上記のリンクされたアプリストアリンクでは機能しますが、アプリに戻ると、「Frame load interrupted」で失敗した後続のリクエストが失敗したようです。どうすればそれを取り除くことができますか? OSが-webView:shouldStartLoadWithRequest:navigationType:からのリクエストを処理するようになっているときは起こらないので、少し面倒です。

youはそのようなリクエストをどのように処理しますか?

61
theory

これが私が思いついたものです。 webView:shouldStartLoadWithRequest:navigationType:では、次のように、OSにHTTP以外およびHTTP以外のリクエストを処理するように依頼します。

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

これは、血なまぐさい "Frame Load Interrupted"エラーを除いて非常にうまく機能します。 webView:shouldStartLoadWithRequest:navigationType:からfalseを返すことで、Webビューがリクエストをロードしないため、処理するエラーがなくなると考えていました。しかし、上記のNOを返しても、「フレームロードが中断されました」というエラーが発生します。何故ですか?

とにかく、-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…
}

そして今、iTunes URLはmailto:sおよびアプリリンクと同様に適切に機能します。

91
theory

Theoryのコードから始めて、「itms」スキームのURLを調べます(このメソッドは、リダイレクトのために複数回呼び出すことができます)。 「itms」スキームが表示されたら、webViewのロードを停止し、SafariでURLを開きます。私のWebViewはたまたまNavigationControllerにあるので、Safariを開いた後(点滅が少なくなる)、そこから飛び出します。

- (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;
    }
}
8
Steve Spencer