Android webview cookie cleared/garbage 会在一段时间后收集 - 我可以设置 cookie 自定义存储路径吗?
Android webview cookies are cleared/garbage collected after some time - Can I set a cookie custom storage path?
我正在尝试让我的网络视图记住它的 cookie。我的问题是,它们会在一段时间后被删除。
经过一些研究后,我发现 java 的内部 HttpClient 使用 CookieManager 并且 CookieStore 将被垃圾收集。 HttpClient 在我的一些网络代码中使用(并非全部由我编写)。
我很确定这是我的问题的原因。
所以我的问题是:有没有办法将 webview 中的 cookie 保存到 HttpClient 使用的位置以外的其他位置?
我试过像这样设置自定义路径:
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);
但运气不好。
我终于找到了一个解决方案,我很满意。基本上,我将 cookie 保存在共享首选项中并从那里获取它们。
这是我的解决方案建议(视图 class 扩展 AdvancedWebView,也可以是标准的 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();
}
}
我希望这对其他人也有用。
我正在尝试让我的网络视图记住它的 cookie。我的问题是,它们会在一段时间后被删除。
经过一些研究后,我发现 java 的内部 HttpClient 使用 CookieManager 并且 CookieStore 将被垃圾收集。 HttpClient 在我的一些网络代码中使用(并非全部由我编写)。 我很确定这是我的问题的原因。
所以我的问题是:有没有办法将 webview 中的 cookie 保存到 HttpClient 使用的位置以外的其他位置?
我试过像这样设置自定义路径:
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);
但运气不好。
我终于找到了一个解决方案,我很满意。基本上,我将 cookie 保存在共享首选项中并从那里获取它们。
这是我的解决方案建议(视图 class 扩展 AdvancedWebView,也可以是标准的 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();
}
}
我希望这对其他人也有用。