user68621 user68621 -3 years ago 116
Android Question

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.

I really hope someone can help me out here.
Any help will be gratly appreciated.

Answer Source

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.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download