具有在线和离线内容的android WebViews的同步localstorage

时间:2017-01-06 20:28:56

标签: android android-webview local-storage offline-caching

我有一个应用程序,允许用户在线玩游戏或在本地缓存它们。当他们将游戏转换为缓存时,我不希望他们失去进展。

在KitKat之前,您可以设置localstorage目录,但我需要更新的手机来支持此功能。

if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
    playingField.getSettings().setDatabasePath("/data/data/" + playingField.getContext().getPackageName() + "/databases/");
}

我无法找到替代方法。因此,以下是两个目录:

root@ghost:/data/data/com.myapp.android/app_webview/Local Storage #
ls -la
total 80
drwx------ 2 u0_a165 u0_a165 4096 2017-01-06 11:51 .
drwxrwx--x 4 u0_a165 u0_a165 4096 2017-01-06 11:41 ..
-rw------- 1 u0_a165 u0_a165 4096 2017-01-06 11:51 file__0.localstorage
-rw------- 1 u0_a165 u0_a165    0 2017-01-06 11:51 file__0.localstorage-journal
-rw------- 1 u0_a165 u0_a165 4096 2017-01-06 12:02 http_cdn.myapp.com_0.localstorage
-rw------- 1 u0_a165 u0_a165    0 2017-01-06 12:02 http_cdn.myapp.com_0.localstorage-journal

有没有人解决过这个问题?

我可能会尝试在活动的onPause()期间同步文件,但我想知道是否有更优雅的解决方案 - 例如整合存储。

2 个答案:

答案 0 :(得分:1)

感觉有点,但它有效(在KitKat和更新){/ p>

下面的LocalStorageCopier课程使用SharedPreferences商店来跟踪商品(可以随意使用其他任何商品)。 之前,您加载网址(本地或远程),创建LocalStorageCopier的实例并将其作为JavascriptInterface添加到您的网络视图中:

webView.setWebViewClient(new WebClient());
storageBackup = new LocalStorageCopier(someContext, someId);
webView.addJavascriptInterface(storageBackup, "backup");
webView.loadUrl (someUrl);

注意:在加载页面之前添加javascript界面​​非常重要。我正在摸不着为什么“备份是未定义的”,直到我在加载url之前将这一点移动(我在执行备份之前添加它)。

现在您只需要绑定备份还原操作。

备份:正如您上面提到的,onPause方法是支持这些内容的好地方。在onPause内的适当位置添加以下代码:

webView.evaluateJavascript(BACKUP_JAVASCRIPT, new ValueCallback<String>() {
        @Override public void onReceiveValue(String s) {
            LOG.d("Backed up.");
        }
    });

其中BACKUP_JAVASCRIPT"(function() { console.log('backing up'); backup.clear(); for (var key in localStorage) { backup.set(key, localStorage.getItem(key)); }})()"

现在,每当您的活动暂停时,您的localStorage都会备份。

恢复以非常类似的方式完成。您需要在加载页面后启动还原操作。这是WebClient类(下面的代码)的来源。页面加载完成后,您必须抓取LocalStorageCopier实例中的所有项目并将其放入localStorageRESTORE_JAVASCRIPT的javascript是:"(function(){console.log('Restoring'); backup.dump(); var len = backup.size(); for (i = 0; i < len; i++) { var key = backup.key(i); console.log(key); localStorage.setItem(key, backup.get(key));}})()"

<强> LocalStorageCopier

public static class LocalStorageCopier {
    private final SharedPreferences store;
    private String[] keys = null;
    private String[] values = null;

    private boolean dumped = false;

    LocalStorageCopier(final Context context, final String id) {
        store = context.getSharedPreferences(id, Context.MODE_PRIVATE);
    }

    @JavascriptInterface
    public synchronized void dump() {
        if (dumped) throw new IllegalStateException("already dumped");
        final Map<String, ?> map = store.getAll();
        final int size = map.size();
        keys = new String[size];
        values = new String[size];

        int cur = 0;

        for (final String key : map.keySet()) {
            keys[cur] = key;
            values[cur] = (String) map.get(key);
            ++cur;
        }

        dumped = true;
    }

    @JavascriptInterface
    public synchronized int size() {
        if (!dumped) throw new IllegalStateException("dump() first");
        return keys.length;
    }

    @JavascriptInterface
    public synchronized String key(final int i) {
        if (!dumped) throw new IllegalStateException("dump() first");
        return keys[i];
    }

    @JavascriptInterface
    public synchronized String value(final int i) {
        if (!dumped) throw new IllegalStateException("dump() first");
        return values[i];
    }

    @JavascriptInterface
    public synchronized String get(final String key) {
        return store.getString(key, null);
    }

    @JavascriptInterface
    public synchronized void set(final String key, final String value) {
        if (dumped) throw new IllegalStateException("already dumped");
        store.edit().putString(key, value).apply();
    }

    @JavascriptInterface
    public synchronized void clear() {
        store.edit().clear().apply();
        keys = null;
        values = null;
        dumped = false;
    }

    @Override public synchronized String toString() {
        return store.getAll().toString();
    }
}

<强> Web客户端

class WebClient extends WebViewClient {
    @Override public void onPageFinished(WebView view, String url) {
        LOG.d("Page finished. Restoring storage.");

        view.evaluateJavascript(RESTORE_JAVASCRIPT, new ValueCallback<String>() {
            @Override public void onReceiveValue(String s) {
                LOG.d("Restored.");
            }
        });

        super.onPageFinished(view, url);
    }
}

答案 1 :(得分:0)

也许使用符号链接,两个版本的webview都会使用相同的文件:

Creating SymLinks in Android