Javascript console.log () в iOS UIWebView


84

Під час написання програми iPhone / iPad за допомогою UIWebView консоль не видно. ця чудова відповідь показує, як ловити помилки, але я хотів би також скористатися console.log ().


1
Спочатку запишіть це у браузер, увімкніть інструменти розробника, а потім подивіться на вихід консолі.
beatgammit

Відповіді:


183

Проконсультувавшись із шанованим колегою сьогодні, він попередив мене про інструментарій розробника Safari та про те, як це можна підключити до UIWebViews в iOS Simulator для виведення консолі (та налагодження!).

Кроки:

  1. Відкрийте Налаштування Safari -> вкладка "Додатково" -> увімкніть прапорець "Показати меню" Розробка "в рядку меню"
  2. Запустіть програму за допомогою UIWebView в iOS Simulator
  3. Safari -> Розробка -> Симулятор i (Pad / Pod) -> [the name of your UIWebView file]

Тепер ви можете скидати складний (у моєму випадку, flot ) Javascript та інший матеріал в UIWebViews та налагоджувати за бажанням.

EDIT: Як зазначив @Joshua J McKinnon, ця стратегія також працює під час налагодження UIWebViews на пристрої. Просто увімкніть Web Inspector у налаштуваннях пристрою: Налаштування-> Safari-> Додатково-> Web Inspector (вітає @Jeremy Wiebe)

ОНОВЛЕННЯ: Також підтримується WKWebView


13
Зауважте, ця стратегія також працює під час налагодження на реальних пристроях iOS.
Джошуа Дж. Мак-Кіннон,

2
+100 якби міг. Це чудово, це працює і для додатків для телефонних розривів!
Енді Новоцин,

2
Спроба з iPad, коли я заходжу в меню розробки в Safari, немає пристроїв на вибір. Коли я розгортаю на тренажері, це працює як шарм.
Флойдіан,

10
@Floydian ви повинні увімкнути Web Inspector на пристрої. Налаштування-> Safari-> Додатково-> Веб-інспектор.
Jeremy Wiebe

2
мій додаток не відображається в моєму меню розробки. Я увімкнув веб-інспектор. З'являється Safari, але мій додаток (який є актуальним; y відображає 2 UIWebviews) не виявлено .. немає ідей?
нарко

82

У мене є рішення увійти за допомогою javascript на консоль налагодження програм. Це трохи сиро, але це працює.

Спочатку ми визначаємо функцію console.log () у javascript, яка відкриває та негайно видаляє iframe за допомогою 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;

Тепер ми повинні зловити цю URL-адресу в UIWebViewDelegate у додатку iOS, використовуючи функцію 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;
}

1
дивіться просту ідею NSTJ нижче.
Ashwin S

в стрімкий 4, можливо? : D
Костянтинос Націос

35

Ось рішення Swift: (Це трохи зламати, щоб отримати контекст)

  1. Ви створюєте UIWebView.

  2. Отримайте внутрішній контекст і перевизначте функцію javascript console.log () .

    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! зекономив ТОНИ часу, чудовий хак, вимагає 0 змін у коді JS. Дякую!! Лише мої 2 центи для майбутніх читачів: не забудьте прив’язати JavaScriptCoreфреймворк до свого проекту та importйого у вашому швидкому файлі webview.
mindbomb

У мене працює Swift 4 ... вам потрібно передати "журнал" у NSString..context.objectForKeyedSubscript ("консоль"). SetObject (unsafeBitCast (logFunction, to: AnyObject.self), forKeyedSubscript: "log" як 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);
    };

З цікавості, де ідеальне місце для розміщення цього коду?
Леслі Годвін,

Добре, зрозумів. Відразу після створення UIWebviewви можете налаштувати будь-які JSContextречі.
Леслі Годвін,

4
Чи JSContextвсе ще працює в iOS 8+ WKWebView?
Микола Самтеладзе

Я поклав це, - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationTypeі воно працює чудово!
Артур Бартчак

@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 22.03.18

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)
          }
      }
 }
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.