Android中在使用OkHttp这个库的时候。有时候须要持久化Cookie,那么怎么实现呢。OkHttp的内部源代码过于复杂,不进行深究。这里仅仅看当中的HttpEngineer里面的部分源代码,在发起请求以及请求结束都会调用这个类的几个方法。

我们先看networkRequest方法。在里面通过client.getCookieHandler()函数获得了CookieHandler对象。通过该对象拿到cookie并设置到请求头里,请求结束后取得响应后通过networkResponse.headers()函数将请求头获得传入receiveHeaders函数,并将取得的cookie存入getCookieHandler得到的一个CookieHandler对象中去

This client doesn't specify a default {@code Accept} header because it
* doesn't know what content types the application is interested in.
*/
private Request networkRequest(Request request) throws IOException {
Request.Builder result = request.newBuilder(); //此处省略n行代码...... CookieHandler cookieHandler = client.getCookieHandler();
if (cookieHandler != null) {
// Capture the request headers added so far so that they can be offered to the CookieHandler.
// This is mostly to stay close to the RI; it is unlikely any of the headers above would
// affect cookie choice besides "Host".
Map> headers = OkHeaders.toMultimap(result.build().headers(), null); Map> cookies = cookieHandler.get(request.uri(), headers); // Add any new cookies to the request.
OkHeaders.addCookies(result, cookies);
} //此处省略n行代码...... return result.build();
}" data-snippet-id="ext.4df17b386793c68468195a690c917859" data-snippet-saved="false" data-csrftoken="bFkHGE1O-cy7WY9D6w70F6qK9YUKZHLynI5g" data-codota-status="done">/**
* Populates request with defaults and cookies.
*
* <p>This client doesn't specify a default {@code Accept} header because it
* doesn't know what content types the application is interested in.
*/
private Request networkRequest(Request request) throws IOException {
Request.Builder result = request.newBuilder(); //此处省略n行代码...... CookieHandler cookieHandler = client.getCookieHandler();
if (cookieHandler != null) {
// Capture the request headers added so far so that they can be offered to the CookieHandler.
// This is mostly to stay close to the RI; it is unlikely any of the headers above would
// affect cookie choice besides "Host".
Map<String, List<String>> headers = OkHeaders.toMultimap(result.build().headers(), null); Map<String, List<String>> cookies = cookieHandler.get(request.uri(), headers); // Add any new cookies to the request.
OkHeaders.addCookies(result, cookies);
} //此处省略n行代码...... return result.build();
}
public void readResponse() throws IOException {
//此处省略n行代码...... receiveHeaders(networkResponse.headers()); //此处省略n行代码......
}
public void receiveHeaders(Headers headers) throws IOException {
CookieHandler cookieHandler = client.getCookieHandler();
if (cookieHandler != null) {
cookieHandler.put(userRequest.uri(), OkHeaders.toMultimap(headers, null));
}
}

而这个CookieHandler对象是OkHttpClient类中的一个属性,提供了getter和setter方法,默认的构造函数OkHttpClient client = new OkHttpClient();不会创建这个CookieHandler对象。如果我们传入了这个对象。那么OkHttp自然会进行cookie的自己主动管理了。

private CookieHandler cookieHandler;
public OkHttpClient setCookieHandler(CookieHandler cookieHandler) {
this.cookieHandler = cookieHandler;
return this;
} public CookieHandler getCookieHandler() {
return cookieHandler;
}

那么如果我们将CookieHandler对象传入

OkHttpClient client = new OkHttpClient();
client.setCookieHandler(CookieHandler cookieHanlder);

那么,如今关键是怎样去实现这个CookieHandler 对象。CookieManager是CookieHandler 的一个子类,其构造函数 public CookieManager(CookieStore store, CookiePolicy cookiePolicy)须要传入两个參数,CookieStore 是一个接口,因此我们实现CookieStore接口中的抽象方法。就可以实现这个CookieHandler 对象。

參考android-async-http这个库,它具有cookie的自己主动管理功能。主要我们參考当中的两个类

參考以上两个类并做适当改动,得到了例如以下两个类,他们的功能就是将cookie保持在SharedPreferences中。

package com.kltz88.okhttp.cookie;

/**
* User:lizhangqu(513163535@qq.com)
* Date:2015-07-13
* Time: 17:31
*/
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.net.HttpCookie; public class SerializableHttpCookie implements Serializable {
private static final long serialVersionUID = 6374381323722046732L; private transient final HttpCookie cookie;
private transient HttpCookie clientCookie; public SerializableHttpCookie(HttpCookie cookie) {
this.cookie = cookie;
} public HttpCookie getCookie() {
HttpCookie bestCookie = cookie;
if (clientCookie != null) {
bestCookie = clientCookie;
}
return bestCookie;
} private void writeObject(ObjectOutputStream out) throws IOException {
out.writeObject(cookie.getName());
out.writeObject(cookie.getValue());
out.writeObject(cookie.getComment());
out.writeObject(cookie.getCommentURL());
out.writeObject(cookie.getDomain());
out.writeLong(cookie.getMaxAge());
out.writeObject(cookie.getPath());
out.writeObject(cookie.getPortlist());
out.writeInt(cookie.getVersion());
out.writeBoolean(cookie.getSecure());
out.writeBoolean(cookie.getDiscard());
} private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
String name = (String) in.readObject();
String value = (String) in.readObject();
clientCookie = new HttpCookie(name, value);
clientCookie.setComment((String) in.readObject());
clientCookie.setCommentURL((String) in.readObject());
clientCookie.setDomain((String) in.readObject());
clientCookie.setMaxAge(in.readLong());
clientCookie.setPath((String) in.readObject());
clientCookie.setPortlist((String) in.readObject());
clientCookie.setVersion(in.readInt());
clientCookie.setSecure(in.readBoolean());
clientCookie.setDiscard(in.readBoolean());
}
}
> 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.commit();
} 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.commit();
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.commit(); 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) {
Log.d(LOG_TAG, "IOException in encodeCookie", e);
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) {
Log.d(LOG_TAG, "IOException in decodeCookie", e);
} catch (ClassNotFoundException e) {
Log.d(LOG_TAG, "ClassNotFoundException in decodeCookie", e);
} return cookie;
} /**
* Using some super basic byte array &lt;-&gt; 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 package com.kltz88.okhttp.cookie; /**
* User:lizhangqu(513163535@qq.com)
* Date:2015-07-13
* Time: 17:31
*/
import android.content.Context;
import android.content.SharedPreferences;
import android.text.TextUtils;
import android.util.Log; import java.io.*;
import java.net.CookieStore;
import java.net.HttpCookie;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap; /**
* A persistent cookie store which implements the Apache HttpClient CookieStore interface.
* Cookies are stored and will persist on the user's device between application sessions since they
* are serialized and stored in SharedPreferences. Instances of this class are
* designed to be used with AsyncHttpClient#setCookieStore, but can also be used with a
* regular old apache HttpClient/HttpContext if you prefer.
*/
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<String, ConcurrentHashMap<String, HttpCookie>> 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<String, ConcurrentHashMap<String, HttpCookie>>(); // Load any previously stored cookies into the store
Map<String, ?> prefsMap = cookiePrefs.getAll();
for(Map.Entry<String, ? > 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<String, HttpCookie>());
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<String, HttpCookie>());
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.commit();
} protected String getCookieToken(URI uri, HttpCookie cookie) {
return cookie.getName() + cookie.getDomain();
} @Override
public List<HttpCookie> get(URI uri) {
ArrayList<HttpCookie> ret = new ArrayList<HttpCookie>();
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.commit();
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.commit(); return true;
} else {
return false;
}
} @Override
public List<HttpCookie> getCookies() {
ArrayList<HttpCookie> ret = new ArrayList<HttpCookie>();
for (String key : cookies.keySet())
ret.addAll(cookies.get(key).values()); return ret;
} @Override
public List<URI> getURIs() {
ArrayList<URI> ret = new ArrayList<URI>();
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) {
Log.d(LOG_TAG, "IOException in encodeCookie", e);
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) {
Log.d(LOG_TAG, "IOException in decodeCookie", e);
} catch (ClassNotFoundException e) {
Log.d(LOG_TAG, "ClassNotFoundException in decodeCookie", e);
} return cookie;
} /**
* Using some super basic byte array &lt;-&gt; 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;
} }

使用的时候。在发起请求前对CookieHandler进行设置,兴许的cookie全都是自己主动管理,无需你关心cookie的保存于读取

OkHttpClient client = new OkHttpClient();

client.setCookieHandler(new CookieManager(
new PersistentCookieStore(getApplicationContext()),
CookiePolicy.ACCEPT_ALL));

这样,实现模拟登录,抓取一些数据就方便非常多了。再也不用手动处理cookie了。

Android OkHttp的Cookie自己主动化管理的更多相关文章

  1. Android自己主动化測试解决方式

    如今,已经有大量的Android自己主动化測试架构或工具可供我们使用,当中包含:Activity Instrumentation, MonkeyRunner, Robotium, 以及Robolect ...

  2. Android自己主动化測试之Monkeyrunner用法及实例

    眼下android SDK里自带的现成的測试工具有monkey 和 monkeyrunner两个.大家别看这俩兄弟名字相像,但事实上是完全然全不同的两个工具,应用在不同的測试领域.总的来说,monke ...

  3. Android Monkey自己主动化測试

    前言 假设你做Android开发,还没有使用过Monkey进行測试,那么今天看到这篇文章,希望能解决你Android測试中的一些问题.起码能帮你省点測试的时间而且发现很多其它的问题. Monkey简单 ...

  4. 使用Adt自带的工具进行Android自己主动化測试(三)

    在这个系列的上一篇文章中,我们介绍了MonkeyRunner,并提到假设依据坐标来编写自己主动化脚本的话存在着一定的局限性(点击文末"阅读原文"能够打开这篇文章查看).这篇文章将进 ...

  5. Android 自己主动化測试(3)&lt;monkeyrunner&gt; 依据ID查找对象&amp;touch&amp;type (python)

    我在之前的两篇文章中用java来实现过 Android 自己主动化測试(1)怎样安装和卸载一个应用(java).Android 自己主动化測试(2)依据ID查找对象(java). 可是本质上都是用mo ...

  6. Android自己主动化构建之Ant多渠道打包实践(下)

    前言 上一篇(Android自己主动化构建之Ant多渠道打包实践(上))已经介绍了Android的apk是怎样构建的,本篇博客继续Ant打包的实践过程. 集成友盟统计SDK 这里以友盟统计为例,对各个 ...

  7. 【金阳光測试】基于控件核心技术探讨---Android自己主动化系列(2)---2013年5月

    第一讲分享了下安卓自己主动化一些概况和一些自己主动化框架现状和技术可以解决什么样的问题. 这次课就深入到android世界里面.遨游.翱翔.深入了解自己主动化測试核心技术. 搞过编程开发的同学听到in ...

  8. 【金阳光測试】大话Android自己主动化測试--Android自己主动化系列(1)--金阳光于2013年4月份

    Android自己主动化測试框架和工具在四年多的发展日趋成熟. 从五年前的第一代自己主动化架构演进到眼下第四代(本系列讲座第7篇后将具体剖析第三代和第四代自己主动化框架)从曾经最早谷歌推崇的monke ...

  9. 自己主动化的在程序中显示SVN版本号

    有时候会有这种情况,策划拿着应用过来提一个bug,但我们却不好确定策划的手机上装的应用相应的是那个代码版本号. 为了解决问题.我们希望能在应用上显示出当前应用所相应的代码版本号,即svn版本号. 构想 ...

随机推荐

  1. C语言中的基础知识变量探讨

    C语言中的变量是编程的基础,主要有四个要素:存储类型.存储大小.存储名称和存储地址. 一.变量的要素: 1.存储类型:主要表明名变量存储的特征,主要有auto.extern.static和regist ...

  2. i2c 协议解析【转】

    转自:http://blog.csdn.net/g_salamander/article/details/8016698 版权声明:本文为博主原创文章,未经博主允许不得转载. 1.基本概念 主机    ...

  3. Android下设置CPU核心数和频率

    现在的Android手机双核.四核变得非常普遍,同时CPU频率经常轻松上2G,功耗肯定会显著增加.而大多数的ARM架构的CPU采用的是对称多处理(SMP)的方式处理多CPU.这就意味着每个CPU核心是 ...

  4. EOJ 3.30 A. 打工时不可能打工的【贪心】

    [链接]:https://acm.ecnu.edu.cn/contest/59/problem/A/ A. 打工时不可能打工的 Time limit per test: 2.0 seconds Mem ...

  5. IE6~IE7 bugs

    本来想写一篇关于 IE bugs 的总结的,但是发现 IE 的 bugs 一般都存在IE5,IE6,IE7上,这都是很古老的浏览器.而且这些 bugs 测试起来相当麻烦,IEtester和 IE10 ...

  6. SQL SERVER 技术博客 外文

    https://www.sqlskills.com/blogs/paul/capturing-io-latencies-period-time/ http://www.sqlskills.com/bl ...

  7. kindeditor编辑器,获取textarea值

    在获取textarea值的时候,从数据库读出来的值都能获取到,但是新输入的值就得不到,只要是新输入的都得不到值 答案: 我昨天刚用kindeditor,我是使用ajaxForm提交表单的在360浏览器 ...

  8. Flutter开发记录part2

    (1)文本超出折叠:child: Text('跑马灯dddd的范德萨范德萨放多少范德萨范德萨范德萨范德萨范德萨发',maxLines: 1,overflow: TextOverflow.ellipsi ...

  9. Spark原理小总结

    1.spark是什么? 快速,通用,可扩展的分布式计算引擎 2.弹性分布式数据集RDD RDD(Resilient Distributed Dataset)叫做分布式数据集,是Spark中最基本的数据 ...

  10. setTag和findViewByTag的使用具体解释

    在使用ListView或者GridView的时候. 假设想要在Aciviry中获取到Item中的子View,比較频繁的使用是:getChildAt(int position): 之前自己差点儿不会去使 ...