Javascript console.log () trong UIWebView iOS


84

Khi viết ứng dụng iPhone / iPad bằng UIWebView, bảng điều khiển sẽ không hiển thị. câu trả lời tuyệt vời này chỉ ra cách bẫy lỗi, nhưng tôi cũng muốn sử dụng console.log ().


1
Trước tiên, hãy viết nó vào trình duyệt, bật Công cụ dành cho nhà phát triển, sau đó xem đầu ra của bảng điều khiển.
beatgammit

Câu trả lời:


183

Sau khi tham khảo ý kiến ​​của một đồng nghiệp đáng kính, hôm nay anh ấy đã cảnh báo tôi về Bộ công cụ dành cho nhà phát triển Safari và cách kết nối bộ công cụ này với UIWebViews trong Trình mô phỏng iOS cho đầu ra bảng điều khiển (và gỡ lỗi!).

Các bước:

  1. Mở Tùy chọn Safari -> tab "Nâng cao" -> bật hộp kiểm "Hiển thị menu Phát triển trong thanh menu"
  2. Khởi động ứng dụng với UIWebView trong iOS Simulator
  3. Safari -> Develop -> i (Pad / Pod) Simulator -> [the name of your UIWebView file]

Bây giờ bạn có thể thả Javascript phức tạp (trong trường hợp của tôi là flot ) và những thứ khác vào UIWebViews và gỡ lỗi theo ý muốn.

CHỈNH SỬA: Như đã chỉ ra bởi @Joshua J McKinnon, chiến lược này cũng hoạt động khi gỡ lỗi UIWebViews trên một thiết bị. Chỉ cần bật Trình kiểm tra web trên cài đặt thiết bị của bạn: Cài đặt-> Safari-> Nâng cao-> Trình kiểm tra web (chúc mừng @Jeremy Wiebe)

CẬP NHẬT: WKWebView cũng được hỗ trợ


13
Lưu ý, chiến lược này cũng hoạt động khi gỡ lỗi trên thiết bị iOS thực.
Joshua J. McKinnon

2
+100 nếu tôi có thể. Điều này thật tuyệt vời, nó cũng hoạt động cho các ứng dụng khoảng cách điện thoại!
Andy Novocin

2
Thử với iPad, khi tôi chuyển đến menu phát triển trên Safari, không có Thiết bị nào để chọn. Khi tôi triển khai trên trình mô phỏng, nó hoạt động giống như một sự quyến rũ.
Floydian

10
@Floydian bạn phải bật Trình kiểm tra web trên thiết bị. Cài đặt-> Safari-> Nâng cao-> Trình kiểm tra web.
Jeremy Wiebe

2
ứng dụng của tôi không hiển thị trong menu phát triển của tôi. Tôi đã kích hoạt trình kiểm tra web. Safari hiển thị, nhưng ứng dụng của tôi (hiện tại; y hiển thị 2 UIWebview) không được phát hiện .. bất kỳ ý tưởng nào?
tuý

83

Tôi có một giải pháp để ghi nhật ký, sử dụng javascript, vào bảng điều khiển gỡ lỗi ứng dụng. Nó hơi thô, nhưng nó hoạt động.

Đầu tiên, chúng ta xác định hàm console.log () trong javascript, hàm này sẽ mở và xóa ngay lập tức một iframe có 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;

Bây giờ chúng ta phải bắt URL này trong UIWebViewDelegate trong ứng dụng iOS bằng cách sử dụng chức năng 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
xem ý tưởng đơn giản của NSTJ bên dưới.
Ashwin S

trong nhanh chóng 4 có thể? : D
Konstantinos Natsios

35

Đây là giải pháp Swift: (Có một chút khó khăn khi lấy bối cảnh)

  1. Bạn tạo UIWebView.

  2. Lấy ngữ cảnh bên trong và ghi đè hàm 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! đã tiết kiệm cho tôi HÀNG TẤN thời gian, hack tuyệt vời, yêu cầu 0 thay đổi trong mã JS. Cảm ơn!! Chỉ 2 xu của tôi cho những độc giả trong tương lai: đừng quên liên kết JavaScriptCorekhung với dự án của bạn và importnó trong tệp nhanh webview của bạn.
mindbomb

Làm việc cho tôi với Swift 4 ... bạn phải truyền "log" tới NSString..context.objectForKeyedSubscript ("console"). SetObject (secureBitCast (logFunction, thành: AnyObject.self), forKeyedSubscript: "log" là NSString)
Serge

28

Bắt đầu từ iOS7, bạn có thể sử dụng cầu nối Javascript gốc. Một cái gì đó đơn giản như sau

 #import <JavaScriptCore/JavaScriptCore.h>

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

Không quan tâm, đâu là nơi lý tưởng để đặt mã này?
Leslie Godwin

OK, đã tìm ra. Ngay sau khi bạn tạo, UIWebviewbạn có thể thiết lập bất kỳ JSContextthứ gì.
Leslie Godwin

4
Liệu JSContextvẫn làm việc trong iOS 8+ với WKWebView?
Nikolai Samteladze

Tôi đã đưa nó vào - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationTypevà nó hoạt động hoàn hảo!
Artur Bartczak

@NikolaiSamteladze: Tôi đã thử với WKWebViewiOS 11.4.1 và anh ấy không thể tìm thấy documentViewvà bị lỗi. Tôi đã thấy câu trả lời này và có vẻ như không thể theo cách này.
kiểm tra

10

NativeBridge rất hữu ích để giao tiếp từ UIWebView sang Objective-C. Bạn có thể sử dụng nó để chuyển các bản ghi bảng điều khiển và gọi các hàm 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);
};

Ưu điểm của kỹ thuật này là những thứ như dòng mới trong thông báo nhật ký được giữ nguyên.


+1. Lưu ý đến người dùng Apache Cordova - Cordova đã xử lý console.log, nhưng window.onerrorchức năng trong câu trả lời này rất hữu ích!
mpontillo

Đối với các nhà phát triển Appcelerator / Titanium: điều này cũng hoạt động để gỡ lỗi Ti.UI.WebView của bạn
Byters

0

Đã thử sửa lỗi của Leslie Godwin nhưng gặp lỗi này:

'objectForKeyedSubscript' is unavailable: use subscripting

Đối với Swift 2.2, đây là những gì phù hợp với tôi:

Bạn sẽ cần nhập JavaScriptCore cho mã này để biên dịch:

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

Sau đó, trong mã javascript của bạn, việc gọi console.log ("_ your_log_") sẽ in trong bảng điều khiển Xcode.

Tốt hơn, hãy thêm mã này làm tiện ích mở rộng cho 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")
        }
    }
}

Và sau đó gọi phương thức này trong bước khởi tạo UIWebView của bạ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)
          }
      }
 }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.