Fritz Ebner
Fritz Ebner

Reputation: 21

offline application cache support in mac os x embedded webkit webview

I am writing OS X HTML5 app which has to function both online and offline. Offline application cache was prototyped based on this and works well in Safari. When i do a simple test using webview in Xcode, the manifest file seems never to be fetched by the webview. A simple way to test uses this minimal html file:

<html manifest="example.manifest"><head> <title>Test with
manifest</title> </head> <body> Test with manifest<br> <br>
</body></html>

the manifest file example.manifest contains:

CACHE MANIFEST
# ver 1
CACHE:

When i view this page in Safari, the page loads, and the manifest is read. If i quit safari, go offline, then start Safari and refresh this page, it loads from cache. the offline cache here seems to work fine.

when i repeat this with web view, in Xcode 7.3 Mac OS 10.11, using the following code (storyboard has a web view in a view controller inside of the window):

class ViewController: NSViewController {
@IBOutlet var webview: WebView!

let THEURL:String = "http://192.168.23.180/WithManifest/"

override func viewDidLoad() {
    super.viewDidLoad()
    let url = NSURL(string: THEURL)
    let request = NSURLRequest(URL: url!, cachePolicy:NSURLRequestCachePolicy.UseProtocolCachePolicy ,timeoutInterval: 10)
    webview.mainFrame.loadRequest(request)
   }
}

In the web view case, the page loads fine, but after quitting and restarting offline, the page fails to load. looking at the network traffic, it is clear that the manifest file is never requested from the client. I have tried all of the different cache policies without success. I have also tried creating my own shared URL cache as has been suggested elsewhere with no success.

    let cacheSizeMemory:Int = 4*1024*1024; // 4MB
    let cacheSizeDisk:Int = 32*1024*1024; // 32MB
    let sharedCache:NSURLCache = NSURLCache(memoryCapacity:cacheSizeMemory, diskCapacity:cacheSizeDisk, diskPath:"nsurlcache")
    NSURLCache.setSharedURLCache(sharedCache)

My questions:

1) does webkit webview in OS X support offline application cache as described in html5?

2) if yes, what has to be done to make it work?

My workaround is to implement a subclass of NSURLProtocol that implements custom caching and doing the loading logic (offline vs. online) in the app. I would much rather use the standard approach if at all possible.

Upvotes: 1

Views: 788

Answers (1)

Fritz Ebner
Fritz Ebner

Reputation: 21

I was able, with help from different places and people, to find an answer. There is an Objective-C webview preference called setOfflineWebApplicationCacheEnabled, which is for some reason not exposed in swift. To make it work, first make a bridging header file. Use Xcode to create a header file and put this into it:

#import <Foundation/Foundation.h>
#import <WebKit/WebKit.h>

@interface WebPreferences (WebPreferencesPrivate)
- (void)_setLocalStorageDatabasePath:(NSString *)path;
- (void) setLocalStorageEnabled: (BOOL) localStorageEnabled;
- (void) setOfflineWebApplicationCacheEnabled:(BOOL)offlineWebApplicationCacheEnabled;
- (void) setDatabasesEnabled:(BOOL)databasesEnabled;
@end

and save it in your project. Go to Build Settings->Swift Compiler - Code Generation and select 'Objective C Bridging Header'. double click on the right side and put in the relative path (based on the file system, not the project organization) to the header file. In my case it was testwebviewmanifest/Header.h, where testwebviewmanifest folder is at the same level as the .xcodeproj file.

Once that is done and you can build successfully (it may complain it can't find your header file if the path is wrong), put this line at a startup place where you have a handle to your webview. For me it was easy to put it in the ViewController.

    webview.preferences.setOfflineWebApplicationCacheEnabled(true)

Once that is done, the cache manifest will be downloaded, and application caching appears to work flawlessly. Extensive testing has not been done yet. I will update if any gotchas are found...

A demo project can be found here: https://github.com/graySquirrel/testwebviewmanifest

Upvotes: 1

Related Questions