undeclared type delegate before swift ios8 wkwebview

type - wkwebview navigation swift



Comunicación nativa síncrona de JavaScript a WKWebView (4)

¿Es posible la comunicación sincrónica entre JavaScript y el código nativo de Swift / Obj-C usando WKWebView?

Estos son los enfoques que he probado y han fallado.

Enfoque 1: uso de controladores de script

La nueva forma de WKWebView de recibir mensajes JS es mediante el uso del método delegado userContentController:didReceiveScriptMessage: invocado desde JS por window.webkit.messageHandlers.myMsgHandler.postMessage(''What''s the meaning of life, native code?'') El problema con Este enfoque es que durante la ejecución del método delegado nativo, la ejecución de JS no se bloquea, por lo que no podemos devolver un valor invocando inmediatamente webView.evaluateJavaScript("something = 42", completionHandler: nil) .

Ejemplo (JavaScript)

var something; function getSomething() { window.webkit.messageHandlers.myMsgHandler.postMessage("What''s the meaning of life, native code?"); // Execution NOT blocking here :( return something; } getSomething(); // Returns undefined

Ejemplo (Swift)

func userContentController(userContentController: WKUserContentController, didReceiveScriptMessage message: WKScriptMessage) { webView.evaluateJavaScript("something = 42", completionHandler: nil) }

Enfoque 2: uso de un esquema de URL personalizado

En JS, la redirección utilizando window.location = "js://webView?hello=world" invoca los métodos nativos WKNavigationDelegate , donde se pueden extraer los parámetros de consulta de URL. Sin embargo, a diferencia de UIWebView , el método delegado no está bloqueando la ejecución de JS, por lo que invocar de inmediato EvalJavaScript para pasar un valor a JS tampoco funciona aquí.

Ejemplo (JavaScript)

var something; function getSomething() { window.location = "js://webView?question=meaning" // Execution NOT blocking here either :( return something; } getSomething(); // Returns undefined

Ejemplo (Swift)

func webView(webView: WKWebView, decidePolicyForNavigationAction navigationAction: WKNavigationAction, decisionHandler decisionHandler: (WKNavigationActionPolicy) -> Void) { webView.evaluateJavaScript("something = 42", completionHandler: nil) decisionHandler(WKNavigationActionPolicy.Allow) }

Enfoque 3: uso de un esquema de URL personalizado y un IFRAME

Este enfoque solo difiere en la forma en que se asigna window.location . En lugar de asignarlo directamente, se utiliza el atributo src de un iframe vacío.

Ejemplo (JavaScript)

var something; function getSomething() { var iframe = document.createElement("IFRAME"); iframe.setAttribute("src", "js://webView?hello=world"); document.documentElement.appendChild(iframe); // Execution NOT blocking here either :( iframe.parentNode.removeChild(iframe); iframe = null; return something; } getSomething();

Sin embargo, esto tampoco es una solución, invoca el mismo método nativo que el Enfoque 2, que no es sincrónico.

Apéndice: Cómo lograr esto con el antiguo UIWebView

Ejemplo (JavaScript)

var something; function getSomething() { // window.location = "js://webView?question=meaning" // Execution is NOT blocking if you use this. // Execution IS BLOCKING if you use this. var iframe = document.createElement("IFRAME"); iframe.setAttribute("src", "js://webView?question=meaning"); document.documentElement.appendChild(iframe); iframe.parentNode.removeChild(iframe); iframe = null; return something; } getSomething(); // Returns 42

Ejemplo (Swift)

func webView(webView: UIWebView, shouldStartLoadWithRequest request: NSURLRequest, navigationType: UIWebViewNavigationType) -> Bool { webView.stringByEvaluatingJavaScriptFromString("something = 42") }


Encontré un truco para hacer comunicación sincrónica pero aún no lo he probado: https://.com/a/49474323/2870783

Editar: Básicamente, puede usar el indicador JS () para transportar su carga desde el lado js al lado nativo. En el WKWebView nativo tendrá que interceptar la llamada de solicitud y decidir si es una llamada normal o si es una llamada jsbridge. Luego puede devolver su resultado como devolución de llamada a la llamada de solicitud. Debido a que la llamada rápida se implementa de tal manera que espera la entrada del usuario, su comunicación nativa de JavaScript será síncrona. La desventaja es que solo puede comunicarse a través de cadenas.


Estaba enfrentando un problema similar, lo resolví almacenando devoluciones de llamadas prometedoras.

El js que carga en su vista web a través de WKUserContentController :: addUserScript

var webClient = { id: 1, handlers: {}, }; webClient.onMessageReceive = (handle, error, data) => { if (error && webClient.handlers[handle].reject) { webClient.handlers[handle].reject(data); } else if (webClient.handlers[handle].resolve){ webClient.handlers[handle].resolve(data); } delete webClient.handlers[handle]; }; webClient.sendMessage = (data) => { return new Promise((resolve, reject) => { const handle = ''m'' + webClient.id++; webClient.handlers[handle] = { resolve, reject }; window.webkit.messageHandlers.<message_handler_name>.postMessage({data: data, id: handle}); }); }

Realizar solicitud Js como

webClient.sendMessage(<request_data>).then((response) => { ... }).catch((reason) => { ... });

Recibir solicitud en userContentController: didReceiveScriptMessage

Llame a EvalJavaScript con webClient.onMessageReceive (handle, error, response_data).


No, no creo que sea posible debido a la arquitectura multiproceso de WKWebView. WKWebView se ejecuta en el mismo proceso que su aplicación, pero se comunica con WebKit que se ejecuta en su propio proceso ( Presentación de la API Modern WebKit ). El código JavaScript se ejecutará en el proceso de WebKit. Esencialmente, usted está pidiendo tener comunicación sincrónica entre dos procesos diferentes que va en contra de su diseño.


También investigué este problema y fallé como tú. Para solucionarlo, debe pasar una función de JavaScript como devolución de llamada. La función nativa necesita evaluar la función de devolución de llamada para devolver el resultado. En realidad, esta es la forma de JavaScript, porque JavaScript nunca espera. Bloquear el hilo de JavaScript puede causar ANR, es muy malo.

He creado un proyecto llamado XWebView que puede establecer un puente entre nativo y JavaScript. Ofrece una API de estilo vinculante para llamar nativo desde JavaScript y viceversa. Hay una aplicación de sample .