web-dev-qa-db-fra.com

Javascript console.log () dans un UIWebView iOS

Lors de l'écriture d'une application iPhone/iPad avec UIWebView, la console n'est pas visible . cette excellente réponse montre comment intercepter les erreurs, mais j'aimerais également utiliser console.log ().

76
TinkerTank

J'ai une solution pour vous connecter, en utilisant javascript, à la console de débogage des applications . C'est un peu brut, mais ça fonctionne.

Premièrement, nous définissons la fonction console.log () en javascript, qui ouvre et supprime immédiatement un iframe avec un ios-log: url.

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

Nous devons maintenant intercepter cette URL dans UIWebViewDelegate dans l'application iOS à l'aide de la fonction shouldStartLoadWithRequest.

- (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
TinkerTank

Après avoir consulté un collègue estimé aujourd'hui, il m'a alerté sur Safari Developer Toolkit et sur la manière de le connecter à UIWebViews dans le simulateur iOS pour une sortie de console (et le débogage!).

Pas:

  1. Ouvrez les préférences Safari -> onglet "Avancé" -> décochez la case "Afficher le menu Développement dans la barre de menus".
  2. Démarrer l'application avec UIWebView dans iOS Simulator
  3. Safari -> Développer -> i(Pad/Pod) Simulateur -> [the name of your UIWebView file]

Vous pouvez maintenant déposer du code Javascript complexe (dans mon cas, flot ) dans UIWebViews et le déboguer à volonté.

EDIT: Comme l'a souligné @Joshua J McKinnon, cette stratégie fonctionne également lors du débogage de UIWebViews sur un périphérique. Activez simplement Web Inspector sur les paramètres de votre appareil: Paramètres-> Safari-> Avancé-> Web Inspector (acclamations @Jeremy Wiebe)

UPDATE: WKWebView est également pris en charge

167
NSTJ

À partir de iOS7, vous pouvez utiliser le pont Javascript natif. Quelque chose d'aussi simple que de suivre

 #import <JavaScriptCore/JavaScriptCore.h>

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

NativeBridge est très utile pour communiquer d'un UIWebView à Objective-C. Vous pouvez l'utiliser pour passer les journaux de la console et appeler des fonctions 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);
};

L'avantage de cette technique est que des éléments tels que les nouvelles lignes dans les messages de journal sont préservés.

9
tangent405

Essayé le correctif de Leslie Godwin, mais obtenait cette erreur:

'objectForKeyedSubscript' is unavailable: use subscripting

Pour Swift 2.2, voici ce qui a fonctionné pour moi:

Vous devrez importer JavaScriptCore pour que ce code soit compilé:

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

Ensuite, dans votre code javascript, l'appel de console.log ("_ your_log_") sera imprimé dans la console Xcode.

Mieux encore, ajoutez ce code en tant qu’extension de 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")
        }
    }
}

Et appelez ensuite cette méthode lors de votre étape d'initialisation de UIWebView:

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