android-cooike的使用

参考:
Android端实现Cookie机制
android-CookieHandler、CookieManager

Java SE 提供了一个主要的类来实现这一功能,java.NET.CookieHandler还有一些其他的辅助类和接口:
java.net.CookieManager,
java.Net.CookiePolicy,
java.net.CookieStore,
java.net.HttpCookie.

java.net.CookieHandler类部分源码:

//抽象类
public abstract class CookieHandler {

    private static CookieHandler cookieHandler;

    public synchronized static CookieHandler getDefault() {
        SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            sm.checkPermission(SecurityConstants.GET_COOKIEHANDLER_PERMISSION);
        }
        return cookieHandler;
    }

    public synchronized static void setDefault(CookieHandler cHandler) {
        SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            sm.checkPermission(SecurityConstants.SET_COOKIEHANDLER_PERMISSION);
        }
        cookieHandler = cHandler;
    }

java.net.CookieManager类部分源码:

//继承CookieHandler
public class CookieManager extends CookieHandler
{
    private CookiePolicy policyCallback;
    private CookieStore cookieJar = null;

    public CookieManager(CookieStore store, CookiePolicy cookiePolicy)
    {
        // use default cookie policy if not specify one
        policyCallback = (cookiePolicy == null) ? CookiePolicy.ACCEPT_ORIGINAL_SERVER: cookiePolicy;

        // if not specify CookieStore to use, use default one
        if (store == null) {
            cookieJar = new InMemoryCookieStore();
        } else {
            cookieJar = store;
        }
    }
}

一、开启Cookie存储

Android自身所带的HttpUrlConnection方法是默认不开启Cookie存储的。
不过我们可以用java提供的几个类来在Android中实现:可以先在所有请求之前声明:

        //CookieManager构造方法:
        //      第一个参数CookieStore:表示了一个用来存储cookies的地方
        //          null:使用默认的CookieStore:即class InMemoryCookieStore implements CookieStore,内存存储
        //      第二个参数CookiePolicy:表示了一个用来接收Cookie的规则
        //          CookiePolicy.ACCEPT_ORIGINAL_SERVER 只接收来自对应Server的cookies.
        //          CookiePolicy.ACCEPT_ALL 接收所有Cookies.
        //          CookiePolicy.ACCEPT_NONE 不接收Cookies.
java.net.CookieHandler.setDefault(new java.net.CookieManager(null, CookiePolicy.ACCEPT_ALL));

开启此开关后,每次请求的Set-Cookie信息都会被CookieManager处理。

CookieManager又会使用第一个参数传入的CookieStore来处理Cookie的存储问题,因为此处传入了null,
系统会默认调用一个基于CookieStore实现的CookieStoreImpl类来处理Cookie的存储,这个类的只有基于内存的存储,当进程被杀死后,下次再进入应用,保存的Cookie信息就会丢失。
所以我们需要基于CookieStore这个接口实现一个具有内存和本地双存储机制的Cookie存储类。

什么是持久化的和非持久化的Cookies
我们可以将cookies分成两类:
(1) 持久化的cookies
(2) 非持久化的cookies
持久化的cookies:这可以被称为永久性的cookies,它被存储在客户端的硬盘内,直到它们失效。持久化的cookies应该被设置一个失效时间。有时,它们会一直存在直到用户删除它们。持久化的cookies通常被用来为某个系统收集一个用户的标识信息。
非持久化cookies:也可以被称之为临时性的cookies。如果没有定义失效时间,那么cookie将会被存储在浏览器的内存中。我上面展示的例子就是一个非持久的cookies。
修改一个持久化的cookies与一个非持久化的cookies并没有什么不同。它们唯一的区别是——持久化的cookies有一个失效时间的设置。

可以参考:
Fran Montiel实现的PersistentCookieStore 类:
https://gist.github.com/franmontiel/ed12a2295566b7076161

保存cookie有两种方式一种是数据库,另一种是SharedPreferences,其中http://blog.csdn.NET/junjieking/article/details/7658551 是使用数据库来保存的

参考:Android持久化保存cookie

二、添加cookie到请求头

当解决了Cookie的存储后,我们就需要考虑以后我们的每次请求需要在请求的消息头中加入Cookie字段。
以上用CookieStore存储下来的Cookie信息都会被保存成HttpCookie形式的信息。我们可以提取CookieStore中的信息并组合。


StringBuilder cookieBuilder = new StringBuilder();
String divider = "";
for (HttpCookie cookie : getCookies()) {
    cookieBuilder.append(divider);
    divider = ";";
    cookieBuilder.append(cookie.getName());
    cookieBuilder.append("=");
    cookieBuilder.append(cookie.getValue());
}
cookieString = cookieBuilder.toString();

然后把这个cookieString在以后的请求中加入到请求头中,如果你用HttpUrlConnection,你就可以

httpUrlConnection.setRequestProperty("Cookie",cookieString);

java.net.HttpCookie 类部分源码:

package java.net;

import java.util.List;
import java.util.StringTokenizer;
import java.util.NoSuchElementException;
import java.text.SimpleDateFormat;
import java.util.TimeZone;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Date;

import java.lang.NullPointerException;  // for javadoc
import java.util.Locale;
import java.util.Objects;

// ----- BEGIN android -----
import java.util.Set;
import java.util.HashSet;
// ----- END android -----

/**
 * An HttpCookie object represents an http cookie, which carries state
 * information between server and user agent. Cookie is widely adopted
 * to create stateful sessions.
 *
 * <p>There are 3 http cookie specifications:
 * <blockquote>
 *   Netscape draft<br>
 *   RFC 2109 - <a href="http://www.ietf.org/rfc/rfc2109.txt">
 * <i>http://www.ietf.org/rfc/rfc2109.txt</i></a><br>
 *   RFC 2965 - <a href="http://www.ietf.org/rfc/rfc2965.txt">
 * <i>http://www.ietf.org/rfc/rfc2965.txt</i></a>
 * </blockquote>
 *
 * <p>HttpCookie class can accept all these 3 forms of syntax.
 */
public final class HttpCookie implements Cloneable {
    // ----- BEGIN android -----
    private static final Set<String> RESERVED_NAMES = new HashSet<String>();

    static {
        RESERVED_NAMES.add("comment");    //           RFC 2109  RFC 2965  RFC 6265
        RESERVED_NAMES.add("commenturl"); //                     RFC 2965  RFC 6265
        RESERVED_NAMES.add("discard");    //                     RFC 2965  RFC 6265
        RESERVED_NAMES.add("domain");     // Netscape  RFC 2109  RFC 2965  RFC 6265
        RESERVED_NAMES.add("expires");    // Netscape
        RESERVED_NAMES.add("httponly");   //                               RFC 6265
        RESERVED_NAMES.add("max-age");    //           RFC 2109  RFC 2965  RFC 6265
        RESERVED_NAMES.add("path");       // Netscape  RFC 2109  RFC 2965  RFC 6265
        RESERVED_NAMES.add("port");       //                     RFC 2965  RFC 6265
        RESERVED_NAMES.add("secure");     // Netscape  RFC 2109  RFC 2965  RFC 6265
        RESERVED_NAMES.add("version");    //           RFC 2109  RFC 2965  RFC 6265
    }
    // ----- END android -----

    /* ---------------- Fields -------------- */

    //
    // The value of the cookie itself.
    //

    private String name;        // NAME= ... "$Name" style is reserved
    private String value;       // value of NAME

    //
    // Attributes encoded in the header's cookie fields.
    //

    private String comment;     // Comment=VALUE ... describes cookie's use
    private String commentURL;  // CommentURL="http URL" ... describes cookie's use
    private boolean toDiscard;  // Discard ... discard cookie unconditionally
    private String domain;      // Domain=VALUE ... domain that sees cookie
    private long maxAge = MAX_AGE_UNSPECIFIED;  // Max-Age=VALUE ... cookies auto-expire
    private String path;        // Path=VALUE ... URLs that see the cookie
    private String portlist;    // Port[="portlist"] ... the port cookie may be returned to
    private boolean secure;     // Secure ... e.g. use SSL
    private boolean httpOnly;   // HttpOnly ... i.e. not accessible to scripts
    private int version = 1;    // Version=1 ... RFC 2965 style
}

三、webview共享cooike

如果你需要让应用中打开的WebView页面也能共享使用Cookie,则需要使用android.webkit.CookieManager类来设置,简单式例代码如下。

注意,第一个参数要使用链接的host部分。这样让web端的不同页面也可以共享这些cookie。


for (HttpCookie cookie : getCookies()) {
   CookieManager.getInstance().setCookie(Uri.parse(url).getHost(), cookie.toString());
}

android.webkit.CookieManager 类源码:

package android.webkit;

import android.annotation.SystemApi;
import android.net.WebAddress;

/**
 * Manages the cookies used by an application's {@link WebView} instances.
 * Cookies are manipulated according to RFC2109.
 */
public abstract class CookieManager {

    @Override
    protected Object clone() throws CloneNotSupportedException {
        throw new CloneNotSupportedException("doesn't implement Cloneable");
    }

    /**
     * Gets the singleton CookieManager instance.
     *
     * @return the singleton CookieManager instance
     */
    public static synchronized CookieManager getInstance() {
        return WebViewFactory.getProvider().getCookieManager();
    }

    /**
     * Sets whether the application's {@link WebView} instances should send and
     * accept cookies.
     * By default this is set to true and the WebView accepts cookies.
     * <p>
     * When this is true
     * {@link CookieManager#setAcceptThirdPartyCookies setAcceptThirdPartyCookies} and
     * {@link CookieManager#setAcceptFileSchemeCookies setAcceptFileSchemeCookies}
     * can be used to control the policy for those specific types of cookie.
     *
     * @param accept whether {@link WebView} instances should send and accept
     *               cookies
     */
    public abstract void setAcceptCookie(boolean accept);

    /**
     * Gets whether the application's {@link WebView} instances send and accept
     * cookies.
     *
     * @return true if {@link WebView} instances send and accept cookies
     */
    public abstract boolean acceptCookie();

   /**
     * Sets whether the {@link WebView} should allow third party cookies to be set.
     * Allowing third party cookies is a per WebView policy and can be set
     * differently on different WebView instances.
     * <p>
     * Apps that target {@link android.os.Build.VERSION_CODES#KITKAT} or below
     * default to allowing third party cookies. Apps targeting
     * {@link android.os.Build.VERSION_CODES#LOLLIPOP} or later default to disallowing
     * third party cookies.
     *
     * @param webview the {@link WebView} instance to set the cookie policy on
     * @param accept whether the {@link WebView} instance should accept
     *               third party cookies
     */
    public abstract void setAcceptThirdPartyCookies(WebView webview, boolean accept);

    /**
     * Gets whether the {@link WebView} should allow third party cookies to be set.
     *
     * @param webview the {@link WebView} instance to get the cookie policy for
     * @return true if the {@link WebView} accepts third party cookies
     */
    public abstract boolean acceptThirdPartyCookies(WebView webview);

    /**
     * Sets a cookie for the given URL. Any existing cookie with the same host,
     * path and name will be replaced with the new cookie. The cookie being set
     * will be ignored if it is expired.
     *
     * @param url the URL for which the cookie is to be set
     * @param value the cookie as a string, using the format of the 'Set-Cookie'
     *              HTTP response header
     */
    public abstract void setCookie(String url, String value);

    /**
     * Sets a cookie for the given URL. Any existing cookie with the same host,
     * path and name will be replaced with the new cookie. The cookie being set
     * will be ignored if it is expired.
     * <p>
     * This method is asynchronous.
     * If a {@link ValueCallback} is provided,
     * {@link ValueCallback#onReceiveValue(T) onReceiveValue()} will be called on the current
     * thread's {@link android.os.Looper} once the operation is complete.
     * The value provided to the callback indicates whether the cookie was set successfully.
     * You can pass {@code null} as the callback if you don't need to know when the operation
     * completes or whether it succeeded, and in this case it is safe to call the method from a
     * thread without a Looper.
     *
     * @param url the URL for which the cookie is to be set
     * @param value the cookie as a string, using the format of the 'Set-Cookie'
     *              HTTP response header
     * @param callback a callback to be executed when the cookie has been set
     */
    public abstract void setCookie(String url, String value, ValueCallback<Boolean> callback);

    /**
     * Gets the cookies for the given URL.
     *
     * @param url the URL for which the cookies are requested
     * @return value the cookies as a string, using the format of the 'Cookie'
     *               HTTP request header
     */
    public abstract String getCookie(String url);

    /**
     * See {@link #getCookie(String)}.
     *
     * @param url the URL for which the cookies are requested
     * @param privateBrowsing whether to use the private browsing cookie jar
     * @return value the cookies as a string, using the format of the 'Cookie'
     *               HTTP request header
     * @hide Used by Browser and by WebViewProvider implementations.
     */
    @SystemApi
    public abstract String getCookie(String url, boolean privateBrowsing);

    /**
     * Gets cookie(s) for a given uri so that it can be set to "cookie:" in http
     * request header.
     *
     * @param uri the WebAddress for which the cookies are requested
     * @return value the cookies as a string, using the format of the 'Cookie'
     *               HTTP request header
     * @hide Used by RequestHandle and by WebViewProvider implementations.
     */
    @SystemApi
    public synchronized String getCookie(WebAddress uri) {
        return getCookie(uri.toString());
    }

    /**
     * Removes all session cookies, which are cookies without an expiration
     * date.
     * @deprecated use {@link #removeSessionCookies(ValueCallback)} instead.
     */
    public abstract void removeSessionCookie();

    /**
     * Removes all session cookies, which are cookies without an expiration
     * date.
     * <p>
     * This method is asynchronous.
     * If a {@link ValueCallback} is provided,
     * {@link ValueCallback#onReceiveValue(T) onReceiveValue()} will be called on the current
     * thread's {@link android.os.Looper} once the operation is complete.
     * The value provided to the callback indicates whether any cookies were removed.
     * You can pass {@code null} as the callback if you don't need to know when the operation
     * completes or whether any cookie were removed, and in this case it is safe to call the
     * method from a thread without a Looper.
     * @param callback a callback which is executed when the session cookies have been removed
     */
    public abstract void removeSessionCookies(ValueCallback<Boolean> callback);

    /**
     * Removes all cookies.
     * @deprecated Use {@link #removeAllCookies(ValueCallback)} instead.
     */
    @Deprecated
    public abstract void removeAllCookie();

    /**
     * Removes all cookies.
     * <p>
     * This method is asynchronous.
     * If a {@link ValueCallback} is provided,
     * {@link ValueCallback#onReceiveValue(T) onReceiveValue()} will be called on the current
     * thread's {@link android.os.Looper} once the operation is complete.
     * The value provided to the callback indicates whether any cookies were removed.
     * You can pass {@code null} as the callback if you don't need to know when the operation
     * completes or whether any cookies were removed, and in this case it is safe to call the
     * method from a thread without a Looper.
     * @param callback a callback which is executed when the cookies have been removed
     */
    public abstract void removeAllCookies(ValueCallback<Boolean> callback);

    public abstract boolean hasCookies();

    @SystemApi
    public abstract boolean hasCookies(boolean privateBrowsing);

    @Deprecated
    public abstract void removeExpiredCookie();

    public abstract void flush();

    public static boolean allowFileSchemeCookies() {
        return getInstance().allowFileSchemeCookiesImpl();
    }

    @SystemApi
    protected abstract boolean allowFileSchemeCookiesImpl();

    public static void setAcceptFileSchemeCookies(boolean accept) {
        getInstance().setAcceptFileSchemeCookiesImpl(accept);
    }

    @SystemApi
    protected abstract void setAcceptFileSchemeCookiesImpl(boolean accept);
}

参考:Android 控件WebView设置Cookie
Android端实现Cookie机制

工具类:

package com.dch.dai.utils;

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;

import com.dch.dai.DchApplication;

import android.webkit.CookieSyncManager;

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

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

    public CookieManagerUtil(CookieStore store, CookiePolicy cookiePolicy)
    {
        super(null, cookiePolicy);//net包

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

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

    public void removeCookie() {//清除cooike
        try {
            CookieSyncManager.createInstance(DchApplication.getContext()); 
            if (this.webkitCookieManager == null) {
                this.webkitCookieManager = android.webkit.CookieManager.getInstance();
            }
            this.webkitCookieManager.removeAllCookie();
            CookieSyncManager.getInstance().sync();
        } catch (Exception e) {

        }       
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值