61 votes

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

J'ai récemment découvert que mon UIWebView s'étouffait sur les liens ITMS. Plus précisément, à partir de l'UIWebView de mon application, si je navigue vers un site tel que celui-ci et que vous cliquez sur le lien "Disponible sur l'App Store", UIWebView affiche une erreur avec "Error Domain=WebKitErrorDomain Code=101 The URL can't be shown".

Après un peu de recherche sur Google, j'ai réalisé que je devais capturer les demandes de liens vers des applications et les faire gérer par iOS. J'ai commencé par regarder si le schéma commençait par "itms" dans le champ -webView:shouldStartLoadWithRequest:navigationType: mais a réalisé qu'il pourrait y avoir d'autres types de liens d'applications que le système peut gérer. 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 que c'est sain d'esprit ? Je vérifie spécifiquement le domaine d'erreur et le code d'erreur et je récupère la chaîne d'URL à partir du userInfo. Ces éléments sont-ils susceptibles d'être conservés ?
  2. Cela fonctionne pour le lien vers le magasin d'applications ci-dessus, mais lorsque je reviens à mon application, il semble qu'une autre demande ait échoué avec le message "Frame load interrupted". Cela ne se produit pas lorsque le système d'exploitation gère la demande à partir de -webView:shouldStartLoadWithRequest:navigationType: donc c'est un peu ennuyeux.

Comment vous traiter ces demandes ?

92voto

theory Points 3177

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

- (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, sauf pour 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 requête et qu'il n'y aurait donc pas d'erreurs à gérer. Mais même si je renvoie NO ci-dessus, je continue à avoir l'erreur "Frame Load Interrupted". Comment cela se fait-il ?

Quoi qu'il en soit, je suppose que l'on peut l'ignorer en -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 d'iTunes fonctionnent correctement, tout comme mailto: et des liens vers des applications.

8voto

Steve Spencer Points 51

En commençant par le code de Théorie, examinez l'URL à la recherche du ou des schémas "itms" (cette méthode peut être appelée plusieurs fois en raison des redirections). Dès que vous voyez un schéma "itms", arrêtez le chargement du WebView et ouvrez l'URL avec Safari. Mon WebView se trouve dans un NavigationController, donc je sors de ce dernier après avoir ouvert 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;
    }
}

-2voto

Adam Eberbach Points 9587

Est-ce que cela peut aider si vous enregistrez votre application pour gérer les liens itms: ?

par exemple http://inchoo.net/iphone-development/launching-application-via-url-scheme/

Vous pouvez commencer par le schéma http mais on obtient alors un itms qui pourrait échouer si votre application n'est pas enregistrée comme gérant ce schéma.

-9voto

xafarr Points 1

Cela fait presque un an depuis ce post, j'ai également rencontré le même problème et j'ai heureusement trouvé une solution possible au problème de "Frame Load Interrupted". Il s'avère que mettre le délégué de UIWebView à nil s'il passe la condition de ne pas être http(s) résout le problème.

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X