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.
- 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.
- In the protocol, strip the key in
canonicalRequestForRequest:
and ininitWithRequest: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.
NSURLProtocol - startLoading not invoked
I had the same issue. In my case, I was adding an iframe to the page dynamically using JavaScript and loading my custom protocol content in that. In iOS 9.1 the WebView
refuses to load the iframe content when the main document is accessed over https, but it works fine over http. This looks like a new security control, to avoid loading insecure resources over a secure session.
The fix I went with was to change my scheme to use https
. For example, use https://imsweb/...
instead of imsweb://
. It's a bit of a hack but the best solution I could find.
Something like:
+ (BOOL)canInitWithRequest:(NSURLRequest *)request
{
if ([request.URL.scheme isEqualToString:@"https"] &&
[request.URL.host isEqualToString:@"imsweb"]) {
NSLog(@"%@", @"YES");
return YES;
}
return NO;
}
and of course you need to reconstruct the correct URL in startLoading
.
NSURLProtocol canInitWithRequest: called multiple times
I'm not expert, but AFAIK this is normal behavior. [NSURLPRotocol canInitWithRequest:] may be called multiple times for the same request. If you want to be notified just once per request, you should catch it in -startLoading method. I found this tutorial helpful to construct simple NSURLProtocol subclass which will do just that: http://www.raywenderlich.com/59982/nsurlprotocol-tutorial
iOS: passing custom NSURL to NSURLProtocol
If there's some way to get your original NSURL
used as mainDocumentURL
that would be ideal. If there's no way to prevent it being copied, I thought of the following hack as an alternative:
Before the creation of each UIWebView
, set the user agent string to a unique value. Supposedly this change only affects UIWebView
objects that are created subsequently, so each view will end up with its own distinctive user agent string.
In the NSURLProtocol
implementation, you can check the user agent string to identify the associated UIWebView
and pass it through to the real protocol handler using the actual user agent string (so the server will see nothing different).
All this depends on the views really ending up with different UA strings. Let me know if you manage to get it to work!
Should a custom NSURLProtocol follow redirects itself, or let its client worry about that?
To answer this question, I simply removed the code in my URL protocol implementation that follows the link given in the redirect response. It should be pretty obvious if the connection client follows creates a new connection to load the new URL. As it turns out, nothing happened -- the client never creates a new connection, and the redirect isn't followed. From this I have to conclude that the URL protocol itself should attempt to load URL given in the redirect response.
Related Topics
How to Get Index of Xcuielement in Xcuielementquery
Error | [Ios] File Patterns: the 'Source_Files' Pattern Did Not Match Any File
Sync Video in Avplayerlayer and Avplayerviewcontroller
Bootstrap Columns with Flexbox Are Not Taking Proper Width on iOS and Safari
Firebase Cloud Messaging Cannot Parse Topic Name
Import Framework for Whole Project at One Place in Swift
How to Print Out(Nslog) The Properties of a Custom Object Added to a Nsmutablearray
Uilabel Word Wrap Feature Leaving Space Even When Sufficient Space Available for The Word
How to Install Self-Signed Certificates in iOS 11
Xcode 8.3 Swift Version Error (Swift_Version) in Objective C Project
Uialertview's Textfield Does Not Show Keyboard in iOS8
How to Queue Multiple Accessibility Notifications for Voiceover
How to Create a Popup Menu in iOS
Load Custom Error HTMLstring When Wkwebview Loadrequest Fails
Invalid Update: Invalid Number of Sections in Uitableview