iOS UIWebView中的Javascript console.log()
使用UIWebView编写iPhone / iPad应用程序时,控制台不可见。 这个优秀的答案显示了如何捕获错误,但是我也想使用console.log()。
今天在咨询了一位尊敬的同事之后,他向我通报了Safari开发者工具包,以及如何将这个工具包连接到用于控制台输出(和debugging!)的iOS Simulator中的UIWebViews。
脚步:
- 打开Safari首选项 – >“高级”选项卡 – >启用checkbox“在菜单栏中显示制作菜单”
- 在iOS模拟器中使用UIWebView启动应用程序
- Safari – >开发 – >我(Pad / Pod)模拟器 – >
[the name of your UIWebView file]
你现在可以放弃复杂(在我的情况下, flot )Javascript和其他东西到UIWebViews和随意debugging。
编辑:正如@Joshua J McKinnon所指出的,这个策略在设备上debuggingUIWebViews时也是有效的。 只需在您的设备设置上启用Web Inspector:Settings-> Safari-> Advanced-> Web Inspector(欢呼@Jeremy Wiebe)
更新:WKWebView也支持
我有一个解决scheme,使用JavaScript,login到应用程序debugging控制台。 这有点粗糙,但它的工作原理。
首先,我们在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函数在iOS应用程序的UIWebViewDelegate中捕获这个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; }
下面是Swift解决scheme:( 获取上下文有点麻烦)
-
你创build了UIWebView。
-
获取内部上下文并覆盖console.log() 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")
从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); };
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); };
这种技术的优点是保留了日志消息中的换行符。
试过莱斯利戈德温的修复,但得到这个错误:
'objectForKeyedSubscript' is unavailable: use subscripting
对于Swift 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()