2011-04-27 19 views
23

Estoy intentando una aplicación simple para leer en el HTML de un sitio web, y transformarla para crear una interfaz de usuario fácil de leer en Android (esta es una práctica más en Android, no para crear aplicación utilizable). El problema que tengo es persistir en la sesión de un usuario en las actividades y luego utilizar la sesión en un HttpClient una vez que se acordó.Uso de cookies en las actividades al utilizar HttpClient

Me gustaría hacer esto "Correctamente", el enfoque recomendado parece ser usar CookieManager. Sin embargo, he tenido problemas con esto. Parece que no puedo encontrar la forma "Correcta" de tomar un Cookie desde el CookieManager y usarlo en una instancia posterior de HttpClient en actividades separadas.

Al usar un CookieManager puedo guardar el Cookie y el Cookie está en el alcance de otras actividades (Vea el fragmento de código 2). No he encontrado cómo usar esto más tarde (Ver el fragmento de código 3) cuando solicito una página.

Basta de hablar, aquí hay un código. Primero mi acción de acceso y almacenamiento de cookies:

private OnClickListener loginActionListener = new OnClickListener() 
{ 
    public void onClick(View v) 
    { 
     EditText usernameTextView = (EditText) findViewById(R.id.Username); 
     EditText passwordTextView = (EditText) findViewById(R.id.Password); 
     String username = usernameTextView.getText().toString(); 
     String password = passwordTextView.getText().toString(); 

     try { 
      HttpPost postMethod = new HttpPost(URI);     
      HttpParams params = new BasicHttpParams(); 

      params.setParameter("mode", "login"); 
      params.setParameter("autologin", true); 
      params.setParameter("username", username); 
      params.setParameter("password", password); 
      postMethod.setParams(params); 

      DefaultHttpClient httpClient = new DefaultHttpClient(); 
      HttpResponse response  = httpClient.execute(postMethod); 
      List<Cookie> cookies = httpClient.getCookieStore().getCookies(); 

      if(cookies != null) 
      { 
       for(Cookie cookie : cookies) 
       { 
        String cookieString = cookie.getName() + "=" + cookie.getValue() + "; domain=" + cookie.getDomain();       
        CookieManager.getInstance().setCookie(cookie.getDomain(), cookieString); 
       } 
      } 
      CookieSyncManager.getInstance().sync(); 

      Intent intent = new Intent(v.getContext(), IndexAction.class); 
      startActivity(intent); 
    } catch (Exception e) {...} 
} 

La actividad de inicio que decide carnero para hacer la conexión del usuario o ir al índice está por debajo. Se puede ver en el código que la cookie es en su alcance y se puede leer:

public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    CookieSyncManager.createInstance(this); 

    if(CookieManager.getInstance().getCookie(URI) == null) 
    { 
     Intent intent = new Intent(this, LoginAction.class); 
     startActivity(intent); 
    } 
    else 
    { 
     Intent intent = new Intent(this, IndexAction.class); 
     startActivity(intent); 
    } 
} 

Pero desde mi código para leer la página Índice Estoy esperando que usted puede sugerir lo que me falta:

@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    CookieSyncManager.createInstance(this); 

    try 
    { 
      HttpGet getMethod = new HttpGet(URI_INDEX); 

      HttpParams params = new BasicHttpParams();       
      HttpConnectionParams.setConnectionTimeout(params, 30000); 
      HttpConnectionParams.setSoTimeout(params, 30000); 

      // This code results in a ClassCastException, I'm assuming i've found a red herring with this solution. 
      // HttpContext localContext = new BasicHttpContext();  
      // localContext.setAttribute(ClientContext.COOKIE_STORE, CookieManager.getInstance().getCookie(URI)); 

      DefaultHttpClient httpClient = new DefaultHttpClient(params); 
      HttpResponse response  = httpClient.execute(getMethod); 

      if(response.getStatusLine().getStatusCode() > 299 && response.getStatusLine().getStatusCode() < 400) 
      { 
       // Not logged in doesn't give a redirect response. Very annoying. 
      } 

      final char[] buffer = new char[0x10000]; 
      StringBuilder out = new StringBuilder(); 
      Reader in = new InputStreamReader(response.getEntity().getContent(), "UTF-8"); 
      int read = 0; 
      while (read>=0) 
      { 
       read = in.read(buffer, 0, buffer.length); 
       if (read>0) { 
       out.append(buffer, 0, read); 
       } 
      } 

      String returnString = out.toString(); 
    } catch (ClientProtocolException e) {...} 
} 

El HttpClient en execute(getMethod) no está utilizando la Cookie (comprobó esto en depuración) para volver a abrir la página. Sería genial si alguien pudiera llenar este hoyo en mi conocimiento.

Gracias de antemano.

EDITAR

Cuando se añade código comentado de nuevo en (con el cambio httpClient.execute(getMethod) método para httpClient.execute(getMethod, localContext)) esta traza strack se produce - Supuestamente porque estoy llenando el atributo ClientContext.COOKIE_STORE con un CookieString en lugar de un CookieStore :

*org.apache.http.client.protocol.RequestAddCookies.process(RequestAddCookies.java:88), org.apache.http.protocol.BasicHttpProcessor.process(BasicHttpProcessor.java:290), org.apache.http.protocol.HttpRequestExecutor.preProcess(HttpRequestExecutor.java:160), org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:401) 
org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:555), org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:487), 
com.testapp.site.name.IndexAction.onCreate(IndexAction.java:47), 
android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047), 
android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1611), 
android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1663), 
android.app.ActivityThread.access$1500(ActivityThread.java:117), 
android.app.ActivityThread$H.handleMessage(ActivityThread.java:931), 
android.os.Handler.dispatchMessage(Handler.java:99), 
android.os.Looper.loop(Looper.java:123), 
android.app.ActivityThread.main(ActivityThread.java:3683), 
java.lang.reflect.Method.invokeNative(Native Method), 
java.lang.reflect.Method.invoke(Method.java:507), 
com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839), 
com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597), 
dalvik.system.NativeStart.main(Native Method)* 
+0

¿Podría proporcionar el seguimiento de la pila de su excepción? Esta pregunta puede ayudar: http://stackoverflow.com/questions/1652850/android-webview-cookie-problem – Mikaveli

+0

Y posiblemente http://stackoverflow.com/questions/678630/how-do-i-make-an-http -request-using-cookies-on-android – Mikaveli

+0

No ayuda que httpClient.getCookieStore(). addCookie (Cookie) necesite un objeto Cookie y CookieManager.getInstance(). getCookie (URI) devuelve una cadena. Cookie es una interfaz y no sé qué subtipo utilizar. – Graeme

Respuesta

9

(Como se prometió una solución a esto. Todavía no me gusta y siento que me estoy perdiendo la forma "Correcta" de hacerlo, pero funciona.)

Puede usar el CookieManager para registrar sus cookies (y, por lo tanto, hacer que estas cookies estén disponibles) entre aplicaciones) con el siguiente código:

galletas de Ahorro en el CookieManager:

List<Cookie> cookies = httpClient.getCookieStore().getCookies(); 

if(cookies != null) 
{ 
    for(Cookie cookie : cookies) 
    { 
     String cookieString = cookie.getName() + "=" + cookie.getValue() + "; domain=" + cookie.getDomain();       
     CookieManager.getInstance().setCookie(cookie.getDomain(), cookieString); 
    } 
} 
CookieSyncManager.getInstance().sync(); 

Comprobación de cookies en dominio especificado: if(CookieManager.getInstance().getCookie(URI_FOR_DOMAIN)

a rEC onstruct valores para HttpClient:

DefaultHttpClient httpClient = new DefaultHttpClient(params); 
String[] keyValueSets = CookieManager.getInstance().getCookie(URI_FOR_DOMAIN).split(";"); 
for(String cookie : keyValueSets) 
{ 
    String[] keyValue = cookie.split("="); 
    String key = keyValue[0]; 
    String value = ""; 
    if(keyValue.length>1) value = keyValue[1]; 
    httpClient.getCookieStore().addCookie(new BasicClientCookie(key, value)); 
} 
+2

es importante establecer también el dominio de la nueva BasicClientCookie (clave, valor), de modo que mejor algo como BasicClientCookie c = new BasicClientCookie (clave, valor); \t \t \t c.setDomain (URI_FOR_DOMAIN); \t \t \t httpClient.getCookieStore(). AddCookie (c); –

+0

Esto me salvó un poco el pelo. Además, me encantaría saber si has logrado encontrar una forma aún mejor desde que publicaste esto. Gracias :) –

+0

Me sale: 'El método getCookieStore() no está definido para el tipo HttpClient' –

22

CookieManager es utilizado por el cliente HTTP interno del Java. No tiene nada que ver con Apache HttpClient.

En su código siempre se crea para cada solicitud de una nueva instancia de HttpClient y por lo tanto una nueva CookieStore ejemplo, que obviamente se pone basura recogida, junto con todas las cookies almacenadas en cuanto que HttpClient ejemplo, se sale del ámbito.

Debería bien

(1) volver a utilizar la misma instancia de HttpClient para todas las peticiones HTTP lógicamente relacionadas y compartirlo entre todos los temas relacionados lógicamente (que es la forma recomendada de utilizar Apache HttpClient)

(2) o, al menos, comparten la misma instancia de CookieStore entre hilos relacionados lógicamente

(3) o, si usted insiste en usar CookieManager para almacenar todas las cookies, Crea una alfombrilla de CookieStore aplicación respaldado por CookieManager

+0

Específicamente quería poder pasar solo lo que se necesita alrededor de mi aplicación (aunque el código de ejemplo sobre/cómo/pasar esto sería bien recibido). En este caso, lo único que necesitaba en cada 'Activity' es' Cookie'. El enfoque recomendado para usar 'Cookies' en las Actividades (y también entre procesos a partir de lo que he leído) es usar' CookieManager' y es por eso que quería usarlo para guardar, ver y luego reutilizar 'Cookies' en el interior de eso Voy a publicar mi propia solución a este problema lo antes posible y espero que tenga alguna debilidad explicada. – Graeme

+0

También buscaré cambiar este código para usar el 'HttpClient' interno de Java y publicar la solución junto con cualquier ventaja que vea en ella. – Graeme

+0

Esta respuesta es simplemente impresionante – jlengrand

0

supongo que uno de lo mejor es aplicar Patrón Singleton a su HTTPClient lo que sólo tiene sólo una instancia!

import org.apache.http.client.HttpClient; 
import org.apache.http.impl.client.DefaultHttpClient; 

public class myHttpClient { 
    private static HttpClient mClient; 
    private myHttpClient() {}; 
    public static HttpClient getInstance() { 
     if(mClient==null) 
      mClient = new DefaultHttpClient(); 
     return mClient; 
    } 
} 
+0

La solicitud asincrónica no puede hacerse con una sola instancia de la clase HttpClient –

4

En mi servidor de aplicación desea utilizar una misma sesión con las mismas galletas ... Después de unas horas de "googlear" dolorosa y dolor de cabeza que acaba de guardar cookies para SharedPreference o simplemente poner en algún objeto y puse DefaultHttpClient con igual galletas de nuevo ... OnDestroy simplemente eliminar SharedPreferences ... eso es todo:

  1. primera clase copia SerializableCookie a su paquete: SerializableCookie

Mire el siguiente ejemplo:

public class NodeServerTask extends AsyncTask<Void, Void, String> { 
private DefaultHttpClient client; 


protected String doInBackground(Void... params) { 
    HttpPost httpPost = new HttpPost(url); 
    List<NameValuePair> urlParameters = new ArrayList<NameValuePair>(); 
    urlParameters.add(nameValuePair); 
    try { 
     httpPost.setEntity(new UrlEncodedFormEntity(urlParameters)); 
     List<Cookie> cookies = loadSharedPreferencesCookie(); 
     if (cookies!=null){ 
      CookieStore cookieStore = new BasicCookieStore(); 
      for (int i=0; i<cookies.size(); i++) 
       cookieStore.addCookie(cookies.get(i)); 
      client.setCookieStore(cookieStore); 
     } 
     HttpResponse response = client.execute(httpPost); 
     cookies = client.getCookieStore().getCookies(); 

     saveSharedPreferencesCookies(cookies); 

// dos métodos para guardar y cargar cookies ...

private void saveSharedPreferencesCookies(List<Cookie> cookies) { 
    SerializableCookie[] serializableCookies = new SerializableCookie[cookies.size()]; 
    for (int i=0;i<cookies.size();i++){ 
     SerializableCookie serializableCookie = new SerializableCookie(cookies.get(i)); 
     serializableCookies[i] = serializableCookie; 
    } 
    SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context); 
    SharedPreferences.Editor editor = preferences.edit(); 
    ObjectOutputStream objectOutput; 
    ByteArrayOutputStream arrayOutputStream = new ByteArrayOutputStream(); 
    try { 
     objectOutput = new ObjectOutputStream(arrayOutputStream); 


     objectOutput.writeObject(serializableCookies); 
     byte[] data = arrayOutputStream.toByteArray(); 
     objectOutput.close(); 
     arrayOutputStream.close(); 

     ByteArrayOutputStream out = new ByteArrayOutputStream(); 
     Base64OutputStream b64 = new Base64OutputStream(out, Base64.DEFAULT); 
     b64.write(data); 
     b64.close(); 
     out.close(); 

     editor.putString("cookies", new String(out.toByteArray())); 
     editor.apply(); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 
} 

private List<Cookie> loadSharedPreferencesCookie() { 
    SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context); 
    byte[] bytes = preferences.getString("cookies", "{}").getBytes(); 
    if (bytes.length == 0 || bytes.length==2) 
     return null; 
    ByteArrayInputStream byteArray = new ByteArrayInputStream(bytes); 
    Base64InputStream base64InputStream = new Base64InputStream(byteArray, Base64.DEFAULT); 
    ObjectInputStream in; 
    List<Cookie> cookies = new ArrayList<Cookie>(); 
    SerializableCookie[] serializableCookies; 
    try { 
     in = new ObjectInputStream(base64InputStream); 
     serializableCookies = (SerializableCookie[]) in.readObject(); 
     for (int i=0;i<serializableCookies.length; i++){ 
      Cookie cookie = serializableCookies[i].getCookie(); 
      cookies.add(cookie); 
     } 
     return cookies; 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } catch (ClassNotFoundException e) { 
     e.printStackTrace(); 
    } 
    return null; 
} 

Google suerte

+0

¿Dónde está el archivo SerializableCoockie.class –

+0

No obtengo el archivo. Por favor envíeme el enlace para ello. Lo necesito de verdad. –

+0

Puede descargar SerializableCoockie.class desde [aquí] (https://dl.dropboxusercontent.com/u/27512913/SeriCookie.java) – AndroidCoolestRulest

1

Yo tenía el mismo problema. Como uso Volley y no HTTPClient directamente, Singleton para HTTPClient no parecía la solución correcta. Pero usando esa misma idea, simplemente guardé el CookieManager en mi aplicación singleton. Así que si la aplicación es mi solicitud Singleton continuación, en el onCreate() de cada actividad añado esto:

if (app.cookieManager == null) { 
     app.cookieManager = new CookieManager(null, CookiePolicy.ACCEPT_ALL); 
    } 
    CookieHandler.setDefault(app.cookieManager); 

Para hacer esto aún mejor, todas mis actividades son subclases de MyAppActivity así que todo lo que tengo que hacer es poner está en onCreate for MyAppActivity y todas mis actividades heredan esta funcionalidad. Ahora todas mis actividades usan el mismo administrador de cookies y todas las actividades comparten mi sesión de servicio web. Simple y funciona genial.

Cuestiones relacionadas