web-dev-qa-db-fra.com

Comment gérer les URL des applications dans une UIWebView?

J'ai récemment découvert que mon UIWebView s'étouffait avec les liens ITMS. Plus précisément, à partir de l'UIWebView dans mon application, si je navigue vers un site tel que celui-ci et que je clique sur le lien "Disponible sur l'App Store", UIWebView commettrait une erreur avec "Error Domain = WebKitErrorDomain Code = 101 L'URL ne peut pas être affichée. "

Après un peu de recherche sur Google, je me suis rendu compte que je devais intercepter les demandes de liens d'application et que iOS les gère. J'ai commencé par chercher si le schéma commence par "itms" dans -webView:shouldStartLoadWithRequest:navigationType:, mais s'est rendu compte que le système pouvait gérer d'autres types de liens d'application. J'ai donc trouvé ceci à la place:

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

J'ai deux questions à ce sujet:

  1. Est-ce sain d'esprit? Je vérifie spécifiquement le domaine d'erreur et le code d'erreur et récupère la chaîne URL à partir de userInfo. Est-ce que ce truc est susceptible de rester?
  2. Cela fonctionne pour le lien de l'App Store lié ci-dessus, mais lorsque je reviens à mon application, il semble y avoir eu une demande qui a échoué par la suite et qui a échoué avec "chargement de trame interrompu". comment puis-je m'en débarrasser? Cela ne se produit pas lorsque le système d'exploitation gère la demande de -webView:shouldStartLoadWithRequest:navigationType:, donc c'est un peu ennuyeux.

Comment gérez-vous ces demandes?

61
theory

Voici ce que j'ai trouvé. Dans webView:shouldStartLoadWithRequest:navigationType:, Je demande au système d'exploitation de gérer toutes les demandes non http et non https qu'il peut, comme ceci:

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

Cela fonctionne très bien, à l'exception de l'erreur sanglante "Frame Load Interrupted". J'avais pensé qu'en renvoyant false de webView:shouldStartLoadWithRequest:navigationType: que la vue Web ne chargerait pas la demande et qu'il n'y aurait donc aucune erreur à gérer. Mais même si je renvoie NO ci-dessus, j'ai toujours l'erreur "Frame Load Interrupted". Pourquoi donc?

Quoi qu'il en soit, je suppose qu'il peut être ignoré dans -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…
}

Et maintenant, les URL iTunes fonctionnent correctement, tout comme mailto:s et liens d'application.

91
theory

En commençant par le code de Theory, examinez l'URL pour les schémas "itms" (cette méthode peut être appelée plusieurs fois en raison de redirections). Une fois que vous voyez un schéma "itms", arrêtez le chargement de webView et ouvrez l'URL avec Safari. Mon WebView se trouve être dans un NavigationController, donc j'en ressort après l'ouverture de Safari (moins de clignotement).

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