将HttpURLConnection(java.net.CookieManager)的cookie传递给WebView(android.webkit.CookieManager)

34
我看到有关如何使用旧的DefaultHttpClient进行操作的答案,但没有一个好的HttpURLConnection示例。
我正在使用HttpURLConnection向Web应用程序发出请求。在我的Android应用程序开始时,我使用CookieHandler.setDefault(new CookieManager())自动处理会话cookie,并且这很好地运行。
在登录后的某个时间点,我想使用WebView显示来自Web应用程序的实时页面,而不是使用HttpURLConnection在幕后下载数据。但是,我希望使用我之前建立的相同会话,以防止用户再次登录。
如何将HttpURLConnection使用的java.net.CookieManager中的cookie复制到WebView使用的android.webkit.CookieManager中,以便我可以共享会话?
4个回答

56
我想提出一种完全不同的方法来解决你的问题。不要通过复制cookie来实现手动同步,而是让HttpURLConnection和WebViews使用相同的cookie存储。
这将完全消除同步的需要。任何在它们中的一个更新的cookie,都会立即自动地反映在另一个上。
为此,创建你自己的java.net.CookieManager实现,将所有请求转发给WebViews的webkit android.webkit.CookieManager。
实现如下:
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);
    }

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

如果服务器尝试删除过期日期的cookie,则此解决方案将无法成功删除cookie。这在javadoc [link](http://developer.android.com/reference/android/webkit/CookieManager.html#setCookie(java.lang.String,java.lang.String))中明确提到:“如果设置的cookie已过期,则将忽略该cookie。”我还在Android 4.2.1设备上进行了验证。 - garnet
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - se22as

20
与DefaultHttpClient相比,使用HTTPURLConnection需要进行一些额外的步骤。关键区别在于如何访问现有的HTTPURLConnection中的cookies:
  1. 调用CookieHandler.getDefault()并将结果转换为java.net.CookieManager
  2. 使用cookie管理器,调用getCookieStore()以访问cookie存储。
  3. 使用cookie存储,调用get()以访问给定URI的cookie列表。
这是一个完整的例子:
@Override
protected void onCreate(Bundle savedInstanceState) {
    // Get cookie manager for WebView
    // This must occur before setContentView() instantiates your WebView
    android.webkit.CookieSyncManager webCookieSync =
        CookieSyncManager.createInstance(this);
    android.webkit.CookieManager webCookieManager =
        CookieManager.getInstance();
    webCookieManager.setAcceptCookie(true);

    // Get cookie manager for HttpURLConnection
    java.net.CookieStore rawCookieStore = ((java.net.CookieManager)
        CookieHandler.getDefault()).getCookieStore();

    // Construct URI
    java.net.URI baseUri = null;
    try {
        baseUri = new URI("http://www.example.com");
    } catch (URISyntaxException e) {
        // Handle invalid URI
        ...
    }

    // Copy cookies from HttpURLConnection to WebView
    List<HttpCookie> cookies = rawCookieStore.get(baseUri);
    String url = baseUri.toString();
    for (HttpCookie cookie : cookies) {
        String setCookie = new StringBuilder(cookie.toString())
            .append("; domain=").append(cookie.getDomain())
            .append("; path=").append(cookie.getPath())
            .toString();
        webCookieManager.setCookie(url, setCookie);
    }

    // Continue with onCreate
    ...
}

我正在使用上述代码获取httpUrlConnection cookies并将其传递到webview。我已经成功从rawCookieStore中获取了cookies,并将cookie设置到cookiemanager中。但是,webview页面在加载时没有获取到该会话。请帮我解决这个问题。 - harshit2811

11

我在onCreate中使用了一行代码神奇地解决了我所有的cookie问题:

CookieHandler.setDefault(new CookieManager());


1
这对我也起作用了。谢谢!这也是Google在这里说的:http://developer.android.com/reference/java/net/HttpURLConnection.html - VinceFior
4
在上述调用中的 new CookieManager(),你是实例化了 android.webkit.CookieManager 还是 java.net.CookieManager? - Subodh Nijsure
@SubodhNijsure java.net.CookieManager @SubodhNijsure java.net.CookieManager - Seb B.
你在那里,救了我的命!谢谢。 - narancs

-2

我曾经遇到过同样的问题,这是我的解决方案:

在登录后(这很重要,因为在此之前,您可能还没有cookie),使用httpurlconnection POST(在getResponseCode之后),我执行以下操作:

 responseCode = connexion.getResponseCode();
 if (responseCode == HttpURLConnection.HTTP_OK) {
     final String COOKIES_HEADER = "Set-Cookie";
     cookie = connexion.getHeaderField(COOKIES_HEADER);
     ...
 }

(其中cookie是我类中的公共字符串)

在WebView活动中,当我想要使用WebView显示来自服务器的网页时,我执行以下操作:

    String url = "http://toto.com/titi.html";        // the url of the page you want to display
    CookieSyncManager.createInstance(getActivity());
    CookieSyncManager.getInstance().startSync();
    android.webkit.CookieManager cookieManager = android.webkit.CookieManager.getInstance();
    cookieManager.setAcceptCookie(true);
    cookieManager.removeSessionCookie();
    cookieManager.setCookie(url, cookie);
    CookieSyncManager.getInstance().sync();

由于我的Webview在一个片段中,我不得不使用getActivity()来获取上下文,我还不得不在CookieManager之前指定android.webkit.,否则它无法解析(导入java.net而不是android.webkit cookie manager)。

cookie与上面的字符串相同(在我的片段中,我必须使用以下方法恢复它:

    cookie = getArguments().getString(COOKIE);

而在我的MainActivity中,我通过以下方式发送它:

    Bundle arg = new Bundle();
    arg.putString(Fragment_Cameras.COOKIE, cookie);
    fragment.setArguments(arg);

希望这可以帮助!


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