2013-08-05 10 views
33

Sfortunatamente, c'è una moltitudine di gestori di cookie per Android. I cookie per HttpURLConnection vengono gestiti da java.net.CookieManager ei cookie per WebView vengono gestiti da android.webkit.CookieManager. Questi repository di cookie sono separati e richiedono la sincronizzazione manuale.Sincronizzazione bidirezionale per i cookie tra HttpURLConnection (java.net.CookieManager) e WebView (android.webkit.CookieManager)

La mia app utilizza sia HttpURLConnections sia mostra WebViews (è un ibrido HTML nativo). Naturalmente, voglio entrambi condividere tutti i cookie, quindi avrò una sessione trasparente.

Più in particolare:

  1. Quando un cookie viene impostato/cambiato in un HttpURLConnection, voglio il WebViews di vedere questo cambiamento pure.
  2. Quando un cookie viene impostato/modificato in una WebView, desidero che le prossime HttpURLConnections visualizzino anche questa modifica.

In poche parole: sto cercando una sincronizzazione a due vie. O ancora meglio, per far sì che entrambi usino lo stesso repository di cookie. Puoi supporre che entrambi siano attivi nello stesso tempo (come nelle diverse schede).

Domande:

  1. C'è un modo per rendere entrambi utilizzano lo stesso repository biscotto?

  2. In caso contrario, qual è la pratica consigliata per eseguire la sincronizzazione manuale? Quando esattamente dovrei sincronizzare e come?

questione connessa: Questo question affronta un problema simile, ma implementa solo a senso unico di sincronizzazione (HttpURLConnection -> WebView).

My Best Idea So Far: Ho molta voglia di evitare una sincronizzazione manuale, così ho cercato di pensare a come fare entrambi utilizzano lo stesso repository. Forse posso creare il mio core handler che estende java.net.CookieManager. Lo imposterò come gestore di cookie di base utilizzando java.net.CookieHandler.setDefault(). La sua attuazione sarà un proxy per il android.webkit.CookieManager istanza del gestore (per ogni funzione sarò semplicemente accedere al gestore webkit).

+0

Ecco la mia soluzione: http://stackoverflow.com/a/27185278/968538 spero che possa aiutare ... – Christian

risposta

59

ho implementato mia idea. In realtà è piuttosto bello. Ho creato il mio attuazione java.net.CookieManager che inoltra tutte le richieste verso i webkit WebViews' android.webkit.CookieManager. Questo significa che non è necessaria alcuna sincronizzazione e HttpURLConnection utilizza la memorizzazione dei cookie stessa come WebViews.

Classe WebkitCookieManagerProxy:

import java.io.IOException; 
import java.net.CookieManager; 
import java.net.CookiePolicy; 
import java.net.CookieStore; 
import java.net.URI; 
import java.util.Arrays; 
import java.util.List; 
import java.util.Map; 

public class WebkitCookieManagerProxy extends CookieManager 
{ 
    private android.webkit.CookieManager webkitCookieManager; 

    public WebkitCookieManagerProxy() 
    { 
     this(null, null); 
    } 

    public WebkitCookieManagerProxy(CookieStore store, CookiePolicy cookiePolicy) 
    { 
     super(null, cookiePolicy); 

     this.webkitCookieManager = android.webkit.CookieManager.getInstance(); 
    } 

    @Override 
    public void put(URI uri, Map<String, List<String>> responseHeaders) throws IOException 
    { 
     // make sure our args are valid 
     if ((uri == null) || (responseHeaders == null)) return; 

     // save our url once 
     String url = uri.toString(); 

     // go over the headers 
     for (String headerKey : responseHeaders.keySet()) 
     { 
      // ignore headers which aren't cookie related 
      if ((headerKey == null) || !(headerKey.equalsIgnoreCase("Set-Cookie2") || headerKey.equalsIgnoreCase("Set-Cookie"))) continue; 

      // process each of the headers 
      for (String headerValue : responseHeaders.get(headerKey)) 
      { 
       this.webkitCookieManager.setCookie(url, headerValue); 
      } 
     } 
    } 

    @Override 
    public Map<String, List<String>> get(URI uri, Map<String, List<String>> requestHeaders) throws IOException 
    { 
     // make sure our args are valid 
     if ((uri == null) || (requestHeaders == null)) throw new IllegalArgumentException("Argument is null"); 

     // save our url once 
     String url = uri.toString(); 

     // prepare our response 
     Map<String, List<String>> res = new java.util.HashMap<String, List<String>>(); 

     // get the cookie 
     String cookie = this.webkitCookieManager.getCookie(url); 

     // return it 
     if (cookie != null) res.put("Cookie", Arrays.asList(cookie)); 
     return res; 
    } 

    @Override 
    public CookieStore getCookieStore() 
    { 
     // we don't want anyone to work with this cookie store directly 
     throw new UnsupportedOperationException(); 
    } 
} 

e usarlo in questo modo sul tuo inizializzazione dell'applicazione:

android.webkit.CookieSyncManager.createInstance(appContext); 
// unrelated, just make sure cookies are generally allowed 
android.webkit.CookieManager.getInstance().setAcceptCookie(true); 

// magic starts here 
WebkitCookieManagerProxy coreCookieManager = new WebkitCookieManagerProxy(null, java.net.CookiePolicy.ACCEPT_ALL); 
java.net.CookieHandler.setDefault(coreCookieManager); 

Testing

Il mio spettacolo test iniziali questo sta funzionandobene. Vedo i cookie condivisi tra WebViews e HttpURLConnection. Spero di non avere problemi. Se provi questo e scopri qualsiasi problema, per favore commenta.

+4

Questa risposta è oro! – Kuno

+0

Questo metodo mi ha anche permesso di aggirare alcuni problemi con java.net.CookieManager. Un sito Web era cookie di impostazioni con un dominio leggermente modificato e il .net CookieManager non stava collaborando. Questa soluzione ha risolto questo. – thepenguin77

+0

Si sta passando 'CookiePolicy' come parametro al costruttore sovrascritto. Hai effettivamente trovato un modo per fare in modo che andinoide 'CookieManager' usi questa politica o non ti interessi alla politica fino ad ora? – ohcibi