Wkwebview and Nsurlprotocol Not Working

WKWebView and NSURLProtocol not working

Updated answer for iOS 11 and macOS 10.13

Since iOS 11 it is possible to declare an object that conforms to the WKURLSchemeHandler protocol and register it in the WKWebView configuration: -[WKWebViewConfiguration setURLSchemeHandler:forURLScheme:].

Old answer

WKWebView makes requests and renders content out-of-process, meaning your app does not hear the requests they make. If you are missing a functionality, now is the time to open a bug report and/or an enhancement request with Apple.

As of iOS 10.3 SDK, WKWebView is still unable to make use of custom NSURLProtocols using public APIs.


Enterprising developers have found an interesting method:
+[WKBrowsingContextController registerSchemeForCustomProtocol:]
It supposedly adds the provided scheme to a list of custom protocol handled schemes and should then work with NSURLProtocol.

NSURLProtocol isn't asked to load after YES response to canInitWithRequest

I was able to workaround this issue by cache-busting the UIWebView cache, while not busting the NSURLCache.

  1. Add a unique param to the query params of the original request. I chose 'key=000000' where the value is zero-led six digit random number.
  2. In the protocol, strip the key in canonicalRequestForRequest: and in initWithRequest:cachedResponse:client

My stripping code looks like this (there might be a cleaner way to strip the param, but this works):

+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request
{
NSURLRequest *canonicalRequest = request;
BOOL myProtocolRequest = [[NSURLProtocol propertyForKey:kMYProtocolRequest inRequest:request] boolValue];
if (myProtocolRequest)
{
NSMutableURLRequest *mutableRequest = [request mutableCopyWorkaround];
NSString *originalURLString = mutableRequest.URL.absoluteString;
NSString *regexString = [NSString stringWithFormat:@"(?:[?&])(key=[[:digit:]]{%d}&*)", kMYKeyLength];

NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:regexString options:0 error:0];
NSTextCheckingResult *result = [regex firstMatchInString:originalURLString options:0 range:NSMakeRange(0, originalURLString.length)];
if (result.numberOfRanges > 1)
{
NSRange keyRange = [result rangeAtIndex:1];
NSLog(@"Removing '%@' from request", [originalURLString substringWithRange:keyRange]);
NSString *replacementURLString = [originalURLString stringByReplacingCharactersInRange:keyRange withString:@""];
mutableRequest.URL = [NSURL URLWithString:replacementURLString];
canonicalRequest = mutableRequest;
}
}

return canonicalRequest;
}

My init code looks like this:

- (id)initWithRequest:(NSURLRequest *)request cachedResponse:(NSCachedURLResponse *)cachedResponse client:(id<NSURLProtocolClient>)client
{
self = [super initWithRequest:[MYURLProtocol canonicalRequestForRequest:request] cachedResponse:cachedResponse client:client];
return self;
}

I don't like that I have to do this, but I'm finally getting exactly the behavior I want. Hopefully it helps someone out there.

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,
    and document.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.

WKWebView and authentication

The solved it in beta 3 using the function didReceiveAuthenticationChallenge in WKNavigationDelegate. I've tried it and it works perfectly



Related Topics



Leave a reply



Submit