iOS 11: Force UIWebView to use cache (NSURLCache) when offline - caching

Since iOS 11, when the device is offline, network requests are most often fail quickly with a “The Internet connection appears to be offline.” error message (code -1009). Previously – as was the case for iOS version < 11 – request would first try and go through (parts of) the URL loading system.
To serve content to UIWebViews while offline, I rely on a custom subclass of NSURLCache, that returns cached data first, and requests the actual resource from the server afterwards in the background (only if needed/updated), to store for the next request.
I would like to force my app – particular my UIWebViews I’d like to work offline – to still go through the URL loading system, so that my custom NSURLCache is asked for a cached response every time (as was the case before iOS 11). Is this possible?
More background
While the request attempt fails immediately on iOS 11 when the device doesn’t have an internet connection, the OS also introduced the waitsForConnectivity-flag to NSURLSession. This does exactly what I want. However, this only works for my simpler requests that load a single file and that I was able to easily port from a NSURLConnection-request to a NSURLSession-request.
UIWebView still uses NSURLConnection, and so I can’t use NSURLSession and waitsForConnectivity. But: is there another way to force going through the URL loading system and hit my custom NSURLCache implementation?
In my web views, I simply request pages like this:
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:#“some/url.html" relativeToURL:[NSURL URLWithString:#“https://www.example.com/"]] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:30];
[self.webView loadRequest:request];
So, the above used to work and still works for iOS versions < 11. No luck with iOS 11.
I tried several values for the cachePolicy parameter, including NSURLRequestReturnCacheDataDontLoad. Still no luck.
And it’s not as simple as loading/requesting a single HTML file. The pages have lots of resources: CSS files, JS, images etc. And this was all transparently cached by my custom NSURLCache. Sadly no more with iOS 11.
(Now: I’m using a custom subclass of NSURLCache in the first place, because I couldn’t rely on the standard NSURLCache implementation, no matter what configuration and cachePolicy settings. If anyone has a suggestion for a different solution (without a custom NSURLCache) to my problem, I’m definitely listening.)

Related

How to change URL at runtime

We are trying to use Cobalt (20.stable) browser as the browser of our web SPA application.
My requirement is to be able to change URL at runtime, what I was able to find in the code:
Is:
starboard::shared::starboard::Application::Link(const char* link_data)
which ends up sending:
kSbEventTypeLink
Unfortunately this is not working, as code is ignoring the call; the handling reaches the point:
// TODO: Remove this when terminal application states are properly handled.
if (deep_link_event->IsH5vccLink()) {
browser_module_->Navigate(GURL(deep_link_event->link()));
}
In my case I m trying to change the URL to let say https://www.example.com.
There should be a way to do that as when navigating we can always have a link that will cause the browser to go to some URL?
Porting layer is not supposed to control navigation directly. Instead, your Starboard implementation may send a deep link event which could be intercepted by a web app which will perform a navigation. See h5vcc_runtime.idl for Web API.
That said, if you are building an SPA, why do you even need to change a URL? Initial URL of a web app is controlled by --url command line switch.
When you say runtime are you looking to change the initial URL when the app is first launched? If so, you could just use the --url parameter.
So you could do the following:
cobalt --url="https://www.example.com"
I did a patch to allow changing the URL.
I just need to call starboard::shared::starboard::Application::Link("https://www.example.com").
Inside this call a DeepLinkEvent is posted.
Patch : https://gofile.io/?c=9GvNHX
Cobalt does not navigate for you. The JavaScript receives the deeplink with the function it sets on h5vcc.runtime.onDeepLink and then does whatever it wants with that. As a SPA, it will parse the URL and load new content from its server in its own internal data format (e.g. protocol buffers, JSON, etc.) which it uses to update its own DOM to show new content.
Navigating is not the point of a SPA since that makes it not be a single page application. However, there may be cases such as a loader app that will want to make some initial decisions then load the actual SPA. That loader app would have to have the appropriate CSP rules in place, then set window.location to the URL of the page to navigate to.
Note: The code you found in Application::OnDeepLinkEvent() is a remnant that previously supported the H5vccURLHandler, which was removed in Cobalt 20. It's not meant to navigate to arbitrary deeplinks.

wxWebView Page Load Fails with no Internet Connection

I am writing a windows application that uses a wxWebView (Trident) to display pages served from an internal server that binds to the localhost interface on an ephemeral port. I have run into a problem where, if the host computer does not have any active external IP interfaces enabled (such as a laptop in airplane mode), the wxWebView instance refuses to load the page and sends a page load failure event with a string of "INET_E_DOWNLOAD_FAILURE". When this happens, I can make an external browser (including internet explorer) load the page from my web server so I know that the loopback interface(s) are working. Is there any way to configure the wxWebView instance so that it WILL load the page?
When I try this in the webview sample application, i can see the following in the log window:
13:33:33: Navigation request to 'res://ieframe.dll/navcancl.htm#http://www.wxwidgets.org/' (target='')
13:33:33: Title changed; title='http://www.wxwidgets.org/'
13:33:33: Navigation complete; url='http://www.wxwidgets.org/'
13:33:33: Title changed; title='Navigation Canceled'
13:33:33: Document loaded; url='http://www.wxwidgets.org/'
13:34:12: Navigation request to 'http://localhost:57588/stations.html' (target='')
13:34:12: Error; url='http://localhost:57588/stations.html', error='wxWEBVIEW_NAV_ERR_CONNECTION (INET_E_DOWNLOAD_FAILURE)'
After searching in vain for methods that could be used to configure the iWebBrowser2 instance, I have decided to dump the Trident engine altogether and managed to get wxWebViewChromium to work. If anyone faces something similar to this, they need to be aware that the current version of wxWebViewChromium do not appear to work with the latest version of CEF.
Note: not an answer, but a comment/question to #Jon Trauntvein, because I don't have enough reputation to comment
I too decided to drop the wxWebView IE engine because it does not render Google Maps polygons.
discussed here, if you want to know
https://forums.wxwidgets.org/viewtopic.php?f=1&t=43186
so, I am trying to build a current CEF build
https://bitbucket.org/chromiumembedded/cef
into wxWebViewChromium
https://github.com/sjlamerton/wxWebViewChromium
but this project is 4 years old and the CEF API changed.
Would you care to post here the changes you made to wxWebViewChromium ?
thanks

Webview not showing loaded content

I'm trying to experiment with web view by using swift. I created a simple Xcode project, placed a web view within my application interface and connected it to my app delegate.swift with an outlet called "myview". By executing
self.myview.mainFrameURL = "http://www.google.com"
from within applicationDidFinishLaunching(), I would expect the Google's homePage to be loaded. However, this doesn't happen: the web view does not show anything. What am I doing wrong?
1) Add the NSAppTransportSecurity in your plist https://ste.vn/2015/06/10/configuring-app-transport-security-ios-9-osx-10-11/
2) check in your project settings that "Sandbox" is enabled and that internet connections are allowed
You will have to call loadRequest() to make it load a page.
So basically:
[self.myWebView loadRequest: [NSURLRequest requestWithURL:
[NSURL URLWithString: #"http://www.google.com"]]]
After digging into the console logs, I found the solution to my problem. I'm not sure if I can share it though, since I'm using a beta OS X version and this restriction could have been introduced to improve apps' security, even if from what I can see it can be disabled.

Parse.com Mixed Content Error

I'm creating a web application using parse and have found that in order for a user to authenticate I need to make all requests using HTTPS. I'm able to switch this over and get it to work correctly, but when I do I get all kinds of mixed content errors because I'm retrieving PFFile objects which only return a non-secure URL.
This wouldn't even be a huge concern with Chrome or Safari but of course IE needs to present a message to the user and block all this content. Are there any potential work arounds? Why can't parse just put a setting in the app to enable files to be served from a secure url? This seems completely ridiculous. How do people get around this? Are you completely avoiding the use of PFFile?
Replace http:// with https://s3.amazonaws.com/.
So if you start with this:
http://files.parsetfss.com/b05e3211-bf8b-.../tfss-fa825f28-e541-...-jpg
The final url will look something like this:
https://s3.amazonaws.com/files.parsetfss.com/b05e3211-bf8b-.../tfss-fa825f28-e541-...-jpg

NSURLConnection methods no more available in IOS5

I was looking at the NSURLConnection class which could be used to establish a sync or async connection to an URL and then retrieve its data... a lot of changes have been made to this class with IOS 5 and I've seen they introduced some formal protocols related to authentication or download, but I don't see, for example, if the connection:didReceiveResponse: message (that was previously sent to the delegate and that it is no more available) is still available in some protocols.. How do you implement an async connection and retrieve, for example, HTTP headers as soon as the Response is received? I'm sure there is a way better than using NSURLConnection along with the connection:didReceiveResponse: message.. methods like stringWithContentsOfURL do always load content synchronously? What do you use to implement async downloads in your apps avoiding deprecated methods and reacting to events such as _http response received_m etc ? Do you launch synchronous downloads in background tasks, if possible?
NSURLConnectionDelegate has become a formal protocol (it was an informal protocol in previous versions). In this protocol, the following (non-deprecated) methods are declared:
connection:didFailWithError:
connectionShouldUseCredentialStorage:
connection:willSendRequestForAuthenticationChallenge:
Furthermore, there are two subprotocols that conform to NSURLConnectionDelegate:
NSURLConnectionDataDelegate is used for delegates that load data to memory, and declares the following methods, some of which I’m sure you’ll find familiar:
connection:willSendRequest:redirectResponse:
connection:didReceiveResponse:
connection:didReceiveData:
connection:needNewBodyStream:
connection:didSendBodyData:totalBytesWritten:totalBytesExpectedToWrite:
connection:willCacheResponse:
connectionDidFinishLoading:
NSURLConnectionDownloadDelegate is used for delegates that store data directly to a disk file, and declares the following methods:
connection:didWriteData:totalBytesWritten:expectedTotalBytes:
connectionDidResumeDownloading:totalBytesWritten:expectedTotalBytes:
connectionDidFinishDownloading:destinationURL:
As you can see, you can still use your previous delegates, possibly with some minor modifications.
For more information, see the iOS 4.3 to iOS 5.0 API Differences document and NSURLConnection.h in your local Xcode installation. When a new SDK version is released, it’s not uncommon for the documentation inside the header files to be more reliable than the documentation available on the developer library. It takes a while for the latter to be up-to-date.
I just encountered this same issue. Looks like sending an asynchronous request is more simplified with blocks and NSOperationQueue.
+ (void)sendAsynchronousRequest:(NSURLRequest *)request queue:(NSOperationQueue *)queue completionHandler:(void (^)(NSURLResponse*, NSData*, NSError*))handler
This means that the delegate is now only used for authentication and failure issues.
NO!
They are NOT limited to use for authentication and failure issues if you look carefully through the Apple's library.
Since introducing +(void)sendAsynchronousRequest:queue:completionHandler: to NSConnection class object, Many things which can perform as many NSConnectionDelegate method as before can now be used in formal protocols called "NSConnectionDataDelegate" & NSConnectionDownloadDelegate, opening a new room to add more feature to NSURLConnection methods. (from iOS5 on)
So I think it is an improvement, not limiting their use.
Even I havent found the documentation on the Apple website
https://developer.apple.com/library/ios/#documentation/Cocoa/Reference/Foundation/Classes/NSURLConnection_Class/Reference/Reference.html
https://developer.apple.com/library/ios/#documentation/Foundation/Reference/NSURLConnectionDelegate_Protocol/Reference/Reference.html
It should have been available over here

Resources