4

To provide a quick way for the user to clear out the cache, I am using the following function (based on this and this) attached to a Clear Cache button:

static void clearAppCache(Context context) {
    try {
        File dir = context.getCacheDir();
        deleteDir(dir);
    } catch (Exception e) {
        // TODO: handle exception
    }
}

private static boolean deleteDir(File dir) {
    if (dir != null && dir.isDirectory()) {
        String[] children = dir.list();
        for (String aChildren : children) {
            boolean success = deleteDir(new File(dir, aChildren));
            if (!success) {
                return false;
            }
        }
        return dir.delete();
    } else if (dir!= null && dir.isFile()) {
        return dir.delete();
    } else {
        return false;
    }
}

I'm also setting up my WebView with the same cache path, as follows:

WebSettings webSettings = mWebView.getSettings();
webSettings.setAppCacheEnabled(true);
String cachePath = getApplicationContext().getCacheDir().getAbsolutePath();
webSettings.setAppCachePath(cachePath);

My theory is that calling clearAppCache() will also clear the WebView's cache because all it's doing is clearing out the same cache folder I've set for the WebView.

But since my WebView is now loading a page that uses a service worker, I'm finding that this doesn't seem to be clearing out the service worker cache. I've had reports from one user that, to really clear out the service worker stuff, they have to manually clear the content of the following folder (on their rooted device):

/data/data/com.example.myapp/app_webview/Cache/

Based on this post I have tried adding the following line to my clearAppCache() function:

WebStorage.getInstance().deleteAllData();

But still this doesn't seem to have the effect of clearing the service worker cache.

Any ideas? Yes I know that the service worker cache can be cleared using javascript (see the above-linked post), but I want a way of doing this directly from Android.

Phantômaxx
  • 37,901
  • 21
  • 84
  • 115
drmrbrewer
  • 11,491
  • 21
  • 85
  • 181

2 Answers2

4

I have now found a way to delete the service worker cache. My data directory is at:

/data/user/0/com.app.package

And then within that is:

/cache
    /http
    /org.chromium.android_webview
    /WebView
/code_cache
/files
/shared_prefs
/app_webview
    /webview_data.lock
    /Web Data
    /Web Data-journal
    /metrics_guid
    /Cookies
    /Cookies-journal
    /GPUCache
    /Service Worker
    /QuotaManager
    /QuotaManager-journal
    /databases
/app_textures
/app_download_internal
/databases
/shaders

Note the presence of a Service Worker sub-directory within app_webview, which is a bit of a giveaway.

So, to clear the service worker cache, it seems that you just have to delete that sub-directory:

File dataDir = context.getDataDir(); // or see https://stackoverflow.com/a/19630415/4070848 for older Android versions
File serviceWorkerDir = new File(dataDir.getPath() + "/app_webview/Service Worker/");
deleteDir(serviceWorkerDir); // function defined in original post

Or, being more brutal, it seems that you can just delete the whole app_webview sub-folder and everything in it:

File dataDir = context.getDataDir(); // or see https://stackoverflow.com/a/19630415/4070848 for older Android versions
File appWebViewDir = new File(dataDir.getPath() + "/app_webview/");
deleteDir(appWebViewDir); // function defined in original post

What still confuses me is that, despite setting the cache path for the WebView with webSettings.setAppCachePath(cachePath) to be in the cache directory (see my original post), the WebView has chosen to use app_webview for service worker caching. Maybe it uses the cache directory for traditional http caching, and chooses its own location (app_webview) for service worker caching? It still doesn't seem right though. Furthermore, as mentioned, one user has reported the presence of a Cache sub-directory within app_webview, and they are on KitKat (Android 4.4) that doesn't support service workers... not sure why that app_webview/Cache directory is in use rather than (or in addition to) cache. I don't have app_webview/Cache at all on mine.

drmrbrewer
  • 11,491
  • 21
  • 85
  • 181
2

I'm not familiar with the Android<->WebView interactions. But assuming you could run JavaScript from the context of a page in your local origin, the following code should clear out everything in the Cache Storage API for your origin:

async function clearAllCaches() {
  const allCaches = await caches.keys();
  for (const cache of allCaches) {
    caches.delete(cache);
  }
}

Using the Clear-Site-Data header is another option, if you have control over a remote webserver that's serving your HTML, and if you know that your users will have a WebView based on Chrome 61+.

Jeff Posnick
  • 53,580
  • 14
  • 141
  • 167
  • The `Clear-Site-Data` header is an interesting option @JeffPosnick because it allows some control over client caches from the host (which I do control). However, it's not clear to me how to set this... I'm used to setting headers up in the `.htaccess` file like `Header set Cache-Control "no-store, no-cache, must-revalidate, max-age=0"` but the `Clear-Site-Data` header is a JSON string (https://www.w3.org/TR/clear-site-data/), which already includes characters like `"` and `[` that don't fit well with the standard `.htaccess` syntax and causes problems... any ideas how to do this? – drmrbrewer Nov 21 '17 at 16:00
  • I don't work with `.htaccess` files regularly, but in general, `\` is customary for escaping characters. So... does \" and \\[ work? – Jeff Posnick Nov 21 '17 at 16:09
  • D'oh! Yes it seems to... the header appears in the response in DevTools. But what actually happens when e.g. my head html page is served with such a header in the response (specifying all of "cache", "cookies", "storage", "executionContexts")... what does the browser do? Clear this stuff just ONCE, then continue loading (and storing stuff in cache including service worker cache), and on subsequent refreshes it doesn't clear this stuff again? – drmrbrewer Nov 21 '17 at 16:17
  • I think https://w3c.github.io/webappsec-clear-site-data/#fetch-integration is the authoritative answer, though the current state of that doc implies that the implementations might change. – Jeff Posnick Nov 21 '17 at 16:26
  • I should note that the w3c reference I included above is an old version... the following is more recent: https://w3c.github.io/webappsec-clear-site-data/ and in that the header format is a (far more sensible) comma separated list (rather than JSON string), e.g.: `Clear-Site-Data: "cache", "cookies", "storage", "executionContexts"`. I still have no clue how to make this work, despite a few attempts so far... I'll keep trying... – drmrbrewer Nov 22 '17 at 15:26
  • See my new question about this header at: https://stackoverflow.com/q/47439072/4070848 – drmrbrewer Nov 22 '17 at 16:02