Jak mogę monitorować żądania w WKWebview?
Jak mogę monitorować żądania w WKWebview?
Próbowałem użyć NSURLprotocol (canInitWithRequest), ale nie będzie monitorować żądań ajax (XHR), tylko żądania nawigacji (żądania dokumentów)
3 answers
W końcu to rozwiązałem
Ponieważ nie mam kontroli nad treścią widoku sieci Web, wstrzyknąłem do WKWebview skrypt java, który zawiera słuchacz żądań jQuery AJAX.
Gdy słuchacz przechwyci żądanie, wysyła do aplikacji natywnej treść żądania w metodzie:
webkit.messageHandlers.callbackHandler.postMessage(data);
Natywna aplikacja wychwytuje wiadomość w delegacie o nazwie:
(void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
I wykonać odpowiednie działania
Oto odpowiedni kod:
AjaxHandler.js -//Every time an Ajax call is being invoked the listener will recognize it and will call the native app with the request details
$( document ).ajaxSend(function( event, request, settings ) {
callNativeApp (settings.data);
});
function callNativeApp (data) {
try {
webkit.messageHandlers.callbackHandler.postMessage(data);
}
catch(err) {
console.log('The native context does not exist yet');
}
}
Mój delegat ViewController to:
@interface BrowserViewController : UIViewController <UIWebViewDelegate, WKUIDelegate, WKNavigationDelegate, WKScriptMessageHandler, UIWebViewDelegate>
I w moim viewDidLoad()
, tworzę WKWebView:
WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc]init];
[self addUserScriptToUserContentController:configuration.userContentController];
appWebView = [[WKWebView alloc]initWithFrame:self.view.frame configuration:configuration];
appWebView.UIDelegate = self;
appWebView.navigationDelegate = self;
[appWebView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString: @"http://#############"]]];
Oto adduserscripttousercontentcontroller:
- (void) addUserScriptToUserContentController:(WKUserContentController *) userContentController{
NSString *jsHandler = [NSString stringWithContentsOfURL:[[NSBundle mainBundle]URLForResource:@"ajaxHandler" withExtension:@"js"] encoding:NSUTF8StringEncoding error:NULL];
WKUserScript *ajaxHandler = [[WKUserScript alloc]initWithSource:jsHandler injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:NO];
[userContentController addScriptMessageHandler:self name:@"callbackHandler"];
[userContentController addUserScript:ajaxHandler];
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-29 21:28:25
Jeśli masz kontrolę nad zawartością wewnątrz WkWebView
Możesz wysyłać wiadomości do swojej natywnej aplikacji za pomocą window.webkit.messageHandlers
za każdym razem, gdy złożysz żądanie ajax, które zostanie odebrane jako WKScriptMessage
które mogą być przetwarzane przez cokolwiek określiłeś jako swój WKScriptMessageHandler
. Wiadomości mogą zawierać dowolne informacje i będą automatycznie konwertowane na natywne obiekty / wartości w kodzie Objective-C lub Swift.
Jeśli nie masz kontroli nad treścią, nadal możesz to zrobić to poprzez wstrzyknięcie własnego JavaScript poprzez WKUserScript
aby śledzić żądania ajax i wysyłać wiadomości zwrotne za pomocą metody podanej powyżej.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-03-02 06:25:38
@ Benzi Heler odpowiedź jest świetna, ale używa jQuery, który wygląda na to, że nie działa już w WKWebView
, więc znalazłem rozwiązanie bez używania jQuery.
Oto implementacja ViewController, która pozwala być powiadamianym o każdym żądaniu AJAX jest zakończone w WKWebView
:
import UIKit
import WebKit
class WebViewController: UIViewController {
private var wkWebView: WKWebView!
private let handler = "handler"
override func viewDidLoad() {
super.viewDidLoad()
let config = WKWebViewConfiguration()
let userScript = WKUserScript(source: getScript(), injectionTime: .atDocumentStart, forMainFrameOnly: false)
config.userContentController.addUserScript(userScript)
config.userContentController.add(self, name: handler)
wkWebView = WKWebView(frame: view.bounds, configuration: config)
view.addSubview(wkWebView)
if let url = URL(string: "YOUR AJAX WEBSITE") {
wkWebView.load(URLRequest(url: url))
} else {
print("Wrong URL!")
}
}
private func getScript() -> String {
if let filepath = Bundle.main.path(forResource: "script", ofType: "js") {
do {
return try String(contentsOfFile: filepath)
} catch {
print(error)
}
} else {
print("script.js not found!")
}
return ""
}
}
extension WebViewController: WKScriptMessageHandler {
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
if let dict = message.body as? Dictionary<String, AnyObject>, let status = dict["status"] as? Int, let responseUrl = dict["responseURL"] as? String {
print(status)
print(responseUrl)
}
}
}
Dość standardowa implementacja. Istnieje WKWebView
tworzony programowo. Jest wstrzykiwany skrypt, który jest ładowany z pliku script.js
.
A najważniejszą częścią jest script.js
plik:
var open = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function() {
this.addEventListener("load", function() {
var message = {"status" : this.status, "responseURL" : this.responseURL}
webkit.messageHandlers.handler.postMessage(message);
});
open.apply(this, arguments);
};
userContentController
metoda delegate będzie wywoływana za każdym razem, gdy zostanie załadowane żądanie AJAX. Przechodzę tam status
i responseURL
, ponieważ tego potrzebowałem w moim przypadku, ale możecie też uzyskać więcej informacji na temat request. Oto lista wszystkich dostępnych właściwości i metod:
https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest
Moje rozwiązanie jest inspirowane tą odpowiedzią napisaną przez @ John Culviner: https://stackoverflow.com/a/27363569/3448282
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-21 07:03:44