iOS UIWebView中的Javascript console.log()

问题描述:

使用UIWebView编写iPhone/iPad应用程序时,控制台不可见。 this excellent answer显示如何捕获错误,但我也想使用console.log()。iOS UIWebView中的Javascript console.log()

+1

写在浏览器中第一次,开启开发工具,然后看看控制台输出。 – tjameson

我有一个解决方案,使用JavaScript,登录到应用程序调试控制台。 这有点粗糙,但它的工作原理。

首先,我们在javascript中定义console.log()函数,该函数打开并立即使用ios-log:url删除iframe。

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

现在我们必须抓住用shouldStartLoadWithRequest功能在UIWebViewDelegate在iOS应用此URL。

- (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; 
} 
+1

下面看到NSTJ的简单思路。 –

+0

这太棒了...... –

NativeBridge对于从UIWebView到Objective-C的通信非常有帮助。您可以使用它来传递控制台日志并调用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); 
}; 

这种技术的优点是,之类的东西在日志消息换行符将被保留。

+0

+1。注意[Apache Cordova](http://cordova.apache.org/)用户 - Cordova已经处理'console.log',但这个答案中的'window.onerror'函数非常有用! – mpontillo

今天在咨询了一位尊敬的同事之后,他向我发送了Safari Developer Toolkit以及如何将它连接到iOS Simulator的UIWebViews以用于控制台输出(和调试!)。

步骤:

  1. 打开Safari偏好设置 - > “高级” 选项卡 - >启用勾选 “在菜单栏中显示开发菜单”
  2. 与UIWebView中开始应用在iPhone模拟器
  3. Safari浏览器 - >发展 - >我(PAD/POD)模拟器 - >[the name of your UIWebView file]

现在您可以删除复杂的(在我的情况,海军报)Javascript和其他的东西进入UIWebViews并随意调试。

编辑:正如@Joshua J McKinnon所指出的,这个策略在设备上调试UIWebViews时也有效。只要在您的设备设置中启用Web检查:设置 - > Safari->高级 - > Web检查(欢呼@Jeremy韦博)

更新:支持WKWebView太

+12

请注意,此策略在真实iOS设备上进行调试时也适用。 –

+0

优秀!谢谢,这样可以节省很多时间。 –

+0

太棒了!完全有用的功能。 (不仅对日志) – adsurbum

从iOS7开始,你可以使用本地JavaScript桥。东西如下

#import <JavaScriptCore/JavaScriptCore.h> 

JSContext *ctx = [webview valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"]; 
ctx[@"console"][@"log"] = ^(JSValue * msg) { 
NSLog(@"JavaScript %@ log message: %@", [JSContext currentContext], msg); 
    }; 
+0

出于兴趣,在哪里放置这段代码的理想场所? –

+0

好的,想通了。在创建UIWebview之后,您可以设置任何'JSContext'东西。 –

+1

'JSContext'是否仍然可以在iOS 8+中使用WKWebView? –

简单以下是雨燕的解决方案: (这是一个黑客位来获取上下文)

  1. 您创建一个UIWebView。

  2. 获取内部上下文并覆盖控制台上的。日志() javascript函数。

    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") 
    
+3

+100!节省了我吨的时间,很好的黑客,需要在JS代码中进行0次更改。谢谢!!就我未来的读者而言,我的2美分:不要忘记将JavaScriptCore框架链接到您的项目并将它导入到您的webview swift文件中。 – mindbomb

+0

太棒了!谢谢! – Frade

+1

不适用于WKWebView :-( – CedricSoubrie

试图莱斯利·戈德温的修复,但在收到此错误:

'objectForKeyedSubscript' is unavailable: use subscripting 

对于雨燕2.2,这里是为我工作:

您需要导入的JavaScriptCore此代码编译:

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

然后在你的javascript代码中,调用console.log(“_ your_log_”)将在Xcode控制台中打印。

更重要的是,添加以下代码作为扩展的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") 
     } 
    } 
} 

然后在你的UIWebView初始化步骤调用这个方法:

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