Java.net.CookieManager和Android.webkit.CookieManager之间的cookie双向同步

36
很不幸,在Android上有许多cookie管理器。 HttpURLConnection的cookie由java.net.CookieManager维护,而WebView的cookie由android.webkit.CookieManager维护。这些cookie存储库是独立的,需要手动同步。
我的应用程序同时使用HttpURLConnections和显示WebViews(它是本地HTML混合应用程序)。自然地,我希望两者共享所有cookie-这样我就会拥有透明的会话。
更具体地说:
1.当在HttpURLConnection中设置/更改cookie时,我希望WebViews也能看到此更改。 2.当在WebView中设置/更改cookie时,我希望下一个HttpURLConnection也能看到此更改。
简单点说-我正在寻找双向同步,甚至更好的是让它们都使用相同的cookie存储库。您可以假设两者在同一时间处于活动状态(例如在不同的选项卡中)。
问题:
  1. 有没有办法使它们共用同一个cookie存储库?

  2. 如果没有,那么建议如何进行手动同步?什么时候应该同步,如何同步?

相关问题:这个question也涉及类似的问题,但只实现了单向同步(HttpURLConnection -> WebView)。

我目前最好的想法:我真的不想手动同步,所以我尝试想如何让它们共用同一个存储库。也许我可以创建自己的核心处理程序,它扩展了java.net.CookieManager。我将使用java.net.CookieHandler.setDefault()将其设置为核心cookie处理程序。它的实现将是到android.webkit.CookieManager处理程序实例的代理(对于每个函数,我将简单地访问webkit管理器)。


这是我的解决方案:https://dev59.com/AWcs5IYBdhLWcg3wlFA2#27185278 我希望它能有所帮助... - Christian
1个回答

66
我实现了自己的想法。其实很酷。我创建了自己的java.net.CookieManager实现,将所有请求转发到WebViews的webkit android.webkit.CookieManager。这意味着不需要同步,并且HttpURLConnection使用与WebViews相同的cookie存储。

类WebkitCookieManagerProxy:

import java.io.IOException;
import java.net.CookieManager;
import java.net.CookiePolicy;
import java.net.CookieStore;
import java.net.URI;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

public class WebkitCookieManagerProxy extends CookieManager 
{
    private android.webkit.CookieManager webkitCookieManager;

    public WebkitCookieManagerProxy()
    {
        this(null, null);
    }

    public WebkitCookieManagerProxy(CookieStore store, CookiePolicy cookiePolicy)
    {
        super(null, cookiePolicy);

        this.webkitCookieManager = android.webkit.CookieManager.getInstance();
    }

    @Override
    public void put(URI uri, Map<String, List<String>> responseHeaders) throws IOException 
    {
        // make sure our args are valid
        if ((uri == null) || (responseHeaders == null)) return;

        // save our url once
        String url = uri.toString();

        // go over the headers
        for (String headerKey : responseHeaders.keySet()) 
        {
            // ignore headers which aren't cookie related
            if ((headerKey == null) || !(headerKey.equalsIgnoreCase("Set-Cookie2") || headerKey.equalsIgnoreCase("Set-Cookie"))) continue;

            // process each of the headers
            for (String headerValue : responseHeaders.get(headerKey))
            {
                this.webkitCookieManager.setCookie(url, headerValue);
            }
        }
    }

    @Override
    public Map<String, List<String>> get(URI uri, Map<String, List<String>> requestHeaders) throws IOException 
    {
        // make sure our args are valid
        if ((uri == null) || (requestHeaders == null)) throw new IllegalArgumentException("Argument is null");

        // save our url once
        String url = uri.toString();

        // prepare our response
        Map<String, List<String>> res = new java.util.HashMap<String, List<String>>();

        // get the cookie
        String cookie = this.webkitCookieManager.getCookie(url);

        // return it
        if (cookie != null) res.put("Cookie", Arrays.asList(cookie));
        return res;
    }

    @Override
    public CookieStore getCookieStore() 
    {
        // we don't want anyone to work with this cookie store directly
        throw new UnsupportedOperationException();
    }
}

在应用程序初始化时按照以下方式使用它:

android.webkit.CookieSyncManager.createInstance(appContext);
// unrelated, just make sure cookies are generally allowed
android.webkit.CookieManager.getInstance().setAcceptCookie(true);

// magic starts here
WebkitCookieManagerProxy coreCookieManager = new WebkitCookieManagerProxy(null, java.net.CookiePolicy.ACCEPT_ALL);
java.net.CookieHandler.setDefault(coreCookieManager);

测试

我的初步测试表明这个功能运行良好。我发现在WebViews和HttpURLConnection之间共享了cookies。希望不会遇到任何问题。如果您尝试并发现任何问题,请评论说明。


这种方法还让我解决了java.net.CookieManager的一些问题。一个网站使用稍微修改过的域名设置cookie,而 .net CookieManager 无法配合。这个解决方案解决了这个问题。 - thepenguin77
你将 CookiePolicy 作为参数传递给了被覆盖的构造函数。你是否真的找到了一种方法让 Android 的 CookieManager 使用该策略,或者你迄今为止并不关心该策略? - ohcibi
1
当安卓应用关闭时,持久化CookieStore怎么样? - Aivan Monceller
2
如果您的目标 API 等级为 21+,则可能需要考虑在 Webview 行为 中处理 cookie 和混合内容的更改。毕竟,此实现依赖于 android.webkit.CookieManager。 - Seb B.
1
由于某种原因,在我的情况下,代码无法超越以下行:`// get the cookie String cookie = this.webkitCookieManager.getCookie(url);`我不确定这里发生了什么问题。我没有收到任何异常,所以可能是一些锁定或死锁... - Alexander K
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接