WKWebView using URLRequest HTTPBody is nil in WKNavigationDelegate (decidePolicyFor)

We are migrating from deprecated API UIWebView to WKWebView.

In WKWebView we loading one login page. After the success, we wanna try to catch the body and try to call other internal API.

But we got nil in the below delegate method.


func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: ((WKNavigationActionPolicy) -> Void)) {

print(navigationAction.request.httpBody) //nil

}


However, UIWebView getting a proper HTTP body.

The fact that you don’t get the HTTP body is a known, and oft-reported, limitation in the current

WKWebView
implementation (r. 35087855). This issue is also being tracked as a WebKit open source bug.

If you read that through, you’ll see that it’s easy to fix in simple cases, like posting an HTML form, but problems crop up when you try to fix it in general, like uploading a huge file. That’s why the fix has not yet made it into mainstream OS releases.

What do you need to do with the body? One common request here is to catch the items being posted to the server as part of a form POST. If so, you can do that as follows:

  1. Catch the POST using the navigation delegate.

  2. Don’t immediately call the decision handler, but instead execute a JavaScript to get the form’s content.

  3. Once that JavaScript is done, call the decision handler.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Hi Eskimo,


Thanks for replying.


We have some questions.

1. Currently, we use UIWebview for a third party login. Can we continue with this? However, Apple says UIWebView is deprecated over WKWebView.

2. By which date this bug https://bugs.webkit.org/show_bug.cgi?id=179077 will get fixed? Meanwhile, can we continue to use UIWebView?

Looking forward to your reply.

1. Currently, we use

UIWebView
for a third party login. Can we continue with this?

I recommend that you work hard to move away from

UIWebView
.

By which date this bug … will get fixed? Meanwhile, can we continue to use

UIWebView
?

No. As I mentioned in my previous post, fixing that issue is not easy. If you have an alternative path, you should take it.

Specifically, I recommend that you look at the approach I suggested in my previous response. If that doesn’t work for you, please post some details about what you’re doing and where things go wrong.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Apple forcing to use of WKWEbView with this issue. because UIWebview is deprecated.

UIWebView
was not deprecated lightly. It’s one of the more commonly used APIs on our platform. For insight into one of the most important reasons for its deprecation, see WWDC 2018 Session 207 Strategies for Securing Web Content.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Hello eskimo,


Thanks for detailed explanation of the workaround for the issue.


In my company, we've a similar case while moving from UIWebView to WKWebView.


We're receiving online payments and there're multiple redirections with credit card input forms. With UIWebViewDelegate's we could get request data while redirection, as you already know the issue, we can't achieve same data with WKWebView navigation delegate's decidePolicy methods.


I know, there's an option where we can register WKScriptMessageHandlers in application and trigger them from web site by posting messages like:


window.webkit.messageHandlers.jsHandler.postMessage("trigger from JS");


But, we want to keep this implementation as the last choice, as there're various integrated payment systems that communicates with each other and it would be more time consuming both for development and testing with all integrated systems.


Considering we cannot rely on form id's, is there any alternative, so that we can achieve request's httpBody from WKWebView redirections?


Looking forward for your reply,

Best Regards

We found a solution that will not require drastic changes or javascript. Basically you need to make use of WKURLSchemeHandler protocol:


1. Setup webview


let config = WKWebViewConfiguration()
config.setURLSchemeHandler(self, forURLScheme: "my-custom-scheme")
let wkWebView = WKWebView(frame: .zero, configuration: config)


2. Implement WKURLSchemeHandler protocol


func webView(_ webView: WKWebView, start urlSchemeTask: WKURLSchemeTask) {
  if let url = urlSchemeTask.request.url, url.scheme == "my-custom-scheme" {
  self.handleTermURLCallback(urlSchemeTask.request)
  }
}


By using this you'll find that your request httpBody in the callback is not null and you can continue the same way you used to with UIWebView.


It took a lot of effort to find this but it is working for us and we didn't need to change very much. Hope it helps you guys.

Hello, kemalenver

Thanks for your solution It's very Awsome!

We are now facing same issue what diff is we need to compatible iOS 10 also.

setURLSchemeHandler is only available for iOS11.

Is there any solution for compatible lower version which below iOS 11?

Looking forward to your reply.

Hello.

this workaround works for me for wkwebkit ios 10
Code Block
let params = @"param1=1&param2=2";
self.request.HTTPBody = [params dataUsingEncoding:NSUTF8StringEncoding];
let dataTask = [NSURLSession.sharedSession
dataTaskWithRequest:self.request
completionHandler:^(NSData *_Nullable data, NSURLResponse *_Nullable response, NSError *_Nullable error) {
if (data) {
[self.webView loadData:data MIMEType:@"text/html" characterEncodingName:@"UTF-8" baseURL:url.baseURL];
}
}];
[dataTask resume];


instead of this

Code Block
[self.webView loadRequest:self.request];


Hope it helps.

It is a shame that Apple keeps making simple things difficult for developers.

It'll never be fixed? I am facing a different error when I use the method where I fetch the data with URLSession then displaying it. It is so much easier if I could just pass the httpBody.

WKWebView using URLRequest HTTPBody is nil in WKNavigationDelegate (decidePolicyFor)
 
 
Q