¿Qué diferencia hay entre los métodos callAsyncJavaScript y evaluateJavaScript ?
Utilizarlo con el mismo script como:
evaluateJavaScript("document.documentElement.outerHTML.toString()")
y
callAsyncJavaScript("document.documentElement.outerHTML.toString()")
devuelve resultados diferentes: HTML en primer lugar y .sucess(nil) en segundo...
Hay 3 métodos que permiten ejecutar JS desde WKWebView (bueno, hay más firmas, pero 3 métodos principales):
El más antiguo y primitivo es evaluateJavaScript(_:completionHandler:) , que permite ejecutar fragmentos de código arbitrarios. Hoy en día, no hay excusa para usarlo, ya que no tiene beneficios sobre los otros métodos.
La versión mejorada más moderna es evaluateJavaScript(_:in:in:completionHandler:) que se introdujo en iOS 14. Se puede usar para ejecutar código síncrono. Utiliza una forma moderna de presentar un resultado: Result<Any, Error> , que permite encapsular cualquier tipo de resultado, éxito o fracaso en un solo objeto conveniente para usar. Pero la diferencia clave es que te permite especificarel contexto de la secuencia de comandos , lo que evita conflictos entre diferentes secuencias de comandos:
Ejecutar una secuencia de comandos en su propio mundo de contenido le otorga una copia separada de las variables de entorno para modificar.
evaluateJavaScript con WKScriptMessage (por ejemplo, como se explica aquí ), pero es muy incómodo. Así que callAsyncJavaScript(_:arguments:in:in:completionHandler:) resuelve ese problema: puede usarlo para ejecutar una promesa, sin la ayuda adicional de WKScriptMessage , lo que hace que el código se distribuya menos y sea más fácil. Aquí tienes un ejemplo de cómo se hace.Además tiene 2 ventajas adicionales de este método:
functionBody , que se convierte en una función anónima y evita los posibles conflictos de nombres debido al alcance global de la función.[String : Any] , lo que nos permite definir el cuerpo de la función en algún lugar de forma estática y reutilizarlo pasando los argumentos (en lugar de inyectarlos en el cuerpo de la función como lo necesita con evaluateJavaScript .Por lo tanto, debe usar este método para ejecutar código JS asíncrono, y puede usarlo para el código síncrono.
Una cosa más: con callAsyncJavaScript debe recordar que está definiendo el cuerpo de la función, por lo que si desea que se devuelva algo, debe usar la word return (a diferencia de evaluateJavaScript , donde definió una pieza de código para ejecutar, que puede no tienen return , a menos que defina una función).