2

Android拓展okhttp3.Cookie实现Cookie管理(缓存、持久化、移除...)

 3 years ago
source link: http://www.lzhpo.com/article/158
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

默认的okhttp3.Cookie没有实现序列化和无参构造器,序列化报错:

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `okhttp3.Cookie` (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)

SerializableOkHttpCookies

import java.io.IOException;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.io.Serializable;import okhttp3.Cookie;/** * - 将Cookie对象输出为ObjectStream * - 将ObjectStream序列化成Cookie对象 * * @author Zhaopo Liu */public class SerializableOkHttpCookies implements Serializable {    private transient final Cookie cookies;    private transient Cookie clientCookies;    public SerializableOkHttpCookies(Cookie cookies) {        this.cookies = cookies;    }    public Cookie getCookies() {        Cookie bestCookies = cookies;        if (clientCookies != null) {            bestCookies = clientCookies;        }        return bestCookies;    }    private void writeObject(ObjectOutputStream out) throws IOException {        out.writeObject(cookies.name());        out.writeObject(cookies.value());        out.writeLong(cookies.expiresAt());        out.writeObject(cookies.domain());        out.writeObject(cookies.path());        out.writeBoolean(cookies.secure());        out.writeBoolean(cookies.httpOnly());        out.writeBoolean(cookies.hostOnly());        out.writeBoolean(cookies.persistent());    }    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {        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;        clientCookies =builder.build();    }}

PersistentCookieStore

import android.content.Context;import android.content.SharedPreferences;import android.text.TextUtils;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.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Locale;import java.util.Map;import java.util.concurrent.ConcurrentHashMap;import okhttp3.Cookie;import okhttp3.HttpUrl;/** * 根据一定的规则去缓存或者获取Cookie * * @author Zhaopo Liu */public class PersistentCookieStore {    private static final String LOG_TAG = "PersistentCookieStore";    private static final String COOKIE_PREFS = "Cookies_Prefs";    private final Map<String, ConcurrentHashMap<String, Cookie>> cookies;    private final SharedPreferences cookiePrefs;    public PersistentCookieStore(Context context) {        cookiePrefs = context.getSharedPreferences(COOKIE_PREFS, 0);        cookies = new HashMap<>();        // 将持久化的cookies缓存到内存中,即 map cookies        Map<String, ?> prefsMap = cookiePrefs.getAll();        for (Map.Entry<String, ?> entry : prefsMap.entrySet()) {            String[] cookieNames = TextUtils.split((String) entry.getValue(), ",");            for (String name : cookieNames) {                String encodedCookie = cookiePrefs.getString(name, null);                if (encodedCookie != null) {                    Cookie decodedCookie = decodeCookie(encodedCookie);                    if (decodedCookie != null) {                        if (!cookies.containsKey(entry.getKey())) {                            cookies.put(entry.getKey(), new ConcurrentHashMap<String, Cookie>());                        }                        cookies.get(entry.getKey()).put(name, decodedCookie);                    }                }            }        }    }    protected String getCookieToken(Cookie cookie) {        return cookie.name() + "@" + cookie.domain();    }    public void add(HttpUrl url, Cookie cookie) {        String name = getCookieToken(cookie);        // 将cookies缓存到内存中,如果缓存过期,就重置此cookie        if (!cookie.persistent()) {            if (!cookies.containsKey(url.host())) {                cookies.put(url.host(), new ConcurrentHashMap<>());            }            cookies.get(url.host()).put(name, cookie);        } else {            if (cookies.containsKey(url.host())) {                cookies.get(url.host()).remove(name);            }        }        // 将cookies持久化到本地        SharedPreferences.Editor prefsWriter = cookiePrefs.edit();        prefsWriter.putString(url.host(), TextUtils.join(",", cookies.get(url.host()).keySet()));        prefsWriter.putString(name, encodeCookie(new SerializableOkHttpCookies(cookie)));        prefsWriter.apply();    }    public List<Cookie> get(HttpUrl url) {        ArrayList<Cookie> ret = new ArrayList<>();        if (cookies.containsKey(url.host()))            ret.addAll(cookies.get(url.host()).values());        return ret;    }    public boolean removeAll() {        SharedPreferences.Editor prefsWriter = cookiePrefs.edit();        prefsWriter.clear();        prefsWriter.apply();        cookies.clear();        return true;    }    public boolean remove(HttpUrl url, Cookie cookie) {        String name = getCookieToken(cookie);        if (cookies.containsKey(url.host()) && cookies.get(url.host()).containsKey(name)) {            cookies.get(url.host()).remove(name);            SharedPreferences.Editor prefsWriter = cookiePrefs.edit();            if (cookiePrefs.contains(name)) {                prefsWriter.remove(name);            }            prefsWriter.putString(url.host(), TextUtils.join(",", cookies.get(url.host()).keySet()));            prefsWriter.apply();            return true;        } else {            return false;        }    }    public List<Cookie> getCookies() {        ArrayList<Cookie> ret = new ArrayList<>();        for (String key : cookies.keySet())            ret.addAll(cookies.get(key).values());        return ret;    }    /**     * cookies 序列化成 string     *     * @param cookie 要序列化的cookie     * @return 序列化之后的string     */    protected String encodeCookie(SerializableOkHttpCookies 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());    }    /**     * 将字符串反序列化成cookies     *     * @param cookieString cookies string     * @return cookie object     */    protected Cookie decodeCookie(String cookieString) {        byte[] bytes = hexStringToByteArray(cookieString);        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);        Cookie cookie = null;        try {            ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);            cookie = ((SerializableOkHttpCookies) objectInputStream.readObject()).getCookies();        } catch (IOException e) {            Log.d(LOG_TAG, "IOException in decodeCookie", e);        } catch (ClassNotFoundException e) {            Log.d(LOG_TAG, "ClassNotFoundException in decodeCookie", e);        }        return cookie;    }    /**     * 二进制数组转十六进制字符串     *     * @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);    }    /**     * 十六进制字符串转二进制数组     *     * @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;    }}

CookiesManager

package com.withive.power_grid.api.cookie;import com.withive.power_grid.manager.AppManager;import java.util.List;import okhttp3.Cookie;import okhttp3.CookieJar;import okhttp3.HttpUrl;/** * 拓展CookieJar * * @author Zhaopo Liu */public class CookiesManager implements CookieJar {    private final PersistentCookieStore cookieStore = new PersistentCookieStore(            AppManager.getInstance().getTopActivity().getApplicationContext());    @Override    public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {        if (cookies != null && cookies.size() > 0) {            for (Cookie item : cookies) {                cookieStore.add(url, item);            }        }    }    @Override    public List<Cookie> loadForRequest(HttpUrl url) {        List<Cookie> cookies = cookieStore.get(url);        return cookies;    }}

如何使用?

// 设置cookieJar即可.cookieJar(new CookiesManager());
import com.withive.power_grid.api.cookie.CookiesManager;import com.withive.power_grid.utils.JsonHelper;import okhttp3.Interceptor;import okhttp3.OkHttpClient;import okhttp3.logging.HttpLoggingInterceptor;import okhttp3.logging.HttpLoggingInterceptor.Level;import retrofit2.Retrofit;import retrofit2.adapter.rxjava3.RxJava3CallAdapterFactory;import retrofit2.converter.jackson.JacksonConverterFactory;import retrofit2.converter.scalars.ScalarsConverterFactory;public class ApiHelper {    private static final String API_SERVICE_URL = "http://Ip:Port";    private static Retrofit retrofit;    static {        OkHttpClient.Builder httpClientBuilder = new OkHttpClient().newBuilder();        // 请求参数拦截器        Interceptor logging = new HttpLoggingInterceptor()                .setLevel(Level.BODY);        httpClientBuilder                .addInterceptor(logging)                .cookieJar(new CookiesManager()); // 使用拓展的CookieJar        retrofit = new Retrofit.Builder()                .client(httpClientBuilder.build())                .baseUrl(API_SERVICE_URL)                .addConverterFactory(ScalarsConverterFactory.create())                .addConverterFactory(JacksonConverterFactory.create(JsonHelper.getMapper()))                .addCallAdapterFactory(RxJava3CallAdapterFactory.create())                .build();    }    public static <T> T getService(Class<T> service) {        return retrofit.create(service);    }}

如何退出?

// 清除所有cookiePersistentCookieStore persistentCookieStore = new PersistentCookieStore(this);persistentCookieStore.removeAll();

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK