Как я могу отслеживать запросы на WKWebview?
Как я могу отслеживать запросы на WKWebview?
Я пробовал использовать NSURLprotocol (canInitWithRequest), но он не будет отслеживать запросы ajax (XHR), только запросы навигации(запросы документов)
3 ответов
наконец-то я решил его
поскольку у меня нет контроля над содержимым веб-представления, я ввел в WKWebview Java-скрипт, который включает прослушиватель запросов jQuery AJAX.
когда слушатель ловит запрос, он отправляет приложение в тексте запроса в методе:
webkit.messageHandlers.callbackHandler.postMessage(data);
родное приложение ловит сообщение в делегате с именем:
(void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
и выполните соответствующие действия
здесь уместно код:
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');
}
}
мой делегат ViewController:
@interface BrowserViewController : UIViewController <UIWebViewDelegate, WKUIDelegate, WKNavigationDelegate, WKScriptMessageHandler, UIWebViewDelegate>
и в моем viewDidLoad()
, Я создаю 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://#############"]]];
вот 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];
}
если у вас есть контроль над содержимым внутри WkWebView
вы можете отправлять сообщения в приложение, используя window.webkit.messageHandlers
всякий раз, когда вы делаете запрос ajax, который будет получен как WKScriptMessage
это может быть обработано тем, что вы обозначили как ваш WKScriptMessageHandler
. Сообщения могут содержать любую информацию, которую вы хотите, и будут автоматически преобразованы в собственные объекты/значения в вашем коде Objective-C или Swift.
если у вас нет контроля над содержание вы все еще можете сделать это, введя свой собственный JavaScript через WKUserScript
для отслеживания запросов ajax и отправки обратных сообщений с помощью метода, указанного выше.
@Benzi Heler ответ отличный, но он использует jQuery, который, похоже, не работает в WKWebView
больше, поэтому я нашел решение без использования jQuery.
вот реализация ViewController, которая позволяет получать уведомления о каждом запросе AJAX завершается в 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)
}
}
}
довольно стандартная реализация. Есть WKWebView
создается программно. Есть инжектированный скрипт, который загружается из .
и самое главное часть :
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
метод делегата будет вызываться каждый раз, когда загружается запрос AJAX. Я проезжаю мимо!--8--> и responseURL
, потому что это было то, что мне нужно в моем случае, но вы также можете получить больше информаций о желанию. Вот список всех доступных свойств и методов:
https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest
мое решение вдохновлено этим ответом, написанным @John Culviner: https://stackoverflow.com/a/27363569/3448282