Search code examples
androidandroid-webviewandroidhttpclientandroid-cookiemanager

Android webview cookies are cleared/garbage collected after some time - Can I set a cookie custom storage path?


I am trying to make my webview remember its cookies. My problem is that, they are removed after some time.

After doing some research, I found out that java's internal HttpClient uses CookieManager and CookieStore will get garbage collected. HttpClient is used in some of my networking code (not all written by me). I am pretty sure this is the reason for my problem.

So my question is: Is there a way to save cookies from webview to another location than the one used by HttpClient?

I have tried setting a custom path like so:

webview.setWebViewClient(new WebViewClient() {
                @Override
                public void onPageFinished(WebView view, String url) {
                    if (getCustomActivity() != null) {
                        CookieSyncManager.createInstance(getCustomActivity()).sync();
                    }
                }
            });
            webview.getSettings().setAppCachePath("/data/data/"+getActivity().getPackageName()+"/webview_cookies/");
            webview.loadUrl(url, true);

But with no luck.


Solution

  • I finally found a solution, which I am satisfied with. Basically, I am saving cookies in Shared Preferences and fetching them from there.

    Here is my suggestion for a solution (A view class extending AdvancedWebView, which also could be the standard webview):

    public class PersistentCookiesWebView extends AdvancedWebView {
    
        private static String       url                         = "PersistentCookiesWebView";
        private static String       cookieKey                   = "";
        private static final String COOKIE_STORAGE_KEY_PREFIX   = "cskp_";
        private static final long   COOKIE_MAX_STORAGE_BYTES    = 500000;
    
        public PersistentCookiesWebView(Context context) {
            super(context);
        }
    
        public PersistentCookiesWebView(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        public PersistentCookiesWebView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
        }
    
        public void loadUrl(final String url, String cookieKey) {
            this.url        = url;
            this.cookieKey  = cookieKey;
            initializeWebView(new WebViewListener() {
                @Override
                public void onWebViewReady() {
                    PersistentCookiesWebView.super.loadUrl(url);
                }
            });
        }
    
        @Override
        public void loadUrl(final String url) {
            this.url        = url;
            this.cookieKey  = getHostName();
            initializeWebView(new WebViewListener() {
                @Override
                public void onWebViewReady() {
                    PersistentCookiesWebView.super.loadUrl(url);
                }
            });
        }
    
        @Override
        public void loadUrl(final String url, final Map<String, String> additionalHttpHeaders) {
            this.url        = url;
            this.cookieKey  = getHostName();
            initializeWebView(new WebViewListener() {
                @Override
                public void onWebViewReady() {
                    PersistentCookiesWebView.super.loadUrl(url, additionalHttpHeaders);
                }
            });
        }
    
        @Override
        public void loadUrl(final String url, final boolean preventCaching) {
            this.url        = url;
            this.cookieKey  = getHostName();
            initializeWebView(new WebViewListener() {
                @Override
                public void onWebViewReady() {
                    PersistentCookiesWebView.super.loadUrl(url, preventCaching);
                }
            });
        }
    
        @Override
        public void loadUrl(final String url, final boolean preventCaching, final Map<String, String> additionalHttpHeaders) {
            this.url        = url;
            this.cookieKey  = getHostName();
            initializeWebView(new WebViewListener() {
                @Override
                public void onWebViewReady() {
                    PersistentCookiesWebView.super.loadUrl(url, preventCaching, additionalHttpHeaders);
                }
            });
        }
    
        protected void initializeWebView(final WebViewListener webViewListener) {
            setWebViewClient(new WebViewClient() {
                @Override
                public void onPageFinished(WebView view, String url) {
                    super.onPageFinished(view, url);
                    CookieManager.getInstance().flush();
                }
            });
            setOnTouchListener(new OnTouchListener() {
                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    saveCookies(null);
                    return false;
                }
            });
            fetchCookies(new CookieFetchListener() {
                @Override
                public void onCookiesFetched() {
                    webViewListener.onWebViewReady();
                }
            });
        }
    
        public void saveCookies(CookieSaveListener cookieSaveListener) {
    
            String storageKey                   = COOKIE_STORAGE_KEY_PREFIX + cookieKey;
            String currentCookieString          = CookieManager.getInstance().getCookie(url) + "";
            ArrayList<String> currentCookieList = new ArrayList<String>(Arrays.asList(currentCookieString.split(";")));
            long cookieBytes                    = 0;
            String newCookies                   = "";
    
            for(int i = currentCookieList.size() - 1; i >= 0; i--) {
                String cookie = currentCookieList.get(i);
                try {
                    cookieBytes = cookieBytes + cookie.getBytes().length;
                } catch (Exception e) {
                    e.printStackTrace();
                }
                if (cookieBytes < COOKIE_MAX_STORAGE_BYTES) {
                    newCookies = cookie + ";" + newCookies;
                } else {
                    break;
                }
            }
            PreferencesManager.putString(getContext(), storageKey, newCookies);
    
            if (cookieSaveListener != null) {
                cookieSaveListener.onCookiesSaved();
            }
        }
    
        private void fetchCookies(final CookieFetchListener cookieFetchListener) {
            String storageKey                   = COOKIE_STORAGE_KEY_PREFIX + cookieKey;
            String currentCookieString          = CookieManager.getInstance().getCookie(url) + "";
            String storedCookiesString          = PreferencesManager.getString(getContext(), storageKey) + "";
            ArrayList<String> storedCookiesList = new ArrayList<String>(Arrays.asList(storedCookiesString.split(";")));
    
            for (String storedCookie : storedCookiesList) {
                if(!currentCookieString.contains(storedCookie)) {
                    CookieManager.getInstance().setCookie(url, storedCookie);
                    CookieManager.getInstance().setCookie(cookieKey, storedCookie);
                }
            }
            cookieFetchListener.onCookiesFetched();
            saveCookies(null);
        }
    
        private String getHostName() {
            try {
                URL aURL = new URL(url);
                return aURL.getHost() + "";
            } catch (MalformedURLException e) {
                e.printStackTrace();
                return "";
            }
        }
    
        @Override
        protected void onDetachedFromWindow() {
            super.onDetachedFromWindow();
            Log.d(getClass().getSimpleName(), "Cookies attempting to save...");
            saveCookies(new CookieSaveListener() {
                @Override
                public void onCookiesSaved() {
                    Log.d(getClass().getSimpleName(), "Cookies saved!");
                }
            });
        }
    
        interface CookieFetchListener {
            void onCookiesFetched();
        }
        interface CookieSaveListener {
            void onCookiesSaved();
        }
        interface WebViewListener {
            void onWebViewReady();
        }
    }
    

    I hope this can be useful to others as well.