İOS UIWebView'da Javascript console.log ()


Yanıtlar:


185

Bugün saygın bir iş arkadaşına danıştıktan sonra, Safari Geliştirici Araç Seti ve bunun konsol çıktısı (ve hata ayıklama!) İçin iOS Simülatöründe UIWebViews'a nasıl bağlanabileceği konusunda beni uyardı.

Adımlar:

  1. Safari Tercihlerini açın -> "Gelişmiş" sekmesini -> "Geliştirme menüsünü menü çubuğunda göster" onay kutusunu etkinleştirin
  2. İOS Simulator'da UIWebView ile uygulamayı başlatın
  3. Safari -> Geliştirme -> i (Ped / Pod) Simülatörü -> [the name of your UIWebView file]

Artık karmaşık (benim durumumda, flot ) Javascript ve diğer şeyleri UIWebViews'a bırakabilir ve istediğiniz zaman hata ayıklayabilirsiniz.

DÜZENLEME: @Joshua J McKinnon tarafından belirtildiği gibi bu strateji, bir cihazda UIWebViews hata ayıklarken de işe yarar. Cihaz ayarlarınızda Web Inspector'ı etkinleştirmeniz yeterlidir: Ayarlar-> Safari-> Gelişmiş-> Web Denetçisi (@Jeremy Wiebe'yi alkışlar)

GÜNCELLEME: WKWebView da desteklenmektedir


13
Bu stratejinin gerçek iOS cihazlarında hata ayıklarken de işe yaradığını unutmayın.
Joshua J. McKinnon

2
Yapabilseydim +100. Bu harika, telefon boşluk uygulamaları için de çalışıyor!
Andy Novocin

2
Bir iPad ile denediğimde, Safari'de geliştirme menüsüne gittiğimde, seçilecek Aygıt yok. Simülatörde konuşlandırdığımda, bir cazibe gibi çalışıyor.
Floydian

10
@Floydian, cihazda Web Inspector'ı etkinleştirmelisiniz. Ayarlar-> Safari-> Gelişmiş-> Web Denetçisi.
Jeremy Wiebe

2
uygulamam geliştirme menümde görünmüyor. Web denetçisini etkinleştirdim. Safari görünüyor, ancak uygulamam (güncel olan; y 2 ​​UIWeb görünümü görüntülüyor) algılanmadı .. herhangi bir fikir?
narco

82

Javascript kullanarak uygulama hata ayıklama konsoluna giriş yapmak için bir çözümüm var. Biraz kaba ama işe yarıyor.

İlk olarak, ios-log: url ile bir iframe'i açan ve hemen kaldıran javascript'te console.log () işlevini tanımlarız.

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

Şimdi bu URL'yi shouldStartLoadWithRequest işlevini kullanarak iOS uygulamasındaki UIWebViewDelegate'de yakalamamız gerekiyor.

- (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
aşağıdaki basit NSTJ fikrine bakın.
Ashwin S

belki hızlı 4'te? : D
Konstantinos Natsios

35

İşte Swift çözümü: (İçeriği anlamak biraz zor)

  1. UIWebView oluşturursunuz.

  2. Dahili bağlamı alın ve console.log () javascript işlevini geçersiz kılın .

    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! Bana TONS zaman kazandırdı, harika hack, JS kodunda 0 değişiklik gerektiriyor. Teşekkürler!! Gelecekteki okuyucular için sadece 2 sentim: JavaScriptCoreframework'ü projenize ve importwebview swift dosyanıza bağlamayı unutmayın .
mindbomb

Swift 4 ile benim için çalışıyor ... "log" u NSString..context.objectForKeyedSubscript'e ("konsol") çevirmelisiniz. SetObject (unsafeBitCast (logFunction, to: AnyObject.self), forKeyedSubscript: NSString olarak "log")
Serge

28

İOS7'den başlayarak, yerel Javascript köprüsünü kullanabilirsiniz. Takip etmek kadar basit bir şey

 #import <JavaScriptCore/JavaScriptCore.h>

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

İlgisiz, bu kodu koymak için ideal yer neresi?
Leslie Godwin

Tamam, anladım. Oluşturduktan hemen sonra UIWebviewher JSContextşeyi kurabilirsiniz .
Leslie Godwin

4
Does JSContexthala ile iOS 8+ çalışmak WKWebView?
Nikolai Samteladze

Onu içine koydum - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationTypeve mükemmel çalışıyor!
Artur Bartczak

@NikolaiSamteladze: WKWebViewiOS 11.4.1 ile denedim ve bulamıyor documentViewve çöküyor. Bu cevabı gördüm ve öyle görünüyor ki, bu şekilde mümkün değil.
test

10

NativeBridge, UIWebView'dan Objective-C'ye iletişim kurmak için çok faydalıdır. Konsol günlüklerini geçirmek ve Objective-C işlevlerini çağırmak için kullanabilirsiniz.

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

Bu tekniğin avantajı, günlük mesajlarındaki satırsonu gibi şeylerin korunmasıdır.


+1. İçin Not Apache Cordova kullanıcıları - Cordova zaten kulpları console.log, ama window.onerrorbu cevap fonksiyonu çok kullanışlıdır!
mpontillo

Appcelerator / Titanium geliştiricileri için: bu da Ti.UI.WebView
Byters

0

Leslie Godwin'in düzeltmesini denedim ama şu hatayı alıyordum:

'objectForKeyedSubscript' is unavailable: use subscripting

Swift 2.2 için, işte benim için işe yarayanlar:

Bu kodu derlemek için JavaScriptCore'u içe aktarmanız gerekecek:

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

Daha sonra javascript kodunuzda, console.log ("_ your_log_") çağrısı Xcode konsolunda yazdırılacaktır.

Daha da iyisi, bu kodu UIWebView'e bir uzantı olarak ekleyin:

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

Ve sonra UIWebView başlatma adımınız sırasında bu yöntemi çağırın:

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

0

Swift 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)
          }
      }
 }
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.