プログラムでWkWebviewに読み込まれているwebappのコンソールログを読み取ろうとしています。
これまでのところ、私の研究では不可能です。
どうすればこれを達成できますか?
JavaScriptのconsole.log()のデフォルト実装を再評価(オーバーライド)して、代わりにwindow.webkit.messageHandlers.postMessage(msg)を使用してメッセージを転送することができます。次に、ネイティブコードでWKScriptMessageHandler :: didReceiveScriptMessageを使用してjavascript postMessage(msg)呼び出しをインターセプトし、ログに記録されたメッセージを取得します。
ステップ1)postMessage()を使用するためにconsole.logのデフォルト実装を再評価します
// javascript to override console.log to use messageHandlers.postmessage
NSString * js = @"var console = { log: function(msg){window.webkit.messageHandlers.logging.postMessage(msg) };";
// evaluate js to wkwebview
[self.webView evaluateJavaScript:js
ステップ2)WKScriptMessageHandler :: didReceiveScriptMessageでネイティブコードのjavascript postMessageをインターセプトする
- (void)viewDidLoad
{
// create message handler named "logging"
WKUserContentController *ucc = [[WKUserContentController alloc] init];
[ucc addScriptMessageHandler:self name:@"logging"];
// assign usercontentcontroller to configuration
WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init];
[configuration setUserContentController:ucc];
// assign configuration to wkwebview
self.webView = [[WKWebView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height) configuration:configuration];
}
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
{
// what ever were logged with console.log() in wkwebview arrives here in message.body property
NSLog(@"log: %@", message.body);
}
通常、コンソールのログはjsで次のように定義されます
"window.addEventListener("message",function(e){console.log(e.data)});"
私の答えは handling-javascript-events-in-wkwebview !
WKWebViewを構成で初期化する
let config = WKWebViewConfiguration()
let source = "document.addEventListener('message', function(e){
window.webkit.messageHandlers.iosListener.postMessage(e.data); })"
let script = WKUserScript(source: source, injectionTime: .atDocumentEnd, forMainFrameOnly: false)
config.userContentController.addUserScript(script)
config.userContentController.add(self, name: "iosListener")
webView = WKWebView(frame: UIScreen.main.bounds, configuration: config)
または、KVOを使用してプロパティ「estimatedProgress」を監視し、JavaScriptを評価してjsを挿入します
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context
{
if ([keyPath isEqualToString:@"estimatedProgress"])
{
CGFloat progress = [change[NSKeyValueChangeNewKey] floatValue];
if (progress>= 0.9)
{
NSString *jsCmd = @"window.addEventListener(\"message\",function(e){window.webkit.messageHandlers.iosListener.postMessage(e.data)});";
//@"document.addEventListener('click', function(e){ window.webkit.messageHandlers.iosListener.postMessage('Customize click'); })";
[_webView evaluateJavaScript:jsCmd completionHandler:^(id _Nullable obj, NSError * _Nullable error) {
NSLog(@"error:%@",error);
}];
}
}
}
メッセージを受信するWKScriptMessageHandlerプロトコルを実装します。
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage)
{
print("message: \(message.body)")
// and whatever other actions you want to take
}
Swift 4.2および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)
}
}
}
これは私のために働きました(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")
次に、プロトコルWKScriptMessageHandlerに準拠して、リダイレクトされたコンソールメッセージを次のように取得します。
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
if message.name == "logHandler" {
print("LOG: \(message.body)")
}
}