1

I use android studio to make an app out of my website, and I really need localstorage, but it deletes completely every time I close the app. How can I fix it?

<uses-permission android:name="android.permission.INTERNET" />

and I use this code to enable javascript and localstorage:

 myWebView = (WebView)findViewById(R.id.webView);
        WebSettings webSettings = myWebView.getSettings();
        webSettings.setJavaScriptEnabled(true);
        myWebView.getSettings().setDomStorageEnabled(true);
        myWebView.getSettings().setDatabaseEnabled(true);

I've seen other people asking the same question and I used this answer:

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

but it says it's deprecated and it still doesn't work(localstorage is deleted every time I restart my app).

Please help me solve this, I want my localstorage to be saved!

Nuflix
  • 69
  • 6
  • "This error is actually not resulting from lacking any Java-side permissions, it's due to improved web security model of newer WebView versions.Your trying to access localStorage from a page of a different origin. E.g. if you are using loadData for your initial page, and then load other parts from a server, that code can have different origin." see [here](https://stackoverflow.com/questions/31812066/html5-localstorage-not-working-on-android-webview). Also [here](https://stackoverflow.com/questions/4157184/android-making-webview-domstorage-persistant-after-app-closed) – Jon Goodwin Jan 22 '18 at 21:57
  • And another [here](https://stackoverflow.com/questions/2961460/my-android-html-application-is-losing-values-stored-in-localstorage-when-it-shut/19631055#19631055) – Jon Goodwin Jan 22 '18 at 22:00
  • so can it be fixed somehow? like making it less secure? – Nuflix Jan 22 '18 at 22:01
  • I'll download your code and do some tests... – Jon Goodwin Jan 22 '18 at 22:03
  • thanks, and does it work with cookies? – Nuflix Jan 22 '18 at 22:05
  • also, my website reads localstorage itself, so it shouldn't be about security? – Nuflix Jan 22 '18 at 22:37

2 Answers2

0

did not understand very well your question but try to add this:

CookieSyncManager.createInstance(this);
CookieManager cookieManager = CookieManager.getInstance();
cookieManager.setAcceptCookie(true);

String appCachePath = getApplicationContext().getCacheDir().getAbsolutePath();
myWebView.setAllowFileAccess(true);
myWebView.setAppCachePath(appCachePath);


<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
Kevin Dias
  • 1,043
  • 10
  • 28
  • I tried it now and it still doesn't work, well to explain further, I use this(localstorage in HTML5) https://www.w3schools.com/html/html5_webstorage.asp – Nuflix Jan 22 '18 at 21:40
  • If you have any other idea pls tell me, and thanks a lot for trying to help – Nuflix Jan 22 '18 at 21:40
  • 1
    I use localstorage in my website and when I open my website in webview it works fine, it saves data to localstorage, but when I close the app and open it again data that should be on the page disappears – Nuflix Jan 22 '18 at 21:43
  • It works fine in browser, I could try cookies, it's a lot of work to change my website now but if nothing else can be done I will try, thanks – Nuflix Jan 22 '18 at 21:51
  • see the tread; one solution :"I've finally managed to solve this problem. The only way I could get it to work, no matter what I tried, was to include the html file within the app, rather than doing it through Buzztouch's control panel, and loading that in. This html file now loads correctly and with no localStorage errors." [https://stackoverflow.com/questions/31812066/html5-localstorage-not-working-on-android-webview] – Kevin Dias Jan 22 '18 at 21:54
  • I've just foujhnd out that cookie size is 4KB and I need at least 700KB because I upload base64 image, anyways it seems cookies can't be used, anyways, website itself reads localstorage, and that means it should be working, except it's not working :( – Nuflix Jan 22 '18 at 22:37
0

I managed to cache audio files in the local storage in one of my apps which uses a WebView. This means that the audio files are intercepted and then if not available in the cache they are downloaded and then served from the cache. The cache survives the phone being restarted on Android 10.

These are the settings I used for the WebView:

@SuppressLint("SetJavaScriptEnabled")
public static void setupWebview(WebView webView) {
    WebSettings settings = webView.getSettings();
    settings.setLoadWithOverviewMode(true);
    settings.setUseWideViewPort(true);
    settings.setAllowFileAccess(true);
    settings.setAllowContentAccess(true);
    settings.setAllowFileAccessFromFileURLs(true);
    settings.setAllowUniversalAccessFromFileURLs(true);
    settings.setBlockNetworkImage(false);
    settings.setBlockNetworkLoads(false);
    settings.setLoadsImagesAutomatically(true);
    settings.setMediaPlaybackRequiresUserGesture(false);
    settings.setDomStorageEnabled(true);
    settings.setLoadWithOverviewMode(true);
    settings.setJavaScriptEnabled(true);
    settings.setAllowUniversalAccessFromFileURLs(true);
    settings.setDatabaseEnabled(true);
    settings.setAppCacheEnabled(true);
    settings.setAppCachePath("/beezone");
}

And I have used a customized WebClient for the same WebView:

So basically the custom WebClient looks like this:

    mWebView.setWebViewClient(new WebViewClient() {

        @TargetApi(Build.VERSION_CODES.LOLLIPOP)
        @Nullable
        @Override
        public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
            return cacheM4a(request, context);
        }

        @Nullable
        @Override
        public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
            return cacheM4a(Uri.parse(url), context);
        }
    });

The relevant code for method cacheM4a looks like this:

@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@Nullable
public static WebResourceResponse cacheM4a(WebResourceRequest request, Context context) {
    Uri source = request.getUrl();
    return cacheM4a(source, context);
}

@Nullable
public static WebResourceResponse cacheM4a(Uri source, Context context) {
    String sourceStr = source.toString();
    if (sourceStr.endsWith(CacheHelper.MAIN_AUDIO_FORMAT)) {
        String language = LanguageHelper.INSTANCE.getLanguage();
        String absolutePath = context.getCacheDir().getAbsolutePath();
        String langPath = String.format("%s/%s", absolutePath, language);
        boolean folderExists = createLanguageCachePath(langPath);
        if(!folderExists) {
            try {
                return new WebResourceResponse("audio/mp4", "binary", new URL(sourceStr).openStream());
            } catch (IOException e) {
                Log.e(TAG, "Failed to read directly from the web", e);
                return null;
            }
        }
        String targetPath = String.format("%s/%s", langPath, source.getLastPathSegment());
        File file = new File(targetPath);
        if (!file.exists()) {
            if (saveToCache(sourceStr, targetPath)) return null;
        }
        // Always read from cache.
        try  {
            FileInputStream fis = new FileInputStream(new File(targetPath));
            WebResourceResponse response = new WebResourceResponse("audio/mp4", "binary", fis);
            return response;
        } catch (IOException e) {
            Log.e(TAG, "Failed to read cache", e);
            return null;
        }
    }
    return null;
}

private static boolean saveToCache(String sourceStr, String targetPath) {
    // File is not present in cache and thus needs to be downloaded
    try (InputStream in = new URL(sourceStr).openStream();
         FileOutputStream fos = new FileOutputStream(new File(targetPath))) {
        ByteStreams.copy(in, fos);
    } catch (IOException e) {
        Log.e(TAG, "Failed to save in cache", e);
        return true;
    }
    return false;
}

private static boolean createLanguageCachePath(String langPath) {
    File langPathFile = new File(langPath);
    if(!langPathFile.exists()) {
        if(!langPathFile.mkdirs()) {
            Log.e(TAG, String.format("Could not create %s", langPathFile));
            return false;
        };
    }
    return true;
}

These are the permissions I have used:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
gil.fernandes
  • 12,978
  • 5
  • 63
  • 76