【问题标题】:Two way sync for cookies between HttpURLConnection (java.net.CookieManager) and WebView (android.webkit.CookieManager)HttpURLConnection (java.net.CookieManager) 和 WebView (android.webkit.CookieManager) 之间 cookie 的两种同步方式
【发布时间】:2013-08-05 11:59:36
【问题描述】:

很遗憾,Android 有大量的 cookie 管理器。 HttpURLConnection 的 cookie 由 java.net.CookieManager 维护,WebView 的 cookie 由 android.webkit.CookieManager 维护。这些 cookie 存储库是独立的,需要手动同步。

我的应用同时使用 HttpURLConnections 和显示 WebViews(它是原生 HTML 混合体)。自然,我希望两者都共享所有 cookie - 所以我将有一个透明的会话。

更具体地说:

  1. 在 HttpURLConnection 中设置/更改 cookie 时,我希望 WebView 也能看到此更改。
  2. 在 WebView 中设置/更改 cookie 时,我希望下一个 HttpURLConnections 也能看到此更改。

简单地说 - 我正在寻找双向同步。或者更好的是,让它们都使用相同的 cookie 存储库。您可以假设两者同时处于活动状态(例如在不同的选项卡上)。

问题:

  1. 有没有办法让两者使用相同的 cookie 存储库?

  2. 如果没有,推荐的手动同步做法是什么?我应该在什么时候同步以及如何同步?

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

迄今为止我的最佳想法:我真的很想避免手动同步,所以我试着思考如何让两者使用同一个存储库。也许我可以创建自己的核心处理程序来扩展java.net.CookieManager。我将使用java.net.CookieHandler.setDefault() 将其设置为核心cookie 处理程序。它的实现将是android.webkit.CookieManager 处理程序实例的代理(对于每个函数,我将简单地访问webkit 管理器)。

【问题讨论】:

标签: android http cookies android-webview httpurlconnection


【解决方案1】:

我已经实现了自己的想法。它实际上很酷。我创建了自己的java.net.CookieManager 实现,它将所有请求转发到WebViews 的webkit android.webkit.CookieManager。这意味着不需要同步,并且 HttpURLConnection 使用 same cookie 存储作为 WebView。

类 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);

测试

我的初步测试表明这运行良好。我看到了 WebView 和 HttpURLConnection 之间共享的 cookie。我希望我不会遇到任何问题。如果您尝试此操作并发现任何问题,请发表评论。

【讨论】:

  • 这个方法也让我可以解决 java.net.CookieManager 的一些问题。一个网站正在设置带有稍微修改的域的 cookie,而 .net CookieManager 不合作。这个解决方案解决了这个问题。
  • 您将CookiePolicy 作为参数传递给被覆盖的构造函数。您是否真的找到了一种方法让机器人CookieManager 使用该政策,或者到目前为止您不关心该政策?
  • android 应用关闭时保存 CookieStore 怎么样?
  • 如果您的目标是 API 级别 21+,您可能需要考虑在 Webview-behaviour 中使用 cookie 和混合内容进行的更改。这个实现毕竟依赖于 android.webkit.CookieManager。
  • 出于某种原因,在我的情况下,代码没有超出以下行:// get the cookie String cookie = this.webkitCookieManager.getCookie(url); 我不确定这里发生了什么样的问题。我没有得到任何异常,所以它可能是一些锁或死锁......
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-01-29
  • 2012-03-01
  • 1970-01-01
  • 2013-02-10
  • 2011-02-25
  • 1970-01-01
  • 2012-05-24
相关资源
最近更新 更多