2012-09-10 97 views
21

我已經開始使用推薦的HTTPUrlConnection並從DefaultHTTPClient移開。我一直無法粘合在一起的一件事是使用持久性cookie存儲。我想簡單地將自定義Cookie處理程序/管理器附加到我的連接以存儲Cookie。 Android文檔並沒有太大的幫助,因爲它包含了兩行cookies的主題。如何在使用HTTPUrlConnection時堅持cookie?

我以前一直在使用LoopJ的PersistentCookieStore,並且工作得很好。

關於如何在Android中設置持久性Cookie存儲的任何想法,我可以附加到我的HTTPUrlConnection上,以便自動保存和檢索cookie?

感謝

回答

23

其我花了幾個小時,但我設法建立一個自定義的cookie存儲自己。

你必須這樣做是爲了將這個附加:

public class application extends Application { 
    @Override 
    public void onCreate() { 
     super.onCreate(); 
     CookieManager cmrCookieMan = new CookieManager(new MyCookieStore(this.objContext), CookiePolicy.ACCEPT_ALL); 
     CookieHandler.setDefault(cmrCookieMan); 
     } 
    } 

這裏的實際存儲:

/* 
* This is a custom cookie storage for the application. This 
* will store all the cookies to the shared preferences so that it persists 
* across application restarts. 
*/ 
class MyCookieStore implements CookieStore { 

    /* 
    * The memory storage of the cookies 
    */ 
    private Map<URI, List<HttpCookie>> mapCookies = new HashMap<URI, List<HttpCookie>>(); 
    /* 
    * The instance of the shared preferences 
    */ 
    private final SharedPreferences spePreferences; 

    /* 
    * @see java.net.CookieStore#add(java.net.URI, java.net.HttpCookie) 
    */ 
    public void add(URI uri, HttpCookie cookie) { 

     System.out.println("add"); 
     System.out.println(cookie.toString()); 

     List<HttpCookie> cookies = mapCookies.get(uri); 
     if (cookies == null) { 
      cookies = new ArrayList<HttpCookie>(); 
      mapCookies.put(uri, cookies); 
     } 
     cookies.add(cookie); 

     Editor ediWriter = spePreferences.edit(); 
     HashSet<String> setCookies = new HashSet<String>(); 
     setCookies.add(cookie.toString()); 
     ediWriter.putStringSet(uri.toString(), spePreferences.getStringSet(uri.toString(), setCookies)); 
     ediWriter.commit(); 

    } 

    /* 
    * Constructor 
    * 
    * @param ctxContext the context of the Activity 
    */ 
    @SuppressWarnings("unchecked") 
    public MyCookieStore(Context ctxContext) { 

     spePreferences = ctxContext.getSharedPreferences("CookiePrefsFile", 0); 
     Map<String, ?> prefsMap = spePreferences.getAll(); 

     for(Map.Entry<String, ?> entry : prefsMap.entrySet()) { 

      for (String strCookie : (HashSet<String>) entry.getValue()) { 

       if (!mapCookies.containsKey(entry.getKey())) { 

        List<HttpCookie> lstCookies = new ArrayList<HttpCookie>(); 
        lstCookies.addAll(HttpCookie.parse(strCookie)); 

        try { 

         mapCookies.put(new URI(entry.getKey()), lstCookies); 

        } catch (URISyntaxException e) { 

         e.printStackTrace(); 

        } 

       } else { 

        List<HttpCookie> lstCookies = mapCookies.get(entry.getKey()); 
        lstCookies.addAll(HttpCookie.parse(strCookie)); 

        try { 

         mapCookies.put(new URI(entry.getKey()), lstCookies); 

        } catch (URISyntaxException e) { 

         e.printStackTrace(); 

        } 

       } 

       System.out.println(entry.getKey() + ": " + strCookie); 

      } 

     } 

    } 

    /* 
    * @see java.net.CookieStore#get(java.net.URI) 
    */ 
    public List<HttpCookie> get(URI uri) { 

     List<HttpCookie> lstCookies = mapCookies.get(uri); 

     if (lstCookies == null) 
      mapCookies.put(uri, new ArrayList<HttpCookie>()); 

     return mapCookies.get(uri); 

    } 

    /* 
    * @see java.net.CookieStore#removeAll() 
    */ 
    public boolean removeAll() { 

     mapCookies.clear(); 
     return true; 

    }   

    /* 
    * @see java.net.CookieStore#getCookies() 
    */ 
    public List<HttpCookie> getCookies() { 

     Collection<List<HttpCookie>> values = mapCookies.values(); 

     List<HttpCookie> result = new ArrayList<HttpCookie>(); 
     for (List<HttpCookie> value : values) {     
      result.addAll(value);     
     } 

     return result; 

    } 

    /* 
    * @see java.net.CookieStore#getURIs() 
    */ 
    public List<URI> getURIs() { 

     Set<URI> keys = mapCookies.keySet(); 
     return new ArrayList<URI>(keys); 

    } 

    /* 
    * @see java.net.CookieStore#remove(java.net.URI, java.net.HttpCookie) 
    */ 
    public boolean remove(URI uri, HttpCookie cookie) { 

     List<HttpCookie> lstCookies = mapCookies.get(uri); 

     if (lstCookies == null) 
      return false; 

     return lstCookies.remove(cookie); 

    } 

} 
+0

這還沒有被徹底的測試,但正如我走,我會進行編輯。請提出改進​​建議。 –

+25

有時候我想知道我是否瘋狂地期待SDK中包含永久cookie這樣基本的東西......如果我能提出任何改進建議,我一定會回覆。 –

+8

在這個實現中,它會將cookies添加到它們來自的確切URI,這意味着它們不會被髮送到該主機上的任何其他URI。我建議使用僅包含主機名的新URI來替換傳遞的URI,以使其行爲符合預期。 例如:在目前的實施中,如果您訪問yourdomain.com/pageOne.htm,那麼當您訪問yourdomain.com/pageTwo.htm時,將不會發送任何Cookie集,因爲這些URI不同。該實現應該將URI參數修剪到yourdomain.com以使其表現爲(I)預期。 – Keith

0

我用上面的答案,但改變了我的add方法下面來處理多個來自相同URI的Cookie(具有GAE的此Cookie商店將會話令牌和記憶令牌視爲來自相同URI的兩個單獨的Cookie,出於某種原因):

public void add(URI uri, HttpCookie cookie) { 


    List<HttpCookie> cookies = mapCookies.get(uri); 
    if (cookies == null) { 
     cookies = new ArrayList<HttpCookie>(); 
     mapCookies.put(uri, cookies); 
    } 
    cookies.add(cookie); 

    Editor ediWriter = spePreferences.edit(); 
    HashSet<String> setCookies = new HashSet<String>(); 
    setCookies.add(cookie.toString()); 
    HashSet<String> emptyCookieSet = new HashSet<String>(); 
    if(spePreferences.contains(uri.toString())){ 
     emptyCookieSet = (HashSet<String>) spePreferences.getStringSet(uri.toString(), emptyCookieSet); 
     if(!emptyCookieSet.isEmpty()){ 
      if(!emptyCookieSet.contains(cookie.toString())){ 
      emptyCookieSet.add(cookie.toString()); 
      ediWriter.putStringSet(uri.toString(), emptyCookieSet); 
      } 
     } 
    } 
    else{ 
     ediWriter.putStringSet(uri.toString(), setCookies); 
    } 
    ediWriter.commit(); 
} 

以及訪問和創建一個聯合餅乾:

MyCookieStore store = new MyCookieStore(this.context, false); 
String cookie = TextUtils.join(",", store.get(new URI(URLString))); 

附加到連接:

URL urlToRequest = new URL(stringPath); 
HttpURLConnection urlConnection = (HttpURLConnection) urlToRequest.openConnection(); 
urlConnection.setRequestProperty("Cookie", cookie); 
1

有很多定製的CookieStore實現一些基本的問題。

第一個問題是HttpCookie序列化成字符串 - HttpCookie.toString()方法不被接受,因爲它的結果不適合HttpCookie.parse(String header)方法。

第二個問題:大多數CookieStore實現(例如這裏的https://codereview.stackexchange.com/questions/61494/persistent-cookie-support-using-volley-and-httpurlconnection)沒有考慮到HttpCookie.maxAge字段的格式。這是實況cookie的幾秒鐘。但是,如果你堅持自己的價值,並在經過一段時間不加以解決,那將是錯誤的。您必須將maxAge字段轉換爲類似「expire_at」的字符,並將其保留,而不是maxAge。

1

在下面的鏈接中籤出實施。它通過主機名像原始的java.net.InMemoryCookieStore實現那樣保存cookie。

除此之外,它還包含一個SerializableHttpCookie,可以將完整的HashMap序列化到SharedPreferences中。

https://gist.github.com/jacobtabak/78e226673d5a6a4c4367