Sincronización bidireccional para cookies entre HttpURLConnection(java.net.CookieManager) y WebView(android.webkit.CookieManager)
android-webview (1)
Implementé mi propia idea. En realidad es bastante genial. Creé mi propia implementación de java.net.CookieManager
que reenvía todas las solicitudes al webkit de WebView, android.webkit.CookieManager
. Esto significa que no se requiere sincronización y HttpURLConnection utiliza el mismo almacenamiento de cookies que WebViews.
Clase 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();
}
}
Y úsela haciendo esto en la inicialización de su aplicación:
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);
Pruebas
Mi prueba inicial muestra que esto está funcionando bien. Veo cookies compartidas entre WebViews y HttpURLConnection. Espero no tener problemas. Si prueba esto y descubre cualquier problema, por favor coméntelo.
Desafortunadamente, hay una gran cantidad de administradores de cookies para Android. Las cookies para HttpURLConnection
son mantenidas por java.net.CookieManager
y las cookies para WebView
son mantenidas por android.webkit.CookieManager
. Estos repositorios de cookies están separados y requieren sincronización manual.
Mi aplicación utiliza HttpURLConnections
y muestra WebViews
(es un híbrido HTML nativo). Naturalmente, quiero que ambos compartan todas las cookies, así que tendré una sesión transparente en todas partes.
Más específicamente:
- Cuando se establece / cambia una cookie en un HttpURLConnection, quiero que WebViews vea este cambio también.
- Cuando se establece / cambia una cookie en un WebView, quiero que las próximas HttpURLConnections también vean este cambio.
En pocas palabras: estoy buscando una sincronización bidireccional. O mejor aún, que ambos usen el mismo repositorio de cookies. Puede suponer que ambos están activos al mismo tiempo (como en pestañas diferentes).
Preguntas:
¿Hay alguna manera de hacer que ambos usen el mismo depósito de cookies?
Si no, ¿cuál es la práctica recomendada para hacer la sincronización manual? ¿Cuándo exactamente debería sincronizar y cómo?
Pregunta relacionada: Esta question aborda un problema similar, pero solo implementa la sincronización en un sentido (HttpURLConnection -> WebView).
Mi mejor idea hasta ahora: realmente quiero evitar una sincronización manual, así que traté de pensar cómo hacer que ambos usen el mismo repositorio. Tal vez pueda crear mi propio controlador central que amplíe java.net.CookieManager
. Lo estableceré como el controlador de cookies principal utilizando java.net.CookieHandler.setDefault()
. Su implementación será un proxy para la instancia del controlador android.webkit.CookieManager
(para cada función, simplemente accederé al administrador de webkit).