iOS UIWebView 中的 Javascript console.log()

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6508313/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 22:06:33  来源:igfitidea点击:

Javascript console.log() in an iOS UIWebView

javascriptiosuiwebview

提问by TinkerTank

When writing a iPhone / iPad app with a UIWebView, the console isn't visible. this excellent answershows how to trap errors, but I would like to use the console.log() as well.

使用 UIWebView 编写 iPhone/iPad 应用程序时,控制台不可见。 这个优秀的答案展示了如何捕获错误,但我也想使用 console.log() 。

采纳答案by TinkerTank

I have a solution to log, using javascript, to the apps debug console. It's a bit crude, but it works.

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

First, we define the console.log() function in javascript, which opens and immediately removes an iframe with a ios-log: url.

首先,我们在 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;

Now we have to catch this URL in the UIWebViewDelegate in the iOS app using the shouldStartLoadWithRequest function.

现在我们必须使用 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;
}

回答by NSTJ

After consulting with an esteemed colleague today he alerted me to the Safari Developer Toolkit, and how this can be connected to UIWebViews in the iOS Simulator for console output (and debugging!).

今天咨询了一位受人尊敬的同事后,他提醒我注意 Safari Developer Toolkit,以及如何将其连接到 iOS 模拟器中的 UIWebViews 以进行控制台输出(和调试!)。

Steps:

脚步:

  1. Open Safari Preferences -> "Advanced" tab -> enable checkbox "Show Develop menu in menu bar"
  2. Start app with UIWebView in iOS Simulator
  3. Safari -> Develop -> i(Pad/Pod) Simulator -> [the name of your UIWebView file]
  1. 打开Safari首选项->“高级”选项卡->启用复选框“在菜单栏中显示开发菜单”
  2. 在 iOS 模拟器中使用 UIWebView 启动应用程序
  3. Safari -> 开发 -> i(Pad/Pod) 模拟器 -> [the name of your UIWebView file]

You can now drop complex (in my case, flot) Javascript and other stuff into UIWebViews and debug at will.

您现在可以将复杂的(在我的情况下为flot)Javascript 和其他内容放入 UIWebViews 并随意调试。

EDIT: As pointed out by @Joshua J McKinnon this strategy also works when debugging UIWebViews on a device. Simply enable Web Inspector on your device settings: Settings->Safari->Advanced->Web Inspector (cheers @Jeremy Wiebe)

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

UPDATE: WKWebView is supported too

更新:也支持 WKWebView

回答by Leslie Godwin

Here's the Swift solution:(It's a bit of a hack to get the context)

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

  1. You create the UIWebView.

  2. Get the internal context and override the console.log()javascript function.

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

回答by Ji Fang

Starting from iOS7, you can use native Javascript bridge. Something as simple as following

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

回答by tangent405

NativeBridge is very helpful for communicating from a UIWebView to Objective-C. You can use it to pass console logs and call Objective-C functions.

NativeBridge 对于从 UIWebView 到 Objective-C 的通信非常有帮助。您可以使用它来传递控制台日志和调用 Objective-C 函数。

https://github.com/ochameau/NativeBridge

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

The advantage of this technique is that things like newlines in log messages are preserved.

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

回答by parag

Tried Leslie Godwin's fix but was getting this error:

尝试了 Leslie Godwin 的修复,但遇到了这个错误:

'objectForKeyedSubscript' is unavailable: use subscripting

For Swift 2.2, here's what worked for me:

对于 Swift 2.2,这对我有用:

You will need to import JavaScriptCore for this code to compile:

您需要导入 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")
}

Then in your javascript code, calling console.log("_your_log_") will print in Xcode console.

然后在您的 javascript 代码中,调用 console.log("_your_log_") 将在 Xcode 控制台中打印。

Better yet, add this code as an extension to UIWebView:

更好的是,将此代码添加为 UIWebView 的扩展:

import JavaScriptCore

extension UIWebView {
    public func hiHymanConsoleLog() {
        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")
        }
    }
}

And then call this method during your UIWebView initialization step:

然后在您的 UIWebView 初始化步骤中调用此方法:

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

回答by Barath

Swift 5

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