Как я могу отслеживать запросы на 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