I am trying to read the console logs of webapp that is loaded in my WkWebview programmatically.
so far in my research it's not possible.
How can I achieve this?
It's possible to connect Safari browser on you Mac to the WKWebView and get access to the console.
From Safari, open "Develop" tab and while the iOS Simulator is running with the WKWebView open - just click it to open the console. See:
This worked for me (Swift 4.2/5):
// inject JS to capture console.log output and send to iOS
let source = "function captureLog(msg) { window.webkit.messageHandlers.logHandler.postMessage(msg); } window.console.log = captureLog;"
let script = WKUserScript(source: source, injectionTime: .atDocumentEnd, forMainFrameOnly: false)
webView.configuration.userContentController.addUserScript(script)
// register the bridge script that listens for the output
webView.configuration.userContentController.add(self, name: "logHandler")
Then, conforming to the protocol WKScriptMessageHandler, pick up redirected console messages with the following:
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
if message.name == "logHandler" {
print("LOG: \(message.body)")
}
}
I needed a way to see JavaScript logs in Xcode's console. Based on the answer by noxo, here's what I came up with:
let overrideConsole = """
function log(emoji, type, args) {
window.webkit.messageHandlers.logging.postMessage(
`${emoji} JS ${type}: ${Object.values(args)
.map(v => typeof(v) === "undefined" ? "undefined" : typeof(v) === "object" ? JSON.stringify(v) : v.toString())
.map(v => v.substring(0, 3000)) // Limit msg to 3000 chars
.join(", ")}`
)
}
let originalLog = console.log
let originalWarn = console.warn
let originalError = console.error
let originalDebug = console.debug
console.log = function() { log("📗", "log", arguments); originalLog.apply(null, arguments) }
console.warn = function() { log("📙", "warning", arguments); originalWarn.apply(null, arguments) }
console.error = function() { log("📕", "error", arguments); originalError.apply(null, arguments) }
console.debug = function() { log("📘", "debug", arguments); originalDebug.apply(null, arguments) }
window.addEventListener("error", function(e) {
log("💥", "Uncaught", [`${e.message} at ${e.filename}:${e.lineno}:${e.colno}`])
})
"""
class LoggingMessageHandler: NSObject, WKScriptMessageHandler {
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
print(message.body)
}
}
let userContentController = WKUserContentController()
userContentController.add(LoggingMessageHandler(), name: "logging")
userContentController.addUserScript(WKUserScript(source: overrideConsole, injectionTime: .atDocumentStart, forMainFrameOnly: true))
let webViewConfig = WKWebViewConfiguration()
webViewConfig.userContentController = userContentController
let webView = WKWebView(frame: .zero, configuration: webViewConfig)
It has a few improvements:
log
, warn
, error
and debug
console.log
, not just the first oneIf you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With