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 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.