Javascript console.log () en una UIWebView de iOS

Al escribir una aplicación para iPhone / iPad con UIWebView, la console no está visible. esta excelente respuesta muestra cómo atrapar errores, pero también me gustaría usar console.log ().

Después de consultar con un colega estimado hoy, me alertó sobre Safari Developer Toolkit, y cómo esto puede conectarse a UIWebViews en el simulador de iOS para la salida de la console (¡y debugging!).

Pasos:

  1. Abra Preferences de Safari -> pestaña "Avanzado" -> active la checkbox "Mostrar el menu de Desarrollo en la barra de menu"
  2. Inicie la aplicación con UIWebView en iOS Simulator
  3. Safari -> Desarrollar -> i (Pad / Pod) Simulador -> [the name of your UIWebView file]

Ahora puede eliminar complejos (en mi caso, flot ) Javascript y otras cosas en UIWebViews y depurar a voluntad.

EDITAR: Como señaló @Joshua J McKinnon, esta estrategia también funciona al depurar UIWebViews en un dispositivo. Simplemente habilite Web Inspector en la configuration de su dispositivo: Configuración-> Safari-> Avanzado-> Web Inspector (vítores @Jeremy Wiebe)

ACTUALIZACIÓN: WKWebView es compatible también

Tengo una solución para iniciar session, usando javascript, en la console de debugging de aplicaciones. Es un poco crudo, pero funciona.

Primero, definimos la function console.log () en javascript, que se abre e inmediatamente elimina un iframe con un ios-log: url.

 // Debug console = new Object(); console.log = function(log) { var iframe = document.createElement("IFRAME"); iframe.setAttribute("src", "ios-log:#iOS#" + log); document.documentElement.appendChild(iframe); iframe.parentNode.removeChild(iframe); iframe = null; }; console.debug = console.log; console.info = console.log; console.warn = console.log; console.error = console.log; 

Ahora tenemos que atrapar esta URL en UIWebViewDelegate en la aplicación iOS utilizando la function shouldStartLoadWithRequest.

 - (BOOL)webView:(UIWebView *)webView2 shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { NSString *requestString = [[[request URL] absoluteString] stringByReplacingPercentEscapesUsingEncoding: NSUTF8StringEncoding]; //NSLog(requestString); if ([requestString hasPrefix:@"ios-log:"]) { NSString* logString = [[requestString componentsSeparatedByString:@":#iOS#"] objectAtIndex:1]; NSLog(@"UIWebView console: %@", logString); return NO; } return YES; } 

Aquí está la solución de Swift: (es un poco complicado para entender el context)

  1. Usted crea el UIWebView.

  2. Obtenga el context interno y anule la function javascript console.log () .

     self.webView = UIWebView() self.webView.delegate = self let context = self.webView.valueForKeyPath("documentView.webView.mainFrame.javaScriptContext") as! JSContext let logFunction : @convention(block) (String) -> Void = { (msg: String) in NSLog("Console: %@", msg) } context.objectForKeyedSubscript("console").setObject(unsafeBitCast(logFunction, AnyObject.self), forKeyedSubscript: "log") 

A partir de iOS7, puede usar el puente Javascript nativo. Algo tan simple como seguir

  #import <JavaScriptCore/JavaScriptCore.h> JSContext *ctx = [webview valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"]; ctx[@"console"][@"log"] = ^(JSValue * msg) { NSLog(@"JavaScript %@ log message: %@", [JSContext currentContext], msg); }; 

NativeBridge es muy útil para comunicarse desde un UIWebView a Objective-C. Puede usarlo para pasar los loggings de la console y llamar a las funciones de Objective-C.

https://github.com/ochameau/NativeBridge

 console = new Object(); console.log = function(log) { NativeBridge.call("logToConsole", [log]); }; console.debug = console.log; console.info = console.log; console.warn = console.log; console.error = console.log; window.onerror = function(error, url, line) { console.log('ERROR: '+error+' URL:'+url+' L:'+line); }; 

La ventaja de esta técnica es que se preservan cosas como las nuevas líneas en los posts de logging.

Intenté la solución de Leslie Godwin pero estaba obteniendo este error:

 'objectForKeyedSubscript' is unavailable: use subscripting 

Para Swift 2.2, esto es lo que funcionó para mí:

Necesitará importar JavaScriptCore para comstackr este código:

 import JavaScriptCore if let context = webView.valueForKeyPath("documentView.webView.mainFrame.javaScriptContext") { context.evaluateScript("var console = { log: function(message) { _consoleLog(message) } }") let consoleLog: @convention(block) String -> Void = { message in print("javascript_log: " + message) } context.setObject(unsafeBitCast(consoleLog, AnyObject.self), forKeyedSubscript: "_consoleLog") } 

Luego, en su código de JavaScript, la llamada a console.log ("_ your_log_") se imprimirá en la console de Xcode.

Mejor aún, agregue este código como una extensión de UIWebView:

 import JavaScriptCore extension UIWebView { public func hijackConsoleLog() { if let context = valueForKeyPath("documentView.webView.mainFrame.javaScriptContext") { context.evaluateScript("var console = { log: function(message) { _consoleLog(message) } }") let consoleLog: @convention(block) String -> Void = { message in print("javascript_log: " + message) } context.setObject(unsafeBitCast(consoleLog, AnyObject.self), forKeyedSubscript: "_consoleLog") } } } 

Y luego llame a este método durante su paso de initialization de UIWebView:

 let webView = UIWebView(frame: CGRectZero) webView.hijackConsoleLog()