【问题标题】:How can i monitor requests on WKWebview?我如何监控 WKWebview 上的请求?
【发布时间】:2015-04-30 06:14:15
【问题描述】:

如何监控 WKWebview 上的请求?

我尝试过使用 NSURLprotocol (canInitWithRequest),但它不会监控 ajax 请求 (XHR),只监控导航请求(文档请求)

【问题讨论】:

    标签: javascript ios monitor wkwebview nsurlprotocol


    【解决方案1】:

    如果您可以控制WkWebView 中的内容,则您可以在发出ajax 请求时使用window.webkit.messageHandlers 向您的本机应用程序发送消息,该请求将作为WKScriptMessage 接收,您可以处理任何您'已指定为您的WKScriptMessageHandler。消息可以包含您想要的任何信息,并且会在您的 Objective-C 或 Swift 代码中自动转换为本机对象/值。

    如果您无法控制内容,您仍然可以通过WKUserScript 注入您自己的 JavaScript 来跟踪 ajax 请求并使用上述方法发回消息。

    【讨论】:

    • 我无法控制 WKWebview 中的内容。我还能获得 ajax 请求吗?
    • @BenziHeler,您提到您无法控制 WKWebview 中的内容,但您说您已经按照贾斯汀迈克尔建议的方式解决了它……您能解释一下吗您可能无法控制 webview 内容吗?
    【解决方案2】:

    终于解决了

    由于我无法控制 Web 视图内容,因此我向 WKWebview 注入了一个包含 jQuery AJAX 请求侦听器的 java 脚本。

    当监听器捕获到一个请求时,它会在方法中向原生应用发送请求体:

    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 中是否已经支持 jquery 库?还是您也必须导入它?
    • 这个 ajaxHandler 不适合我。我不断收到错误提示未知变量 $。有什么想法吗?
    • @iOSAddicted 你可能没有在原始请求的响应中导入 jQuery($ 是一个 JQuery 变量)
    • @CharltonProvatas,鉴于 halil_g 的回答看起来不受 WKWebView 支持,需要在响应网页内容中导入。
    【解决方案3】:

    @Benzi Heler 的答案很棒,但它使用了 jQuery,这似乎不再适用于 WKWebView,所以我找到了不使用 jQuery 的解决方案。

    这里是 ViewController 实现,它让您在 WKWebView 中完成的每个 AJAX 请求都会收到通知:

    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。有从script.js 文件加载的注入脚本。

    最重要的部分是script.js文件:

    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 请求时被调用。我要经过statusresponseURL,因为这是我需要的,但您也可以获得有关请求的更多信息。以下是所有可用属性和方法的列表: https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest

    我的解决方案受到@John Culviner 写的这个答案的启发: https://stackoverflow.com/a/27363569/3448282

    【讨论】:

    • WKWebView加载后是否可以注入配置?
    • 否 - 您只能在其 init 方法中设置 WKWebView 的配置
    • 它不工作,它实际上与导航流程混乱。
    • @user3448282 我需要观察 Ajax 中的验证码变化。在 didLoad 我使用 "var c = document.createElement('canvas'); var ctx = c.getContext('2d'); const list = document.getElementsByTagName(\"img\"); ctx.drawImage(list [1], 100, 40); var value = c.toDataURL(); value.split(',')[1];"。我可以在 script.js 中执行此操作吗?如果现在将其添加到 script.js 中?
    • 它很棒。我可以捕获网络调用的 json
    【解决方案4】:

    您可以使用它来响应来自 WKWebView 的请求。它的工作原理类似于 UIWebView。

    - (void)webView:(WKWebView *)webView2 decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
        
        if (navigationAction.navigationType == WKNavigationTypeLinkActivated) {
         
            NSString *url = [navigationAction.request.URL absoluteString];
            
           // Handle URL request internally
    
        }
    
        decisionHandler(WKNavigationActionPolicyAllow); // Will continue processing request
    
        decisionHandler(WKNavigationActionPolicyCancel); // Cancels request
    }
    

    【讨论】:

      猜你喜欢
      • 2018-07-15
      • 2016-11-12
      • 1970-01-01
      • 1970-01-01
      • 2023-03-22
      • 1970-01-01
      • 2019-07-26
      • 1970-01-01
      • 2014-07-17
      相关资源
      最近更新 更多