VERSIONES
- 06/02/2013 (Primera publicación)
- 28/06/2015: Reescrito desde cero eliminado el código para Apache HttpClient
- URLConnection:basada en la API estándar de Java
- Apache HttpClient: Android incluye una versión de esta API, más abstracta y fácil de utilizar que la anterior sobre todo si se utiliza para consumir servicios web REST. Lamentablemente esta versión es bastante antigüa y Google sólo mantiene URLConnection. Es más, en Android 5.1 (Api Level 22) ha sido marcada como obsoleta por lo que en este tip sólo veremos el uso básico de URLConnection
- Necesitamos definir en el Manifest el permiso correspondiente para acceder a Internet:
<uses-permission android:name="android.permission.INTERNET" />
También es una buena práctica comprobar que la conexión está disponible, ver el tip #1.
- Por seguridad Android no permite realizar operaciones de «networking» en el hilo principal para evitar que la app quede bloqueda mientras se realiza la operación (se lanza la excepción NetworkOnMainThreadException). Debemos utilizar un hilo (ver tips #2 y #3).
- Crear la conexión para la url (para HTTPS usaríamos HttpsURLConnection)
URL url = new URL("http://url.com"); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); //método http (GET, POST, PUT...) connection.setRequestMethod("POST");
Si utilizando HTTPS obtenemos la excepción SSLHandshakeException consultar el tip 35: HTTPS y certificados
- Definir los timeout de conexión y lectura (opcionales)
connection.setConnectTimeout(5000); connection.setReadTimeout(10000);
- Establecer los parámetros a incluir en el header, incluyendo autenticación BASIC si fuera necesario
connection.setRequestProperty("Content-Type", "application/json"); connection.setRequestProperty("User-Agent","cliente Android 1.0"); //autenticación BASIC connection.setRequestProperty("Authorization","Basic " + Base64.encodeToString((usuario + ":" + password).getBytes(), Base64.NO_WRAP));
Si estamos trabajando con Java en lugar de Android la autenticación BASIC se haría así:
String basic = new String(Base64.encodeBase64((usuario + ":" + password).getBytes())); connection.setRequestProperty("Authorization","Basic " + basic);
La clase Base64 pertenece a Apache Commons Codec.
- Incluir el documento que se enviará en el body si fuera necesario, por ejemplo el JSON o XML para un servicio REST.
connection.setDoOutput(true); DataOutputStream dataOutputStream = new DataOutputStream(connection.getOutputStream()); dataOutputStream.write(json.getBytes(StandardCharsets.UTF_8)); dataOutputStream.flush(); dataOutputStream.close();
- Si estamos enviando un formulario añadimos los campos del mismo
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); OutputStreamWriter request = new OutputStreamWriter(connection.getOutputStream()); request.write("campo1=danielme&campo2=android"); request.flush(); request.close();
- Realizar la petición y comprobar el código de estado devuelto por el servidor web para actuar en consecuencia. Podemos utilizar las constantes públicas definidas en la clase HttpUrlConnection
- Obtener la respuesta para procesarla.
-
Cerrar siempre el InputStream de respuesta en un finally. Generalmente no es necesario realizar un connection.disconnect(), la liberación o reutilización del socket será realizada por el sistema
if (inputStreamResponse != null){ try{ inputStreamResponse.close(); } catch(IOException ex){ Log.d(this.getClass().toString(), "Error cerrando InputStream", ex); } }
- Volley. Creada por Google, permite crear clientes REST/HTTP mediante anotaciones de forma rápida y sencilla. Es muy configurable y potente e incluso permite configurar el reescalado de las imágenes obtenidas.
- Retrofit. También se basa en anotaciones pero es menos configurable y carece de algunas características avanzadas de Volley como el tratamiento de imágenes. Como contrapartida, es algo más sencilla de utilizar y realiza automáticamente la conversión entre objetos y JSON al estar integrada de serie con Gson.
- Picasso: solución específica para la descarga de imágenes y su reescalado y «cacheo» tanto en memoria como en disco. Es realmente potente pero muy fácil de utilizar.
- Android Glide: alternativa a Picassa menos conocida pero más potente.
En Android SDK disponemos de dos APIs para interactuar con servidores HTTP/HTTPS:
Antes de ver el código, un par de observaciones:
Plantilla para el uso de URLConnection
A continuación se exponen las operaciones que generalmente deberemos realizar para el envío y recepción de datos a través de HTTP. El código es válido tanto para Android como para Java, si hubiera alguna diferencia se indicará.
if(connection.getResponseCode() == HttpURLConnection.HTTP_OK)
InputStream inputStreamResponse = connection.getInputStream();
Por ejemplo, si la respuesta es un documento de texto plano (html, XML, JSON…) la convertimos en una cadena.
String linea = null; StringBuilder respuestaCadena = new StringBuilder(); BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStreamResponse, "UTF-8")); while((linea = bufferedReader.readLine()) != null){ respuestaCadena.append(linea); }
Si es una imagen se puede utilizar la clase BitmapFactory
Bitmap bmp = BitmapFactory.decodeStream(inputStreamResponse);
Frameworks
Aunque no es excesivamente complicada de utilizar, URLConnection exige escribir bastante código para realizar operaciones básicas con servidores HTTP lo que nos obligará a implementar métodos genéricos, Wrappers, etc, que nos permitan abstraer y reutilizar todo el código que sea posible. Afortunadamente tenemos a nuestra disposición frameworks Open Source ampliamente utilizados que facilitan enormemente el trabajo para interactuar con servidores HTTP especialmente la hora de implementar clientes REST:
que tal, buen dia te platico, tengo algunos dias investigando sobre como pasar parametros de android a php a un web service , sin embargo a pesar de que tengo todo exactamente como bien lo mencionas no consigo lograrlo, parece que todo va bien con android sin embargo en php no sucede nada no muestra si se definen las variables, ojala me pudieras echar la mano, saludos y felicidades por tu post…
Si es un web service SOAP tendrás que utilizar un cliente adecuado. En Android siempre he consumido servicios REST pero para SOAP ksoap2 es famoso. http://code.google.com/p/ksoap2-android/wiki/ProjectNews
En cuanto al TIP, es muy básico y sólo para hacer get y post sobre http. En breve espero actualizarlo con soporte para sesiones y https.
les hago una consulta, y si quisiera ver una camara ip? que utilizo
Excelente post! he realizado un código para enviar parametros a php sin embargo no recibo nada en php El php calculo que esta bien porque envia datos a mi bd probandolo independientemente.
Dejo el código Android por si se ve algún detalle o falencia. Desde ante mano gracias!
public class MainActivity extends AppCompatActivity {
private static final String LOGTAG = «LogsAndroid»;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btnSync = (Button) findViewById(R.id.button1);
// btnSync.setOnClickListener(new View.OnClickListener()
//{
}
// public void onClick(View view)
public void numero(View v) {
new Conexion().execute();
// Log.e(LOGTAG, «Mensaje de error»);
}
public class Conexion extends AsyncTask {
String urlParameters = «param1=a¶m2=b¶m3=c»;
byte[] postData = urlParameters.getBytes(StandardCharsets.UTF_8);
int postDataLength = postData.length;
String request = «http://turnero.hicpanel.com/cargar.php»;
@Override
protected Void doInBackground(URL… urls) {
HttpURLConnection conn = null;
try {
URL url = new URL(request);
conn = (HttpURLConnection) url.openConnection();
conn.setDoOutput(true);
conn.setInstanceFollowRedirects(false);
conn.setRequestMethod(«POST»);
conn.setRequestProperty(«Content-Type», «application/x-www-form-urlencoded»);
conn.setRequestProperty(«charset», «utf-8»);
conn.setRequestProperty(«Content-Length», Integer.toString(postDataLength));
conn.setUseCaches(false);
DataOutputStream wr = new DataOutputStream(conn.getOutputStream());
wr.write(postData);
wr.flush();
wr.close();
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
if (conn != null)
conn.disconnect();
}
return null;
}
// });
}
}
//}
Deberías solicitar la respuesta del servidor:
conn.getResponseCode();
Gracias por tu respuesta!!. Acabo de descubrir que mi problema era que faltaba conn.connect().