Tengo un módulo dentro de mi iOS 7+ app que es un UIWebView. La página html que carga un javascript que crea personalizado en forma de botones (utilizando el Raphaeljs de la biblioteca). Con UIWebView, me puse delegado a sí mismo. El delegado método webView: shouldStartLoadWithRequest: navigationType: se llama cada vez que uno de mis personalizado se pulsa el botón. Las solicitudes no deben ser manejados por el html, sino más bien por el código de iOS. Así que he usado una solicitud de convenio (leído aquí en stackoverflow), usando «inapp» como el esquema de mis peticiones. Luego reviso para el host y tomar la acción apropiada.

Este código funciona bien en iOS 7. Pero la web vistas aparecen en blanco en iOS 8 (bug?), así que me decidí a usar WKWebView para iOS 8 dispositivos. Las vistas web ahora de procesamiento de multa (y sorprendentemente rápido!), pero mis botones no tienen ningún efecto.

He intentado utilizar - (WKNaviation *)loadRequest:(NSURLRequest *)request, pero no se le llama.

No puedo encontrar un equivalente directo de la UIWebView método delegado webView: shouldStartLoadWithRequest: navigationType:. ¿Cuál es la mejor manera de manejar las solicitudes con WKWebView?

7 Comentarios

  1. 14

    Re-lectura de su descripción se parece a lo que realmente necesitas saber acerca de cómo reimplementar un Javascript/Objective-C puente con WKWebView.

    Que acabo de hacer esto por mí mismo, siguiendo el tutorial en http://tetontech.wordpress.com/2014/07/17/objective-c-wkwebview-to-javascript-and-back/ y la información en http://nshipster.com/wkwebkit/

    WKWebView tiene un built-en la forma de comunicarse entre Javascript y Objective-C/Swift: WKScriptMessageHandler.

    Primera, se incluyen aquí los encabezados y WKScriptMessageHandler protocolo en su controlador de vista del encabezado:

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

    El momento de iniciar su WKWebView, debe configurar con una secuencia de comandos del controlador de mensajes. El nombre de lo que quieras, pero a mí me parece un nombre para tu aplicación tiene sentido.

        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];

    Ahora, implementar userContentController:didReceiveScriptMessage:. Esto desencadena cuando el webview recibe un mensaje, por lo que se hace el trabajo que estaba haciendo con webView:shouldStartLoadWithRequest:navigationType:.

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

    Ahora usted está listo para recibir mensajes de Javascript. La llamada a la función que usted necesita para añadir a tu Javascript es este:

    window.webkit.messageHandlers.myApp.postMessage({"message":"Hello there"});
    • En primer lugar, pido disculpas por la demora. He probado tu solución para uno de mis enlaces, y funcionó. Gracias! Voy a aplicar la solución en todas partes ahora. Aunque, puedo ver en mi web, contenido en el simulador, pero no puedo verla en mi dispositivo. En el dispositivo, sigo sin ver una página en blanco. Alguna idea de por qué?
    • Se te carga el contenido de la web de la web o de su paquete? Porque desde entonces he aprendido que hay un poco de un mal error en WKWebView para la carga de contenido local: stackoverflow.com/questions/24882834/…
    • Está cargado de mi paquete. Me acaba de publicar una pregunta dedicado íntegramente a la página en blanco cuestión: stackoverflow.com/q/26455432/873436. Ese vínculo fue muy útil, gracias de nuevo. Esto llevó a la otra cuestión, sin embargo.
    • Es tan complicado. ¿Por qué no utilizar decidePolicyForNavigationAction?
  2. 93

    He estado buscando una buena explicación a mí mismo, pero no he encontrado uno. He utilizado el siguiente en mi aplicación y todo parece que funciona (Edición: actualizado basado en ccoroom comentario):

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

    Aquí está la otra UIWebViewDelegate métodos:

    UIWebViewDelegate     - webViewDidStartLoad:
    WKNavigationDelegate  - webView:didCommitNavigation:
    
    UIWebViewDelegate     - webViewDidFinishLoad:
    WKNavigationDelegate  - webView:didFinishNavigation:
    
    UIWebViewDelegate     - webView:didFailLoadWithError:
    WKNavigationDelegate  - webView:didFailNavigation:withError:
                          - webView:didFailProvisionalNavigation:withError:

    Me encantaría que alguien confirme esto para mí, sin embargo.

    Edición: en Realidad, yo he respondido a la pregunta que había en el título (aunque yo no estoy seguro de que webView:didCommitNavigation: se llama exactamente en el mismo punto del ciclo de vida), pero re-lectura de su descripción se parece a lo que realmente necesitas saber acerca de cómo reimplementar un Javascript/Objective-C puente con WKWebView. Así que eche un vistazo a mi otra respuesta.

    • Tal vez me estoy perdiendo algo, pero una gran diferencia entre webView:shouldStartLoadWithRequest:navigationType: y webView:didStartProvisionalNavigation: parece ser que el último no obtener la NSUrlRequest. ¿Cómo se puede obtener información acerca de la solicitud?
    • Usted puede obtener la dirección URL de WkWebView.URL, pero no estoy seguro acerca de otros detalles de la solicitud.
    • Yo no diría que las dos primeras son las mismas, ya que no se puede evaluar la solicitud y detenerlo en WKNavigationDelegate.
    • «webView:shouldStartLoadWithRequest:navigationType:»‘s de la contraparte es «webView:decidePolicyForNavigationAction:decisionHandler:»
    • Esto responde a la pregunta del título. La pregunta del cuerpo es realmente una pregunta aparte, como @SeanR consejos.
    • Podemos obtener la solicitud de WKNavigationAction (WKNavigationAction.request) en - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler; Usted debe utilizar el método de delegado en el lugar de webView:shouldStartLoadWithRequest:navigationType:.

  3. 71

    Para responder a la pregunta original, el equivalente de webView:shouldStartLoadWithRequest:navigationType: en UIWebView es webView:decidePolicyForNavigationAction:decisionHandler: en WKWebView. Estos métodos son llamados antes de cada solicitud (incluyendo la solicitud inicial) y ofrecer la posibilidad de permitir o prohibir ella.

  4. 31

    Sólo utilice el siguiente método , que es una parte de WKNavigationDelegate

    - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
    
        NSURLRequest *request = navigationAction.request;
        NSString *url = [[request URL]absoluteString];
    
        decisionHandler(WKNavigationActionPolicyAllow);
    }
    • decidePolicyForNavigationAction no llamar. Necesito agregar cualquier cosa llamar a este método en mi javascript lado?
  5. 10

    En Swift puede hacer algo como esto:

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

    Y este es el enlace en la página web:

    <a href="http://action.is.needed/some-action">Hello world!</a>
  6. 6

    para swift 4.2:
    (tomando de Yifei Él 何一非. )

     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
            }
    
        }
    • decidePolicyFor a menudo no se alcanza porque el provisional de navegación fallará
  7. 0

    Puede agregar Observador de su 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
      }
    }

    No te olvides de eliminar de viewWillDisappear

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

Dejar respuesta

Please enter your comment!
Please enter your name here