以下有两种方法
第一种方法是针对Volley来实现的,这种方法比较简单,但是对于有多重类型的Request必须都要按照这种方式来处理,耦合度比较高。
第二种方法只要设置一次,之后所有的请求都会携带cookie。建议采用第二种方法
Request
对象是一个抽象类,其中有两个抽象方法。
abstract protected Response parseNetworkResponse(NetworkResponse response)
abstract protected void deliverResponse(T response) 不需要操作该方法
这两个方法经常被我们用来实现自定义的Request对象,而如果要实现Cookie的自定义这两个方法我们只需要使用到 第一个方法 parseNetworkResponse
和 public Map
方法。
import com.android.volley.AuthFailureError;
import com.android.volley.NetworkResponse;
import com.android.volley.Request;
import com.android.volley.Response;
import java.util.Map;
public class CustomStringRequest extends Request<String>{
public CustomStringRequest(String url, Response.ErrorListener listener) {
super(url, listener);
}
public CustomStringRequest(int method, String url, Response.ErrorListener listener) {
super(method, url, listener);
}
@Override
protected Response parseNetworkResponse(NetworkResponse response) {
//在这里可以的到 response 对象, 然后从response的header中获取cookie信息
if (headers.containsKey(SET_COOKIE_KEY)
&& headers.get(SET_COOKIE_KEY).startsWith(SESSION_COOKIE)) {
String cookie = headers.get(SET_COOKIE_KEY);
if (cookie.length() > 0) {
String[] splitCookie = cookie.split(";");
String[] splitSessionId = splitCookie[0].split("=");
cookie = splitSessionId[1];
//将得到的cookie存储到Sharepreference中
Editor prefEditor = _preferences.edit();
prefEditor.putString(SESSION_COOKIE, cookie);
prefEditor.commit();
}
}
//------------------end-----------------------
//加上自己的其他逻辑代码
return null;
}
@Override
public Map getHeaders() throws AuthFailureError {
Map headers = super.getHeaders();
if (headers == null
|| headers.equals(Collections.emptyMap())) {
headers = new HashMap();
}
//从Sharepreference中获取到cookie,并把cookie添加到header中
String sessionId = _preferences.getString(SESSION_COOKIE, "");
if (sessionId.length() > 0) {
StringBuilder builder = new StringBuilder();
builder.append(SESSION_COOKIE);
builder.append("=");
builder.append(sessionId);
if (headers.containsKey(COOKIE_KEY)) {
builder.append("; ");
builder.append(headers.get(COOKIE_KEY));
}
headers.put(COOKIE_KEY, builder.toString());
}
//-----------------end-------------------------
return headers;
//return super.getHeaders();
}
@Override
protected void deliverResponse(String response) {
}
}
通过在 parseNetworkResponse
和 getHeaders
方法的自定义,就可以实现Request请求携带Cookie参数。
CookieManager
会帮我们管理本地Java应用的cookie,我们只需要实现自定义 CookieStore
就能实现持久化的Cookie
。
关于CookieManager
的介绍和 CookieStore
的自定义可以参考另外一篇文章。Android中Cookie的使用
晚上也会有一些实现好了的PersistCookieStore
比如 这个
下面给出一个已经实现的自定义的持久化CookieStore
public class PersistentCookieStore implements CookieStore {
private static final String LOG_TAG = "PersistentCookieStore";
private static final String COOKIE_PREFS = "CookiePrefsFile";
private static final String COOKIE_NAME_PREFIX = "cookie_";
private final HashMap> cookies;
private final SharedPreferences cookiePrefs;
/**
* Construct a persistent cookie store.
*
* @param context Context to attach cookie store to
*/
public PersistentCookieStore(Context context) {
cookiePrefs = context.getSharedPreferences(COOKIE_PREFS, 0);
cookies = new HashMap>();
// Load any previously stored cookies into the store
Map prefsMap = cookiePrefs.getAll();
for(Map.Entry entry : prefsMap.entrySet()) {
if (((String)entry.getValue()) != null && !((String)entry.getValue()).startsWith(COOKIE_NAME_PREFIX)) {
String[] cookieNames = TextUtils.split((String)entry.getValue(), ",");
for (String name : cookieNames) {
String encodedCookie = cookiePrefs.getString(COOKIE_NAME_PREFIX + name, null);
if (encodedCookie != null) {
HttpCookie decodedCookie = decodeCookie(encodedCookie);
if (decodedCookie != null) {
if(!cookies.containsKey(entry.getKey()))
cookies.put(entry.getKey(), new ConcurrentHashMap());
cookies.get(entry.getKey()).put(name, decodedCookie);
}
}
}
}
}
}
@Override
public void add(URI uri, HttpCookie cookie) {
String name = getCookieToken(uri, cookie);
// Save cookie into local store, or remove if expired
if (!cookie.hasExpired()) {
if(!cookies.containsKey(uri.getHost()))
cookies.put(uri.getHost(), new ConcurrentHashMap());
cookies.get(uri.getHost()).put(name, cookie);
} else {
if(cookies.containsKey(uri.toString()))
cookies.get(uri.getHost()).remove(name);
}
// Save cookie into persistent store
SharedPreferences.Editor prefsWriter = cookiePrefs.edit();
prefsWriter.putString(uri.getHost(), TextUtils.join(",", cookies.get(uri.getHost()).keySet()));
prefsWriter.putString(COOKIE_NAME_PREFIX + name, encodeCookie(new SerializableHttpCookie(cookie)));
prefsWriter.apply();
}
protected String getCookieToken(URI uri, HttpCookie cookie) {
return cookie.getName() + cookie.getDomain();
}
@Override
public List get(URI uri) {
ArrayList ret = new ArrayList();
if(cookies.containsKey(uri.getHost()))
ret.addAll(cookies.get(uri.getHost()).values());
return ret;
}
@Override
public boolean removeAll() {
SharedPreferences.Editor prefsWriter = cookiePrefs.edit();
prefsWriter.clear();
prefsWriter.apply();
cookies.clear();
return true;
}
@Override
public boolean remove(URI uri, HttpCookie cookie) {
String name = getCookieToken(uri, cookie);
if(cookies.containsKey(uri.getHost()) && cookies.get(uri.getHost()).containsKey(name)) {
cookies.get(uri.getHost()).remove(name);
SharedPreferences.Editor prefsWriter = cookiePrefs.edit();
if(cookiePrefs.contains(COOKIE_NAME_PREFIX + name)) {
prefsWriter.remove(COOKIE_NAME_PREFIX + name);
}
prefsWriter.putString(uri.getHost(), TextUtils.join(",", cookies.get(uri.getHost()).keySet()));
prefsWriter.apply();
return true;
} else {
return false;
}
}
@Override
public List getCookies() {
ArrayList ret = new ArrayList();
for (String key : cookies.keySet())
ret.addAll(cookies.get(key).values());
return ret;
}
@Override
public List getURIs() {
ArrayList ret = new ArrayList();
for (String key : cookies.keySet())
try {
ret.add(new URI(key));
} catch (URISyntaxException e) {
e.printStackTrace();
}
return ret;
}
/**
* Serializes Cookie object into String
*
* @param cookie cookie to be encoded, can be null
* @return cookie encoded as String
*/
protected String encodeCookie(SerializableHttpCookie cookie) {
if (cookie == null)
return null;
ByteArrayOutputStream os = new ByteArrayOutputStream();
try {
ObjectOutputStream outputStream = new ObjectOutputStream(os);
outputStream.writeObject(cookie);
} catch (IOException e) {
L.d(LOG_TAG, "IOException in encodeCookie " + e.toString());
return null;
}
return byteArrayToHexString(os.toByteArray());
}
/**
* Returns cookie decoded from cookie string
*
* @param cookieString string of cookie as returned from http request
* @return decoded cookie or null if exception occured
*/
protected HttpCookie decodeCookie(String cookieString) {
byte[] bytes = hexStringToByteArray(cookieString);
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
HttpCookie cookie = null;
try {
ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
cookie = ((SerializableHttpCookie) objectInputStream.readObject()).getCookie();
} catch (IOException e) {
L.d(LOG_TAG, "IOException in decodeCookie " + e.toString());
} catch (ClassNotFoundException e) {
L.d(LOG_TAG, "ClassNotFoundException in decodeCookie " + e.toString());
}
return cookie;
}
/**
* Using some super basic byte array <-> hex conversions so we don't have to rely on any
* large Base64 libraries. Can be overridden if you like!
*
* @param bytes byte array to be converted
* @return string containing hex values
*/
protected String byteArrayToHexString(byte[] bytes) {
StringBuilder sb = new StringBuilder(bytes.length * 2);
for (byte element : bytes) {
int v = element & 0xff;
if (v < 16) {
sb.append('0');
}
sb.append(Integer.toHexString(v));
}
return sb.toString().toUpperCase(Locale.US);
}
/**
* Converts hex values from strings to byte arra
*
* @param hexString string of hex-encoded values
* @return decoded byte array
*/
protected byte[] hexStringToByteArray(String hexString) {
int len = hexString.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(hexString.charAt(i), 16) << 4) + Character.digit(hexString.charAt(i + 1), 16));
}
return data;
}
}
这个CookieStore
内部也是通过Sharepreference来实现cookie的持久化的。
现在定制好了自己的CookieStore,如何来进行设置然后使其生效呢?
//init for api client sync cookie
manager = new CookieManager(
new PersistentCookieStore(context),
CookiePolicy.ACCEPT_ALL);
CookieHandler.setDefault(manager);
只要在网络请求之前调用这个方法,就可以将自定义的CookieStore
设置到CookieManager
中,CookieManager
会在之后的HTTP请求中自动的帮我们处理response中cookie。
建议中Application启动的时候调用上面的设置代码。
CookiePolicy
也是可以进行自定义的,详细可以参考另外一边文章。Android中Cookie的使用