我如何监控 WKWebview 上的请求?
我试过使用 NSURLprotocol (canInitWithRequest) 但它不会监控 ajax 请求 (XHR),只有导航请求(文档请求)
我如何监控 WKWebview 上的请求?
我试过使用 NSURLprotocol (canInitWithRequest) 但它不会监控 ajax 请求 (XHR),只有导航请求(文档请求)
最后我解决了
由于我无法控制 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];
}
@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
编程方式创建的。有从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 请求时都会调用委托方法。我经过那里status
,responseURL
因为这是我需要的,但您也可以获得有关请求的更多信息。以下是所有可用属性和方法的列表:
https ://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest
我的解决方案受到@John Culviner 写的这个答案的启发: https ://stackoverflow.com/a/27363569/3448282
如果您可以控制其中的内容,则WkWebView
可以在发出 ajax 请求时使用向您的本机应用程序发送消息window.webkit.messageHandlers
,该请求将作为WKScriptMessage
可以被您指定为WKScriptMessageHandler
. 消息可以包含您想要的任何信息,并且会在您的 Objective-C 或 Swift 代码中自动转换为本机对象/值。
如果您无法控制内容,您仍然可以通过注入您自己的 JavaScriptWKUserScript
来跟踪 ajax 请求并使用上述方法发回消息。
您可以使用它来响应来自 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
}