Frage Javascript console.log () in einem iOS UIWebView


Wenn Sie eine iPhone / iPad-App mit einem UIWebView schreiben, ist die Konsole nicht sichtbar. diese ausgezeichnete Antwort zeigt, wie man Fehler abfängt, aber ich möchte auch die console.log () verwenden.


74
2018-06-28 14:43


Ursprung


Antworten:


Nachdem ich mich heute mit einem geschätzten Kollegen beraten hatte, informierte er mich über das Safari Developer Toolkit und wie dies mit den UIWebViews im iOS Simulator für Konsolenausgabe (und Debugging!) Verbunden werden kann.

Schritte:

  1. Safari Einstellungen öffnen -> Registerkarte "Erweitert" -> Kontrollkästchen "Entwicklungsmenü in der Menüleiste anzeigen" aktivieren
  2. Starten Sie die App mit UIWebView im iOS Simulator
  3. Safari -> Entwickeln -> i (Pad / Pod) Simulator -> [the name of your UIWebView file]

Sie können jetzt komplex fallen lassen (in meinem Fall Flot) Javascript und andere Dinge in UIWebViews und debuggen nach Belieben.

BEARBEITEN: Wie von @Joshua J McKinnon gezeigt, funktioniert diese Strategie auch beim Debuggen von UIWebViews auf einem Gerät. Aktivieren Sie Web Inspector einfach in Ihren Geräteeinstellungen: Einstellungen-> Safari-> Erweitert-> Web Inspector (cheers @ Jeremy Wiebe)

UPDATE: WKWebView wird auch unterstützt


149
2017-11-27 02:56



Ich habe eine Lösung, um mit der JavaScript-Debug-Konsole Java zu protokollieren. Es ist ein bisschen grob, aber es funktioniert.

Zuerst definieren wir die Funktion console.log () in Javascript, die einen iframe mit einer ios-log: url öffnet und sofort entfernt.

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

Jetzt müssen wir diese URL in UIWebViewDelegate in der iOS App mit der Funktion shouldStartLoadWithRequest abfangen.

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

81
2018-06-28 14:45



Hier ist die Swift-Lösung: (Es ist ein bisschen ein Hack, um den Kontext zu bekommen)

  1. Sie erstellen das UIWebView.

  2. Rufen Sie den internen Kontext ab und überschreiben Sie den console.log () JavaScript-Funktion.

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

30
2017-11-17 08:08



Ab iOS7 können Sie eine native Javascript-Bridge verwenden. Etwas so einfaches wie folgt

 #import <JavaScriptCore/JavaScriptCore.h>

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

24
2018-02-15 19:47



NativeBridge ist sehr hilfreich für die Kommunikation von einem UIWebView zu Objective-C. Sie können damit Konsolenprotokolle übergeben und Objective-C-Funktionen aufrufen.

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

Der Vorteil dieser Technik ist, dass Dinge wie Zeilenumbrüche in Log-Nachrichten erhalten bleiben.


8
2018-02-14 20:37



Versuchte Leslie Godwin's Lösung, bekam aber diesen Fehler:

'objectForKeyedSubscript' is unavailable: use subscripting

Für Swift 2.2, hier ist, was für mich funktionierte:

Sie müssen JavaScriptCore für diesen Code zum Kompilieren importieren:

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

Dann wird in Ihrem Javascript-Code der Aufruf von console.log ("_ your_log_") in der Xcode-Konsole ausgegeben.

Besser noch, füge diesen Code als Erweiterung von UIWebView hinzu:

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

Und dann rufen Sie diese Methode während Ihres UIWebView-Initialisierungsschritts auf:

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

0
2017-07-08 21:36