Android okhttp cookie持久化方法

cookie的作用

当app需要保持用户登陆状态等,这个时候我们通常就要进行对cookie的管理来实现。如果你使用的是okhttp网络请求,那么就可以直接对cookie进行持久化管理。

使用okhttp3进行cookie的持久化处理

主要原理是使用okhttp3中新增的Cookiejar这个接口,通过这个接口我们可以直接进行cookie的持久化管理,代码如下:

  • 首先实现cookieJar,里面有一个管理cookie的公共接口CookieStore,代码如下:

    import java.net.CookieStore;
    import java.util.List;
    
    import okhttp3.Cookie;
    import okhttp3.CookieJar;
    import okhttp3.HttpUrl;
    
    /**
    * @author dmrfcoder
    * @date 2018/8/28
    */
    
    public class CookieJarImpl implements CookieJar {
    
    
      public interface CookieStore {
    
          /**
           * 保存url对应所有cookie
           */
          void saveCookie(HttpUrl url, List cookie);
    
          /**
           * 保存url对应所有cookie
           */
          void saveCookie(HttpUrl url, Cookie cookie);
    
          /**
           * 加载url所有的cookie
           */
          List loadCookie(HttpUrl url);
    
          /**
           * 获取当前所有保存的cookie
           */
          List getAllCookie();
    
          /**
           * 获取当前url对应的所有的cookie
           */
          List getCookie(HttpUrl url);
    
          /**
           * 根据url和cookie移除对应的cookie
           */
          boolean removeCookie(HttpUrl url, Cookie cookie);
    
          /**
           * 根据url移除所有的cookie
           */
          boolean removeCookie(HttpUrl url);
    
          /**
           * 移除所有的cookie
           */
          boolean removeAllCookie();
      }
    
    
      private CookieStore cookieStore;
    
      public CookieJarImpl(CookieStore cookieStore) {
          if (cookieStore == null) {
              throw new IllegalArgumentException("cookieStore can not be null!");
          }
          this.cookieStore = cookieStore;
      }
    
      @Override
      public synchronized void saveFromResponse(HttpUrl url, List cookies) {
          cookieStore.saveCookie(url, cookies);
      }
    
      @Override
      public synchronized List loadForRequest(HttpUrl url) {
          return cookieStore.loadCookie(url);
      }
    
      public CookieStore getCookieStore() {
          return cookieStore;
      }
    }
    
    
  • 实现cookie的序列化:

    
    import android.content.ContentValues;
    import android.database.Cursor;
    import android.util.Log;
    
    import java.io.ByteArrayInputStream;
    import java.io.ByteArrayOutputStream;
    import java.io.IOException;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    import java.io.Serializable;
    import java.util.Locale;
    
    import okhttp3.Cookie;
    
    /**
    * @author dmrfcoder
    * @date 2018/8/28
    */
    
    public class SerializableCookie implements Serializable {
      private static final long serialVersionUID = 6374381323722046732L;
    
      public static final String HOST = "host";
      public static final String NAME = "name";
      public static final String DOMAIN = "domain";
      public static final String COOKIE = "cookie";
    
      public String host;
      public String name;
      public String domain;
      private transient Cookie cookie;
      private transient Cookie clientCookie;
    
      public SerializableCookie(String host, Cookie cookie) {
          this.cookie = cookie;
          this.host = host;
          this.name = cookie.name();
          this.domain = cookie.domain();
      }
    
      public Cookie getCookie() {
          Cookie bestCookie = cookie;
          if (clientCookie != null) {
              bestCookie = clientCookie;
          }
          return bestCookie;
      }
    
      private void writeObject(ObjectOutputStream out) throws IOException {
          out.defaultWriteObject();
          out.writeObject(cookie.name());
          out.writeObject(cookie.value());
          out.writeLong(cookie.expiresAt());
          out.writeObject(cookie.domain());
          out.writeObject(cookie.path());
          out.writeBoolean(cookie.secure());
          out.writeBoolean(cookie.httpOnly());
          out.writeBoolean(cookie.hostOnly());
          out.writeBoolean(cookie.persistent());
      }
    
      private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
          in.defaultReadObject();
          String name = (String) in.readObject();
          String value = (String) in.readObject();
          long expiresAt = in.readLong();
          String domain = (String) in.readObject();
          String path = (String) in.readObject();
          boolean secure = in.readBoolean();
          boolean httpOnly = in.readBoolean();
          boolean hostOnly = in.readBoolean();
          boolean persistent = in.readBoolean();
          Cookie.Builder builder = new Cookie.Builder();
          builder = builder.name(name);
          builder = builder.value(value);
          builder = builder.expiresAt(expiresAt);
          builder = hostOnly ? builder.hostOnlyDomain(domain) : builder.domain(domain);
          builder = builder.path(path);
          builder = secure ? builder.secure() : builder;
          builder = httpOnly ? builder.httpOnly() : builder;
          clientCookie = builder.build();
      }
    
      public static SerializableCookie parseCursorToBean(Cursor cursor) {
          String host = cursor.getString(cursor.getColumnIndex(HOST));
          byte[] cookieBytes = cursor.getBlob(cursor.getColumnIndex(COOKIE));
          Cookie cookie = bytesToCookie(cookieBytes);
          return new SerializableCookie(host, cookie);
      }
    
      public static ContentValues getContentValues(SerializableCookie serializableCookie) {
          ContentValues values = new ContentValues();
          values.put(SerializableCookie.HOST, serializableCookie.host);
          values.put(SerializableCookie.NAME, serializableCookie.name);
          values.put(SerializableCookie.DOMAIN, serializableCookie.domain);
          values.put(SerializableCookie.COOKIE, cookieToBytes(serializableCookie.host, serializableCookie.getCookie()));
          return values;
      }
    
      /**
       * cookies 序列化成 string
       *
       * @param cookie 要序列化
       * @return 序列化之后的string
       */
      public static String encodeCookie(String host, Cookie cookie) {
          if (cookie == null) {
              return null;
          }
          byte[] cookieBytes = cookieToBytes(host, cookie);
          return byteArrayToHexString(cookieBytes);
      }
    
      public static byte[] cookieToBytes(String host, Cookie cookie) {
          SerializableCookie serializableCookie = new SerializableCookie(host, cookie);
          ByteArrayOutputStream os = new ByteArrayOutputStream();
          try {
              ObjectOutputStream outputStream = new ObjectOutputStream(os);
              outputStream.writeObject(serializableCookie);
          } catch (IOException e) {
              Log.e("cookieToBytes: ", e.toString());
              return null;
          }
          return os.toByteArray();
      }
    
      /**
       * 将字符串反序列化成cookies
       *
       * @param cookieString cookies string
       * @return cookie object
       */
      public static Cookie decodeCookie(String cookieString) {
          byte[] bytes = hexStringToByteArray(cookieString);
          return bytesToCookie(bytes);
      }
    
      public static Cookie bytesToCookie(byte[] bytes) {
          ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
          Cookie cookie = null;
          try {
              ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
              cookie = ((SerializableCookie) objectInputStream.readObject()).getCookie();
          } catch (Exception e) {
              Log.e("bytesToCookie: ", e.toString());
          }
          return cookie;
      }
    
      /**
       * 二进制数组转十六进制字符串
       *
       * @param bytes byte array to be converted
       * @return string containing hex values
       */
      private static 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);
      }
    
      /**
       * 十六进制字符串转二进制数组
       *
       * @param hexString string of hex-encoded values
       * @return decoded byte array
       */
      private static 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;
      }
    
      /**
       * host, name, domain 标识一个cookie是否唯一
       */
      @Override
      public boolean equals(Object o) {
          if (this == o) {
              return true;
          }
          if (o == null || getClass() != o.getClass()) {
              return false;
          }
    
          SerializableCookie that = (SerializableCookie) o;
    
          if (host != null ? !host.equals(that.host) : that.host != null) {
              return false;
          }
          return (name != null ? name.equals(that.name) : that.name == null) && (domain != null ? domain.equals(that.domain) : that.domain == null);
      }
    
      @Override
      public int hashCode() {
          int result = host != null ? host.hashCode() : 0;
          result = 31 * result   (name != null ? name.hashCode() : 0);
          result = 31 * result   (domain != null ? domain.hashCode() : 0);
          return result;
      }
    }
    
  • 使用 SharedPreferences 持久化存储 cookie:

    package cn.xiaojii.cashgift.bean.net;
    
    import android.content.Context;
    import android.content.SharedPreferences;
    import android.text.TextUtils;
    
    import java.util.ArrayList;
    import java.util.Collection;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    import java.util.Set;
    import java.util.concurrent.ConcurrentHashMap;
    
    import okhttp3.Cookie;
    import okhttp3.HttpUrl;
    
    /**
    * @author dmrfcoder
    * @date 2018/8/28
    */
    
    public class SPCookieStore implements CookieJarImpl.CookieStore {
    
      private static final String COOKIE_PREFS = "sp_cookie";           //cookie使用prefs保存
      private static final String COOKIE_NAME_PREFIX = "cookie_";         //cookie持久化的统一前缀
    
    
      private final Map> cookies;
      private final SharedPreferences cookiePrefs;
    
      public SPCookieStore(Context context) {
          cookiePrefs = context.getSharedPreferences(COOKIE_PREFS, Context.MODE_PRIVATE);
          cookies = new HashMap<>();
    
          //将持久化的cookies缓存到内存中,数据结构为 Map>
          Map prefsMap = cookiePrefs.getAll();
          for (Map.Entry entry : prefsMap.entrySet()) {
              if ((entry.getValue()) != null && !entry.getKey().startsWith(COOKIE_NAME_PREFIX)) {
                  //获取url对应的所有cookie的key,用","分割
                  String[] cookieNames = TextUtils.split((String) entry.getValue(), ",");
                  for (String name : cookieNames) {
                      //根据对应cookie的Key,从xml中获取cookie的真实值
                      String encodedCookie = cookiePrefs.getString(COOKIE_NAME_PREFIX   name, null);
                      if (encodedCookie != null) {
                          Cookie decodedCookie = SerializableCookie.decodeCookie(encodedCookie);
                          if (decodedCookie != null) {
                              if (!cookies.containsKey(entry.getKey())) {
                                  cookies.put(entry.getKey(), new ConcurrentHashMap());
                              }
                              cookies.get(entry.getKey()).put(name, decodedCookie);
                          }
                      }
                  }
              }
          }
      }
    
      private String getCookieToken(Cookie cookie) {
          return cookie.name()   "@"   cookie.domain();
      }
    
      /**
       * 当前cookie是否过期
       */
      private static boolean isCookieExpired(Cookie cookie) {
          return cookie.expiresAt() < System.currentTimeMillis();
      }
    
      /**
       * 将url的所有Cookie保存在本地
       */
      @Override
      public synchronized void saveCookie(HttpUrl url, List urlCookies) {
          for (Cookie cookie : urlCookies) {
              saveCookie(url, cookie);
          }
      }
    
      @Override
      public synchronized void saveCookie(HttpUrl url, Cookie cookie) {
          if (!cookies.containsKey(url.host())) {
              cookies.put(url.host(), new ConcurrentHashMap());
          }
          //当前cookie是否过期
          if (isCookieExpired(cookie)) {
              removeCookie(url, cookie);
          } else {
              saveCookie(url, cookie, getCookieToken(cookie));
          }
      }
    
      /**
       * 保存cookie,并将cookies持久化到本地
       */
      private void saveCookie(HttpUrl url, Cookie cookie, String cookieToken) {
          //内存缓存
          cookies.get(url.host()).put(cookieToken, cookie);
          //文件缓存
          SharedPreferences.Editor prefsWriter = cookiePrefs.edit();
          prefsWriter.putString(url.host(), TextUtils.join(",", cookies.get(url.host()).keySet()));
          prefsWriter.putString(COOKIE_NAME_PREFIX   cookieToken, SerializableCookie.encodeCookie(url.host(), cookie));
          prefsWriter.apply();
      }
    
      /**
       * 根据当前url获取所有需要的cookie,只返回没有过期的cookie
       */
      @Override
      public synchronized List loadCookie(HttpUrl url) {
          List ret = new ArrayList<>();
          if (!cookies.containsKey(url.host())) {
              return ret;
          }
    
          Collection urlCookies = cookies.get(url.host()).values();
          for (Cookie cookie : urlCookies) {
              if (isCookieExpired(cookie)) {
                  removeCookie(url, cookie);
              } else {
                  ret.add(cookie);
              }
          }
          return ret;
      }
    
      /**
       * 根据url移除当前的cookie
       */
      @Override
      public synchronized boolean removeCookie(HttpUrl url, Cookie cookie) {
          if (!cookies.containsKey(url.host())) {
              return false;
          }
          String cookieToken = getCookieToken(cookie);
          if (!cookies.get(url.host()).containsKey(cookieToken)) {
              return false;
          }
    
          //内存移除
          cookies.get(url.host()).remove(cookieToken);
          //文件移除
          SharedPreferences.Editor prefsWriter = cookiePrefs.edit();
          if (cookiePrefs.contains(COOKIE_NAME_PREFIX   cookieToken)) {
              prefsWriter.remove(COOKIE_NAME_PREFIX   cookieToken);
          }
          prefsWriter.putString(url.host(), TextUtils.join(",", cookies.get(url.host()).keySet()));
          prefsWriter.apply();
          return true;
      }
    
      @Override
      public synchronized boolean removeCookie(HttpUrl url) {
          if (!cookies.containsKey(url.host())) {
              return false;
          }
    
          //内存移除
          ConcurrentHashMap urlCookie = cookies.remove(url.host());
          //文件移除
          Set cookieTokens = urlCookie.keySet();
          SharedPreferences.Editor prefsWriter = cookiePrefs.edit();
          for (String cookieToken : cookieTokens) {
              if (cookiePrefs.contains(COOKIE_NAME_PREFIX   cookieToken)) {
                  prefsWriter.remove(COOKIE_NAME_PREFIX   cookieToken);
              }
          }
          prefsWriter.remove(url.host());
          prefsWriter.apply();
    
          return true;
      }
    
      @Override
      public synchronized boolean removeAllCookie() {
          //内存移除
          cookies.clear();
          //文件移除
          SharedPreferences.Editor prefsWriter = cookiePrefs.edit();
          prefsWriter.clear();
          prefsWriter.apply();
          return true;
      }
    
      /**
       * 获取所有的cookie
       */
      @Override
      public synchronized List getAllCookie() {
          List ret = new ArrayList<>();
          for (String key : cookies.keySet()) {
              ret.addAll(cookies.get(key).values());
          }
          return ret;
      }
    
      @Override
      public synchronized List getCookie(HttpUrl url) {
          List ret = new ArrayList<>();
          Map mapCookie = cookies.get(url.host());
          if (mapCookie != null) {
              ret.addAll(mapCookie.values());
          }
          return ret;
      }
    }
  • 进行取出cookie和删除cookie等公共类的封装:

    
    /**
    * @author dmrfcoder
    * @date 2018/8/28
    */
    
    import android.util.Log;
    
    import java.util.List;
    
    import cn.xiaojii.cashgift.bean.net.CookieJarImpl;
    import cn.xiaojii.cashgift.bean.net.OkManager;
    import okhttp3.Cookie;
    import okhttp3.HttpUrl;
    
    /**
    * cookie管理工具类
    * @author dmrfcoder
    */
    public class CookieUtil {
      /**
       * 获取指定URL对应的cookie
       *
       * @param baseUrl
       * @param url
       * @return
       */
      public static List cookies(String baseUrl, String url) {
          //一般手动取出cookie的目的只是交给 webview 等等,非必要情况不要自己操作
          CookieJarImpl.CookieStore cookieStore = OkManager.getInstance().getCookieJar().getCookieStore();
          HttpUrl httpUrl = HttpUrl.parse(baseUrl   url);
          List cookies = cookieStore.getCookie(httpUrl);
          Log.e("cookies: ", httpUrl.host()   "对应的cookie如下:"   cookies.toString());
          return cookies;
      }
    
      /**
       * 获取所有的cookie
       *
       * @return
       */
      public static List cookieList() {
          CookieJarImpl.CookieStore cookieStore = OkManager.getInstance().getCookieJar().getCookieStore();
          List allCookie = cookieStore.getAllCookie();
          Log.e("所有cookie如下: ", allCookie.toString());
          return allCookie;
      }
    
      public static String getCookie() {
          CookieJarImpl.CookieStore cookieStore = OkManager.getInstance().getCookieJar().getCookieStore();
          List allCookie = cookieStore.getAllCookie();
          for (int i = 0; i < allCookie.size(); i  ) {
              return allCookie.get(i).toString();
          }
          return null;
      }
    
      /**
       * 删除cookie(这里是全部删除,也可指定的地址删除)
       */
      public static void removeCookie() {
          CookieJarImpl.CookieStore cookieStore = OkManager.getInstance().getCookieJar().getCookieStore();
          cookieStore.removeAllCookie();
    
      }
    }
    
  • 最终的Okmanager类:

    import java.util.concurrent.TimeUnit;
    
    
    import okhttp3.OkHttpClient;
    
    /**
    * @author dmrfcoder
    * @date 2018/8/28
    */
    
    public class OkManager {
      public OkHttpClient getClient() {
          return client;
      }
    
      private OkHttpClient client;
      private volatile static OkManager okManager;
      private final String TAG = OkManager.class.getSimpleName();
    
      OkHttpClient.Builder httpBuilder;
    
      public OkManager() {
    
    
          //需要设置请求超时调用下面两行
          httpBuilder = new OkHttpClient.Builder();
          client = httpBuilder.readTimeout(10, TimeUnit.SECONDS)
                  .connectTimeout(10, TimeUnit.SECONDS).writeTimeout(15, TimeUnit.SECONDS) //设置超时
                  .cookieJar(new CookieJarImpl(new SPCookieStore(CashApplication.getContextObject())))
                  .build();
          //将上面的CashApplication换成你自己的Application或者传入同样性质的参数
      }
    
      /**
       * 获取全局的cookie实例
       */
      public CookieJarImpl getCookieJar() {
          return (CookieJarImpl) client.cookieJar();
      }
    
      /**
       * 采用单例获取对象
       *
       * @return
       */
      public static OkManager getInstance() {
          if (okManager == null) {
              synchronized (OkManager.class) {
                  if (okManager == null) {
                      okManager = new OkManager();
                  }
              }
          }
          return okManager;
      }
    }

    使用

    private OkHttpClient okHttpClient = OkManager.getInstance().getClient();

    然后就实现了cookie的持久化。

你可能感兴趣的:(Android)