【发布时间】:2015-04-30 06:14:15
【问题描述】:
如何监控 WKWebview 上的请求?
我尝试过使用 NSURLprotocol (canInitWithRequest),但它不会监控 ajax 请求 (XHR),只监控导航请求(文档请求)
【问题讨论】:
标签: javascript ios monitor wkwebview nsurlprotocol
如何监控 WKWebview 上的请求?
我尝试过使用 NSURLprotocol (canInitWithRequest),但它不会监控 ajax 请求 (XHR),只监控导航请求(文档请求)
【问题讨论】:
标签: javascript ios monitor wkwebview nsurlprotocol
如果您可以控制WkWebView 中的内容,则您可以在发出ajax 请求时使用window.webkit.messageHandlers 向您的本机应用程序发送消息,该请求将作为WKScriptMessage 接收,您可以处理任何您'已指定为您的WKScriptMessageHandler。消息可以包含您想要的任何信息,并且会在您的 Objective-C 或 Swift 代码中自动转换为本机对象/值。
如果您无法控制内容,您仍然可以通过WKUserScript 注入您自己的 JavaScript 来跟踪 ajax 请求并使用上述方法发回消息。
【讨论】:
终于解决了
由于我无法控制 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 实现,它让您在 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 请求时被调用。我要经过status 和responseURL,因为这是我需要的,但您也可以获得有关请求的更多信息。以下是所有可用属性和方法的列表:
https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest
我的解决方案受到@John Culviner 写的这个答案的启发: https://stackoverflow.com/a/27363569/3448282
【讨论】:
init 方法中设置 WKWebView 的配置
您可以使用它来响应来自 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
}
【讨论】: