原文链接:http://alex.tapmania.org/2010/11/html5-cache-android-webview.html
HTML5 Cache, Android WebView
So last post was about HTML5 and WebViews but it didn’t cover offline usage and especially caching.
HTML5 is cool. It can work offline once cached by the browser. The main mechanism for offline HTML5 is the so called Manifest. Basically it’s a file which lists entries (js files, pictures, css, etc.) to be cached by the browser.
To enable cache in Android’s WebView we must do at least the following:
-
webView. setWebChromeClient ( new WebChromeClient ( ) {
-
@Override
-
public void onReachedMaxAppCacheSize ( long spaceNeeded, long totalUsedQuota,
-
WebStorage. QuotaUpdater quotaUpdater )
-
{
-
quotaUpdater. updateQuota (spaceNeeded * 2 ) ;
-
}
-
} ) ;
-
-
webView. getSettings ( ). setDomStorageEnabled ( true ) ;
-
-
// Set cache size to 8 mb by default. should be more than enough
-
webView. getSettings ( ). setAppCacheMaxSize ( 1024 * 1024 * 8 ) ;
-
-
// This next one is crazy. It's the DEFAULT location for your app's cache
-
// But it didn't work for me without this line.
-
// UPDATE: no hardcoded path. Thanks to Kevin Hawkins
-
String appCachePath = getApplicationContext ( ). getCacheDir ( ). getAbsolutePath ( ) ;
-
webView. getSettings ( ). setAppCachePath (appCachePath ) ;
-
webView. getSettings ( ). setAllowFileAccess ( true ) ;
-
webView. getSettings ( ). setAppCacheEnabled ( true ) ;
This will work. Well, this will make your WebView support caching.. doesn’t mean it will actually work.
You can tune cache policies using the following code, even though it’s not required to make it work:
-
webView. getSettings ( ). setCacheMode (WebSettings. LOAD_DEFAULT ) ;
Now when all the cache is setup we would like to see our HTML5 site working in pure offline mode.. but we don’t!
Why? well.. if it’s not working for you it probably means that the site you load up with the following call is actually redirecting you somewhere else:
-
webView. loadUrl ( "http://myHTML5app.com/app/" ) ;
If /app/ is resolving to a redirect – you are in trouble, sir.
The Cache mechanism will cache the actual RESULT of the redirect and sure it will map it to the url you are being REDIRECTED to, not the one you originally called. So once you are offline – the cache has no clue about the /app/ url and thus you are simply given the default android “can’t open page” replacement.
There are at least two ways to solve this issue..
- Get rid of the redirect on the server
- Re-redirect on android side
The first option is bad because you typically don’t want to mess with the working HTML5 site which is working on pure Browsers (iPhone, desktop, etc.).
To implement the second option I used the following code in the WebViewClient implementation:-
@Override
-
public void onReceivedError (WebView view, int errorCode,
-
String description, String failingUrl )
-
{
-
// The magic redirect
-
if ( "http://HTML5app.com/app/". equals (failingUrl ) ) {
-
// main.html is the place we are redirected to by the server if we are online
-
mWebView. loadUrl ( "http://HTML5app.com/app/main.html" ) ;
-
return ;
-
}
-
else if ( "http://HTML5app.com/app/main.html". equals (failingUrl ) ) {
-
// The cache failed – We don't have an offline version to show
-
-
// This code removes the ugly android's "can't open page"
-
// and simply shows a dialog stating we have no network
-
view. loadData ( "", "text/html", "UTF-8" ) ;
-
showDialog (DIALOG_NONETWORK ) ;
-
}
-
}
Good luck!
-
Posted on December 25th, 2010 at 1:58 pm
Great blog it’s not often that I comment but I felt you deserve it.
Posted on February 28th, 2011 at 10:26 am
Thanks a bunch, this helped me out =)
Posted on June 24th, 2011 at 10:58 am
Really awesome
Posted on July 10th, 2011 at 7:53 pm
Hi,
Great article But even by following it, I can’t manage to enable the HTML 5 manifest in the WebView.
The default Android browser notices the manifest file when I’m offline, but a WebView doesn’t and directly shows the “no internet connection” message.
Do you have any idea why? Thanks
Posted on July 10th, 2011 at 8:59 pm
Hi Leimi,
Alas, I don’t remember doing anything special to get the manifest working.. I believe that it should just work if your html5 application works on the stock browser. The only difference might be your android being 2.2 or 2.3 against 2.1 used for this article.. maybe they changed something in newer versions of android.
Hope you can find a solution soon. When you do – let me know
Cheers,
Alex
Posted on July 10th, 2011 at 9:11 pm
Hmm, that’s weird, the code is done with the Android 2.1 SDK. Well, I’ll try harder and come back here if I find a solution :p
Posted on August 5th, 2011 at 2:57 pm
It’s a great blog Alex… Thnx
Posted on September 22nd, 2011 at 2:26 pm
I faced this problem http://code.google.com/p/android/issues/detail?id=7939 on HTC Desire Api 2.2 since I used
webView.getSettings().setAppCachePath("/data/data/com.your.package.appname/cache");
as described in the article. Changing this to
webView.getSettings().setAppCachePath("/data/data/[packagename]/cache");
According to packagename in manifest
This resolved the issue
Posted on October 14th, 2011 at 7:19 am
Thanks..
but in my side, eveything works well except when broswer get new version of cache, always fire ‘Error’ event of appCache and should be fire ‘UpdateReady’ event. I can’t find out the reason. Anybody Help me?
I am really green in android developing field.
Posted on October 14th, 2011 at 9:41 am
Any help is greatly appreciated.
Posted on January 30th, 2012 at 11:03 am
Tack random crap!
Posted on February 15th, 2012 at 6:45 am
Thanks!!!!!!
very very helpful~!!
Posted on February 16th, 2012 at 12:04 pm
Instead to hardcode the cache dir it’s suggested to use getCacheDir() from the Context class (resp. getExternalCacheDir()).
Posted on February 27th, 2012 at 2:50 am
This has been a tremendous help, so thank you!
A couple of things. First, since I abhor literal paths coded into applications, I had to find another way to get the app cache path. I’d recommend this update:
String appCachePath = getApplicationContext().getCacheDir().getAbsolutePath();
webView.getSettings().setAppCachePath(appCachePath);
Second, the WebChromeClient updates aren’t strictly necessary to make caching work. Of course, if you run into situations where your cache *does* get maxed out, making the WebChromeClient additions is a more robust way to handle that situation. But I was able to get by without it.
Thanks again!
Posted on February 27th, 2012 at 9:29 am
Hi Kevin, I’m glad my post helped you out.
Thanks for the update suggestion. I merged your code into the post
Cheers,
Alex
Posted on May 7th, 2012 at 3:31 am
showDialog(DIALOG_NONETWORK); has been depreciated
thanks for all the help!
Posted on May 21st, 2012 at 6:09 am
Thanks! Included this into my code. Hope it works well with Android 4.0
Posted on July 20th, 2012 at 6:10 pm
I was doing this and for the life of me could not figure out why it wasn’t working.
I magically found this: http://www.w3.org/TR/html5/offline.html#manifests
It told me that my webserver mimetype for manifest needs to be supported. So if it isn’t working, make sure your content type for your manifest is text/cache-manifest
you can see by doing curl -I “http://yourmanifestsite/cache.manifest”
Posted on July 31st, 2012 at 9:27 am
Thank you so much!