How can i monitor requests on WKWebview?
Finally I solved it
Since I don't have control over the web view content, I injected to the WKWebview a java script that include a jQuery AJAX request listener.
When the listener catches a request it sends the native app the request body in the method:
webkit.messageHandlers.callbackHandler.postMessage(data);
The native app catches the message in a delegate called:
(void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
and perform the corresponding actions
here is the relevant code:
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');
}
}
My ViewController delegate are:
@interface BrowserViewController : UIViewController <UIWebViewDelegate, WKUIDelegate, WKNavigationDelegate, WKScriptMessageHandler, UIWebViewDelegate>
And in my viewDidLoad()
, I'm creating a 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://#############"]]];
Here is the 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];
}
How to monitor http requests from WKWebView?
Ok, I found a way.
You can create a new class (let's call it MyURLProtocol
) which has NSURLProtocol as subclass. Then add this function to MyURLProtocol
:
+ (BOOL)canInitWithRequest:(NSURLRequest *)request {
NSLog(@"URL = %@", request.URL.absoluteString);
return NO;
}
This function will be called each time your webview makes a request. And then you need to register this protocol with the loading system. In your Appdelegate.m
file include your class and add/replace didFinishLaunchingWithOptions
function with this:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[NSURLProtocol registerClass:[MyURLProtocol class]];
return YES;
}
All set. Now you can edit canInitWithRequest
function and do what you want with the request.
How to intercept all http(s) requests on ios WKWebView?
Take a look at this github repository called as WKWebViewWithURLProtocol Casolorz. This library enables you to use NSURLProtocol to intercept your network requests using method swizzling.
Intercept request with WKWebView
I see that after 5 years this question still generates curiosity, so I describe how I solved it and about some main problems I faced up.
As many who answered here, I have implemented WKURLSchemeHandler
and used new schemes.
First of all the URL that wkwebview launches must not be HTTP (or HTTPS) but one of yours new schemes.
Example
mynewscheme://your-server-application.com
In you WKWebViewConfiguration
conf, I set the handler:
[conf setURLSchemeHandler:[CustomSchemeHandler new] forURLScheme:@"mynewscheme"];
[conf setURLSchemeHandler:[CustomSchemeHandler new] forURLScheme:@"mynewschemesecure"];
In CustomSchemeHandler
I have implemented webView:startURLSchemeTask:
and webView:stopURLSchemeTask:
.
In my case I check if the request is for a file that I just saved locally, otherwise I change actual protocol ("mynewscheme or "mynewschemesecure") with http (or https) and I make request by myself.
At this point I solved the "interception problem".
In this new way we have the webview "location" (location.href
via javascript) with my new scheme and with it new problems started.
First problem is that my applications work mainly with javascript,
anddocument.cookie
has stopped working. I'm using Cordova
framework, so I've develeped a plugin to set and get cookie to
replace document.cookie (I had to do this, because, obviously, I
have also http header set-cookie).Second problem is that I've got a lot of "cross-origin" problems, then
I changed all my urls in relative url (or with new schemes)Third problem is that browser automatically handle server port 80
and 443, omitting them, but has now stopped (maybe because of "not
http location"). In my server code I had to handle this.
Writing down these few rows I admit that it seems to was an easy problem to solve, but I ensure that find out a workaround, how to solve it and integrate with the infinite amount of code has been hard. Every step towards the solution corresponded to a new problem.
How to monitor WKWebView page load progress in Swift?
Swift 4.0
@IBOutlet weak var webView: WKWebView!
@IBOutlet weak var progressView: UIProgressView!
override func viewDidLoad() {
super.viewDidLoad()
// load website or HTML page
self.webView.load(NSURLRequest(url: URL(string: "https://www.apple.com")!) as URLRequest);
//add observer to get estimated progress value
self.webView.addObserver(self, forKeyPath: "estimatedProgress", options: .new, context: nil);
}
// Observe value
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if keyPath == "estimatedProgress" {
print(self.webView.estimatedProgress);
self.progressView.progress = Float(self.webView.estimatedProgress);
}
}
WKWebView function for detecting if the URL has changed
What do you mean they don't always seem to fire? What kind of elements? They have to in order for the WkWebView to work.
Your first indication that the URL is trying to change is in: decidePolicyForNavigationAction
- (void) webView: (WKWebView *) webView decidePolicyForNavigationAction: (WKNavigationAction *) navigationAction decisionHandler: (void (^)(WKNavigationActionPolicy)) decisionHandler {
NSLog(@"%s", __PRETTY_FUNCTION__);
decisionHandler(WKNavigationActionPolicyAllow); //Always allow
NSURL *u1 = webView.URL;
NSURL *u2 = navigationAction.request.URL; //If changing URLs this one will be different
}
By the time you get to: didStartProvisionalNavigation It has changed.
- (void) webView: (WKWebView *) webView didStartProvisionalNavigation: (WKNavigation *) navigation {
NSLog(@"%s", __PRETTY_FUNCTION__);
NSURL *u1 = webView.URL; //By this time it's changed
}
All you'd have to do is implement these delegate methods (in Swift) and do what you want when you see it change.
Related Topics
How to Detect State of CSS Transition via Js and Skip It
Jquery Scroll Show Hidden Content
Write Custom Text on Image Canvas with Fabric.Js and HTML5
How to Use Jquery to Detect If a File Input Has a File Selected
CSS :Hover on Mobile or Other Device as Toggle
Absolute Positioned Floating Header Jitters in Safari
Saving Dropdown Menu Selection in a Cookie
How to Get the Exact Rgba Value Set Through CSS via JavaScript
Using Jquery How to Show and Hide Different Div's Onclick Event
Making Links Active in JavaScript
Run JavaScript Code in Webview
Send a Notification from JavaScript in Uiwebview to Objectivec
Disable Select Option in iOS Safari
How to Disable Smooth Scrolling in Ie11
Firebase Logout User All Sessions
Trigger a Click on a Different Element When Clicking an Other Div