web-dev-qa-db-fra.com

La méthode déléguée UIWebView devraitStartLoadWithRequest: équivalente dans WKWebView?

J'ai un module dans mon application iOS 7+ qui est un UIWebView. La page html charge un javascript qui crée des boutons de forme personnalisée (à l'aide de la bibliothèque Raphaeljs). Avec UIWebView, je règle le délégué à moi-même. La méthode déléguée webView: shouldStartLoadWithRequest: navigationType: est appelée chaque fois que l’on appuie sur un de mes boutons personnalisés. Les requêtes ne doivent pas être traitées par le code HTML, mais par le code iOS. J'ai donc utilisé une convention de requête (lue quelque part ici sur stackoverflow) en utilisant "inapp" comme schéma de mes requêtes. Je vérifie ensuite pour l'hôte et prend les mesures appropriées.

Ce code fonctionne bien sous iOS 7. Mais les vues Web étant vides sous iOS 8 (bug?), J'ai donc décidé d'utiliser WKWebView pour iOS 8. Les vues Web affichent maintenant un rendu correct (et incroyablement plus rapide!), Mais mes boutons n’ont aucun effet.

J'ai essayé d'utiliser - (WKNaviation *)loadRequest:(NSURLRequest *)request, mais ce n'est pas appelé.

Je ne trouve pas d'équivalent direct de la méthode de délégué UIWebView webView: shouldStartLoadWithRequest: navigationType:. Quelle est la meilleure façon de traiter ces demandes avec WKWebView?

31
invalidArgument

Relisez votre description. Vous devez savoir comment réimplémenter un pont Javascript/Objective-C avec WKWebView.

Je viens de le faire moi-même, en suivant le tutoriel à http://tetontech.wordpress.com/2014/07/17/objective-c-wkwebview-to-javascript-and-back/ et l'info à l'adresse http://nshipster.com/wkwebkit/

WKWebView intègre une méthode de communication intégrée entre Javascript et Objective-C/Swift: WKScriptMessageHandler.

Commencez par inclure les en-têtes WebKit et le protocole WKScriptMessageHandler dans l'en-tête de votre contrôleur de vue:

#import <UIKit/UIKit.h>
#import <WebKit/WebKit.h>
@interface ViewController : UIViewController <WKScriptMessageHandler>

@end

Lors de l’initialisation de votre WKWebView, vous devez le configurer avec un gestionnaire de messages de script. Nommez-le comme vous voulez, mais il me semble logique de le nommer pour votre application.

    WKWebViewConfiguration *theConfiguration = 
          [[WKWebViewConfiguration alloc] init];
    [theConfiguration.userContentController 
          addScriptMessageHandler:self name:@"myApp"];

    _theWebView = [[WKWebView alloc] initWithFrame:self.view.frame 
                      configuration:theConfiguration];
    [_theWebView loadRequest:request];
    [self.view addSubview:_theWebView];

Maintenant, implémentez userContentController:didReceiveScriptMessage:. Cela se déclenche lorsque votre vue Web reçoit un message. Ainsi, le travail que vous faisiez précédemment avec webView:shouldStartLoadWithRequest:navigationType:.

- (void)userContentController:(WKUserContentController *)userContentController 
                        didReceiveScriptMessage:(WKScriptMessage *)message {
    NSDictionary *sentData = (NSDictionary *)message.body;
    NSString *messageString = sentData[@"message"];
    NSLog(@"Message received: %@", messageString);
}

Vous êtes maintenant prêt à recevoir des messages de Javascript. L’appel de fonction que vous devez ajouter à votre Javascript est le suivant:

window.webkit.messageHandlers.myApp.postMessage({"message":"Hello there"});
9
SeanR

Pour répondre à la question initiale, l'équivalent de webView:shouldStartLoadWithRequest:navigationType: dans UIWebView est webView:decidePolicyForNavigationAction:decisionHandler: dans WKWebView. Ces méthodes sont appelées avant chaque demande (y compris la demande initiale) et permettent de l’autoriser/de la refuser.

67
robnasby

J'ai moi-même cherché une bonne explication, mais je n'en ai pas trouvé. J'ai utilisé les éléments suivants dans mon application et tout semble fonctionner (Edit: mis à jour à partir du commentaire de ccoroom ):

UIWebViewDelegate     - webView:shouldStartLoadWithRequest:navigationType:
WKNavigationDelegate  - webView:decidePolicyForNavigationAction:decisionHandler:

Voici les autres méthodes UIWebViewDelegate:

UIWebViewDelegate     - webViewDidStartLoad:
WKNavigationDelegate  - webView:didCommitNavigation:

UIWebViewDelegate     - webViewDidFinishLoad:
WKNavigationDelegate  - webView:didFinishNavigation:

UIWebViewDelegate     - webView:didFailLoadWithError:
WKNavigationDelegate  - webView:didFailNavigation:withError:
                      - webView:didFailProvisionalNavigation:withError:

J'aimerais bien que quelqu'un me le confirme.

Edit: En fait, j'ai répondu à la question que vous aviez dans le titre (même si je ne suis plus sûr que webView:didCommitNavigation: s'appelle exactement au même moment du cycle de vie), mais relisez votre description, elle ressemble Ce que vous devez réellement savoir, c'est comment réimplémenter un pont Javascript/Objective-C avec WKWebView. Regardez donc mon autre réponse.

65
SeanR

Utilisez simplement la méthode suivante, elle fait partie de WKNavigationDelegate 

- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {

    NSURLRequest *request = navigationAction.request;
    NSString *url = [[request URL]absoluteString];

    decisionHandler(WKNavigationActionPolicyAllow);
}
27
Benzi Heler

Dans Swift vous pouvez faire quelque chose comme ceci:

func webView(webView: WKWebView, decidePolicyForNavigationAction navigationAction: WKNavigationAction, decisionHandler: (WKNavigationActionPolicy) -> Void) {

    switch navigationAction.request.URLString {
    case "http://action.is.needed/some-action":
        self.someFunc()
        decisionHandler(.Cancel)
        break
    default:
        decisionHandler(.Allow)
        break
    }

}

Et voici le lien dans la page Web:

<a href="http://action.is.needed/some-action">Hello world!</a>
7
He Yifei 何一非

pour Swift 4.2 : (extrait de Yifei He 何 一 非.)

 func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: (WKNavigationActionPolicy) -> Void) {

        let url = navigationAction.request.url
        let urlStr = url?.absoluteString
        switch urlStr {
        case BASE_URL:
            //self.someFunc()
            decisionHandler(.cancel)
            break
        default:
            decisionHandler(.allow)
            break
        }

    }
1
ingconti

Vous pouvez ajouter Observer pour votre WKWebView

 static void* keyValueObservingContext = &keyValueObservingContext;

[webView addObserver:self forKeyPath:@"URL" options:0 context:keyValueObservingContext];


- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
 {

if ([keyPath isEqualToString:@"URL"]){
// do something
  }
}

N'oubliez pas de l'enlever à la vueWillDisappear

-(void)viewWillDisappear:(BOOL)animated{
[super viewWillDisappear:animated];
[webView removeObserver:self forKeyPath:@"URL"];
}
0
ramzi shadid