package com.doumee.lib_coremodel.http.cookie.store; 
 | 
  
 | 
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.Collection; 
 | 
import java.util.HashMap; 
 | 
import java.util.List; 
 | 
import java.util.Locale; 
 | 
import java.util.Map; 
 | 
import java.util.Set; 
 | 
import java.util.concurrent.ConcurrentHashMap; 
 | 
  
 | 
import okhttp3.Cookie; 
 | 
import okhttp3.HttpUrl; 
 | 
  
 | 
/** 
 | 
 * Created by goldze on 2017/5/13. 
 | 
 */ 
 | 
public class PersistentCookieStore implements CookieStore { 
 | 
  
 | 
    private static final String LOG_TAG = "PersistentCookieStore"; 
 | 
    //cookie使用prefs保存 
 | 
    private static final String COOKIE_PREFS = "habit_cookie"; 
 | 
    //cookie持久化的统一前缀 
 | 
    private static final String COOKIE_NAME_PREFIX = "cookie_"; 
 | 
  
 | 
    private final HashMap<String, ConcurrentHashMap<String, Cookie>> cookies; 
 | 
    private final SharedPreferences cookiePrefs; 
 | 
  
 | 
    public PersistentCookieStore(Context context) { 
 | 
        cookiePrefs = context.getSharedPreferences(COOKIE_PREFS, Context.MODE_PRIVATE); 
 | 
        cookies = new HashMap<>(); 
 | 
  
 | 
        //将持久化的cookies缓存到内存中,数据结构为 Map<Url.host, Map<Cookie.name, Cookie>> 
 | 
        Map<String, ?> prefsMap = cookiePrefs.getAll(); 
 | 
        for (Map.Entry<String, ?> 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 = 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); 
 | 
                        } 
 | 
                    } 
 | 
                } 
 | 
            } 
 | 
        } 
 | 
    } 
 | 
  
 | 
    private String getCookieToken(Cookie cookie) { 
 | 
        return cookie.name() + "@" + cookie.domain(); 
 | 
    } 
 | 
  
 | 
    /** 当前cookie是否过期 */ 
 | 
    private static boolean isCookieExpired(Cookie cookie) { 
 | 
        return cookie.expiresAt() < System.currentTimeMillis(); 
 | 
    } 
 | 
  
 | 
    /** 根据当前url获取所有需要的cookie,只返回没有过期的cookie */ 
 | 
    @Override 
 | 
    public List<Cookie> loadCookie(HttpUrl url) { 
 | 
        ArrayList<Cookie> ret = new ArrayList<>(); 
 | 
        if (cookies.containsKey(url.host())) { 
 | 
            Collection<Cookie> 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 void saveCookie(HttpUrl url, List<Cookie> urlCookies) { 
 | 
        if (!cookies.containsKey(url.host())) { 
 | 
            cookies.put(url.host(), new ConcurrentHashMap<String, Cookie>()); 
 | 
        } 
 | 
        for (Cookie cookie : urlCookies) { 
 | 
            //当前cookie是否过期 
 | 
            if (isCookieExpired(cookie)) { 
 | 
                removeCookie(url, cookie); 
 | 
            } else { 
 | 
                saveCookie(url, cookie, getCookieToken(cookie)); 
 | 
            } 
 | 
        } 
 | 
    } 
 | 
  
 | 
    @Override 
 | 
    public void saveCookie(HttpUrl url, Cookie cookie) { 
 | 
        if (!cookies.containsKey(url.host())) { 
 | 
            cookies.put(url.host(), new ConcurrentHashMap<String, Cookie>()); 
 | 
        } 
 | 
        //当前cookie是否过期 
 | 
        if (isCookieExpired(cookie)) { 
 | 
            removeCookie(url, cookie); 
 | 
        } else { 
 | 
            saveCookie(url, cookie, getCookieToken(cookie)); 
 | 
        } 
 | 
    } 
 | 
  
 | 
    /** 
 | 
     * 保存cookie,并将cookies持久化到本地,数据结构为 
 | 
     * Url.host -> Cookie1.name,Cookie2.name,Cookie3.name 
 | 
     * cookie_Cookie1.name -> CookieString 
 | 
     * cookie_Cookie2.name -> CookieString 
 | 
     */ 
 | 
    private void saveCookie(HttpUrl url, Cookie cookie, String name) { 
 | 
        //内存缓存 
 | 
        cookies.get(url.host()).put(name, cookie); 
 | 
        //文件缓存 
 | 
        SharedPreferences.Editor prefsWriter = cookiePrefs.edit(); 
 | 
        prefsWriter.putString(url.host(), TextUtils.join(",", cookies.get(url.host()).keySet())); 
 | 
        prefsWriter.putString(COOKIE_NAME_PREFIX + name, encodeCookie(new SerializableHttpCookie(cookie))); 
 | 
        prefsWriter.apply(); 
 | 
    } 
 | 
  
 | 
    /** 根据url移除当前的cookie */ 
 | 
    @Override 
 | 
    public boolean removeCookie(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(COOKIE_NAME_PREFIX + name)) { 
 | 
                prefsWriter.remove(COOKIE_NAME_PREFIX + name); 
 | 
            } 
 | 
            prefsWriter.putString(url.host(), TextUtils.join(",", cookies.get(url.host()).keySet())); 
 | 
            prefsWriter.apply(); 
 | 
            return true; 
 | 
        } else { 
 | 
            return false; 
 | 
        } 
 | 
    } 
 | 
  
 | 
    @Override 
 | 
    public boolean removeCookie(HttpUrl url) { 
 | 
        if (cookies.containsKey(url.host())) { 
 | 
            //文件移除 
 | 
            Set<String> cookieNames = cookies.get(url.host()).keySet(); 
 | 
            SharedPreferences.Editor prefsWriter = cookiePrefs.edit(); 
 | 
            for (String cookieName : cookieNames) { 
 | 
                if (cookiePrefs.contains(COOKIE_NAME_PREFIX + cookieName)) { 
 | 
                    prefsWriter.remove(COOKIE_NAME_PREFIX + cookieName); 
 | 
                } 
 | 
            } 
 | 
            prefsWriter.remove(url.host()).apply(); 
 | 
            //内存移除 
 | 
            cookies.remove(url.host()); 
 | 
            return true; 
 | 
        } else { 
 | 
            return false; 
 | 
        } 
 | 
    } 
 | 
  
 | 
    @Override 
 | 
    public boolean removeAllCookie() { 
 | 
        SharedPreferences.Editor prefsWriter = cookiePrefs.edit(); 
 | 
        prefsWriter.clear().apply(); 
 | 
        cookies.clear(); 
 | 
        return true; 
 | 
    } 
 | 
  
 | 
    /** 获取所有的cookie */ 
 | 
    @Override 
 | 
    public List<Cookie> getAllCookie() { 
 | 
        List<Cookie> ret = new ArrayList<>(); 
 | 
        for (String key : cookies.keySet()){ 
 | 
            ret.addAll(cookies.get(key).values()); 
 | 
        } 
 | 
        return ret; 
 | 
    } 
 | 
  
 | 
    @Override 
 | 
    public List<Cookie> getCookie(HttpUrl url) { 
 | 
        List<Cookie> ret = new ArrayList<>(); 
 | 
        Map<String, Cookie> mapCookie = cookies.get(url.host()); 
 | 
        if (mapCookie != null) { 
 | 
            ret.addAll(mapCookie.values()); 
 | 
        } 
 | 
        return ret; 
 | 
    } 
 | 
  
 | 
    /** 
 | 
     * cookies 序列化成 string 
 | 
     * 
 | 
     * @param cookie 要序列化的cookie 
 | 
     * @return 序列化之后的string 
 | 
     */ 
 | 
    private 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()); 
 | 
    } 
 | 
  
 | 
    /** 
 | 
     * 将字符串反序列化成cookies 
 | 
     * 
 | 
     * @param cookieString cookies string 
 | 
     * @return cookie object 
 | 
     */ 
 | 
    private Cookie decodeCookie(String cookieString) { 
 | 
        byte[] bytes = hexStringToByteArray(cookieString); 
 | 
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes); 
 | 
        Cookie 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; 
 | 
    } 
 | 
  
 | 
    /** 
 | 
     * 二进制数组转十六进制字符串 
 | 
     * 
 | 
     * @param bytes byte array to be converted 
 | 
     * @return string containing hex values 
 | 
     */ 
 | 
    private 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 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; 
 | 
    } 
 | 
} 
 |