Android WebViews同步本地存储在线和离线内容

3
我有一个应用程序,允许用户在线玩游戏或将游戏缓存到本地。当他们将游戏转换为缓存模式时,我不希望他们失去进度。
在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()期间尝试同步文件,但我想知道是否有更优雅的解决方案 - 比如集中存储。


同步 onPause 存在一些问题:1- 在主线程上阻塞 IO 任务 2- 更可能需要合并两个文件,而不是用新文件替换旧文件。 - copolii
2个回答

1
这感觉有点“不干净”,但它能够工作(在KitKat及更高版本上)!
下面的LocalStorageCopier类使用SharedPreferences存储来跟踪项目(可以随意使用其他替代品)。在加载url(本地或远程)之前,创建一个LocalStorageCopier实例,并将其添加为webView的JavascriptInterface。
webView.setWebViewClient(new WebClient());
storageBackup = new LocalStorageCopier(someContext, someId);
webView.addJavascriptInterface(storageBackup, "backup");
webView.loadUrl (someUrl);

注意: 在加载页面之前添加 JavaScript 接口是很重要的。我一直在想为什么会出现 "backup is undefined" 的问题,直到我把这部分移到加载 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

因此,每次暂停活动时,都会备份你的 localStorage

恢复的方式非常相似。需要在页面加载后启动恢复操作。这就是 WebClient 类(下面的代码)发挥作用的地方。一旦页面加载完成,您必须获取 LocalStorageCopier 实例中的所有项目,并将它们放入 localStorage 中。 RESTORE_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();
    }
}

WebClient(网络客户端)
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);
    }
}

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接