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();
    }
}

我希望这对其他人也有用。