【问题标题】:Javascript console.log() in an iOS UIWebViewiOS UIWebView 中的 Javascript console.log()
【发布时间】:2011-09-24 09:33:24
【问题描述】:

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

【问题讨论】:

  • 先在浏览器中写入,打开开发者工具,然后查看控制台输出。

标签: javascript ios uiwebview


【解决方案1】:

今天与一位尊敬的同事协商后,他提醒我注意 Safari 开发者工具包,以及如何将其连接到 iOS 模拟器中的 UIWebViews 以进行控制台输出(和调试!)。

步骤:

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

您现在可以将复杂的(在我的例子中,flot)Javascript 和其他内容放入 UIWebViews 并随意调试。

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

更新:也支持 WKWebView

【讨论】:

  • 注意,这个策略也适用于在真实的 iOS 设备上调试。
  • 如果可以的话+100。这太棒了,它也适用于手机间隙应用程序!
  • 尝试使用 iPad,当我进入 Safari 上的开发菜单时,没有可供选择的设备。当我在模拟器上部署时,它就像一个魅力。
  • @Floydian 你必须在设备上启用 Web Inspector。设置->Safari->高级->Web Inspector.
  • 我的应用没有出现在我的开发菜单中。我启用了网络检查器。 Safari 出现了,但我的应用程序(这是当前的;y 显示 2 个 UIWebviews)没有被检测到.. 有什么想法吗?
【解决方案2】:

我有一个使用 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 函数在 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;
}

【讨论】:

  • 见下面 NSTJ 的简单想法。
  • 可能在 swift 4 中? :D
【解决方案3】:

这是 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")
    

【讨论】:

  • +100!节省了我大量的时间,很棒的 hack,需要对 JS 代码进行 0 次更改。谢谢!!只是我给未来读者的 2 美分:不要忘记将 JavaScriptCore 框架链接到您的项目,并将 import 链接到您的 webview swift 文件中。
  • 适用于我的 Swift 4... 你必须将“log”转换为 NSString..context.objectForKeyedSubscript("console").setObject(unsafeBitCast(logFunction, to: AnyObject.self), forKeyedSubscript : "log" 作为 NSString)
【解决方案4】:

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

【讨论】:

  • 出于兴趣,放置此代码的理想位置在哪里?
  • 好的,想通了。在您创建 UIWebview 之后,您可以设置任何 JSContext 内容。
  • JSContext 在 iOS 8+ 和 WKWebView 中是否仍然有效?
  • 我把它放到- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType 中,效果很好!
  • @NikolaiSamteladze:我尝试使用WKWebView 和iOS 11.4.1,但他找不到documentView 并崩溃。我看到了这个answer,看来,这是不可能的。
【解决方案5】:

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 函数非常有用!
  • 对于 Appcelerator/Titanium 开发人员:这也适用于调试您的 Ti.UI.WebView
【解决方案6】:

斯威夫特 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)
          }
      }
 }

【讨论】:

    【解决方案7】:

    尝试了 Leslie Godwin 的修复,但收到此错误:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-11-26
      • 2017-08-06
      • 1970-01-01
      • 2012-02-12
      • 2018-09-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多