iOS UIWebView中的Javascript console.log()


Answers:


183

在咨询了一位尊敬的同事之后,他提醒我使用Safari开发者工具包,以及如何将其连接到iOS模拟器中的UIWebViews进行控制台输出(和调试!)。

脚步:

  1. 打开Safari偏好设置->“高级”标签->启用复选框“在菜单栏中显示开发菜单”
  2. 在iOS Simulator中使用UIWebView启动应用
  3. Safari->开发-> i(Pad / Pod)模拟器-> [the name of your UIWebView file]

您现在可以将复杂的Javascript和其他内容(在我的情况下为flot)放到UIWebViews中,然后随意进行调试。

编辑:正如@Joshua J McKinnon所指出的,该策略在设备上调试UIWebViews时也适用。只需在设备设置上启用Web Inspector:设置-> Safari->高级-> Web Inspector(欢呼@Jeremy Wiebe)

更新:WKWebView也受支持


13
请注意,在实际的iOS设备上进行调试时,该策略也适用。
约书亚·麦金农

2
如果可以的话,+ 100。这太好了,它也适用于手机间隙应用程序!
Andy Novocin 2014年

2
尝试使用iPad时,当我转到Safari上的“开发”菜单时,没有可供选择的设备。当我在模拟器上部署时,它的工作原理就像一个魅力。
Floydian 2014年

10
@Floydian,您必须在设备上启用Web Inspector。设置-> Safari->高级-> Web检查器。
Jeremy Wiebe 2014年

2
我的应用程序未显示在我的开发菜单中。我已启用Web检查器。出现了Safari,但是未检测到我的应用程序(当前;正在显示2个UIWebviews)。
narco

83

我有一个解决方案,可以使用JavaScript登录到应用程序调试控制台。有点粗糙,但是可以用。

首先,我们在javascript中定义console.log()函数,该函数将打开并立即删除带有ios-log:网址的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;
}

1
请参阅下面的NSTJ的简单想法。
Ashwin S 2014年


35

这是Swift解决方案:( 获取上下文有点技巧)

  1. 您创建UIWebView。

  2. 获取内部上下文并覆盖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")
    

3
+100!节省了我很多时间,很棒的hack,需要对JS代码进行0次更改。谢谢!!给未来读者的钱只有我的2美分:不要忘记将JavaScriptCore框架链接到您的项目,并将import其链接到webview swift文件中。
mindbomb 2015年

使用Swift 4为我工作...您必须将“ log”转换为NSString..context.objectForKeyedSubscript(“ console”)。setObject(unsafeBitCast(logFunction,to:AnyObject.self),forKeyedSubscript:“ log” as NSString)
Serge

28

从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);
    };

出于兴趣,放置此代码的理想位置在哪里?
Leslie Godwin

好,知道了。创建完之后,UIWebview您可以设置任何JSContext东西。
Leslie Godwin

4
是否JSContext在iOS中仍然工作8+用WKWebView
Nikolai Samteladze

我把它放进去- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType,效果很好!
Artur Bartczak '16

@NikolaiSamteladze:我尝试使用WKWebViewiOS 11.4.1,但他找不到documentView并崩溃。我看到了这个答案,看来这是不可能的。
测试

10

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

此技术的优点是保留了日志消息中的换行符之类的内容。


+1。给Apache Cordova用户注意-Cordova已经可以处理了console.log,但是window.onerror此答案中的功能非常有用!
mpontillo

对于Appcelerator / Titanium开发人员:这也可以调试Ti.UI.WebView
Byters 18-3-22

0

尝试了莱斯利·戈德温的修复方法,但遇到此错误:

'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()

0

迅捷5

func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
      webView.evaluateJavaScript("your javascript string") { (value, error) in
          if let errorMessage = (error! as NSError).userInfo["WKJavaScriptExceptionMessage"] as? String {
                print(errorMessage)
          }
      }
 }
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.