Acceso a Web Service SOAP en Android

| 2014-06-20 | 6 Comentarios »

Antes de comenzar el tutorial, recomiendo que ingresen a éste artículo Web Service Soap con Java EE , donde se explica paso a paso como crear un web service soap con tecnología JAVA.

En primer lugar hay que empezar diciendo que Android no incluye en su SDK ningún tipo de soporte para el acceso a servicios web de tipo SOAP. Es por esto por lo que vamos a utilizar una librería externa para hacernos más fácil esta tarea. Entre la oferta actual, la opción más popular y más utilizada es la librería ksoap2-android. Esta librería es un fork, especialmente adaptado para Android, de la antigua librería kSOAP2. Este framework nos permitirá de forma relativamente fácil y cómoda utilizar servicios web que utilicen el estándar SOAP. La última versión de esta librería en el momento de escribir este artículo es la 3.3.0, pero recomiendo la versión 3.0.0 que puede descargarse desde este enlace.

Agregar esta librería a nuestro proyecto Android es muy sencillo. Una vez tenemos creado el proyecto en Android bastará con copiar el archivo .jar en la carpeta libs de nuestro proyecto.

Como aplicación de ejemplo, vamos a crear una aplicación sencilla que permitirá sumar dos números. Para ello añadiremos a la vista principal dos cuadros de texto para introducir el número 1 y 2 (en mi caso se llamarán nro1 y nro2 respectivamente) y un botón (en mi caso suma) que realice la llamada al método suma del servicio web pasándole como parámetros los datos introducidos en los cuadros de texto anteriores.

Lo primero que vamos a hacer en este evento es definir, por comodidad, cuatro constantes que nos servirán en varias ocasiones durante el código:

  • NAMESPACE. Espacio de nombres utilizado en nuestro servicio web.
  • URL. Dirección URL para realizar la conexión con el servicio web.
  • METHOD_NAME. Nombre del método web concreto que vamos a ejecutar.
  • SOAP_ACTION. Equivalente al anterior, pero en la notación definida por SOAP.

wssoap

En la imagen anterior se muestran resaltados en rojo los valores de las cuatro constantes a definir, que en nuestro caso concreto quedarían de la siguiente forma:


 //WebService - Opciones
 final String NAMESPACE = "http://ws/";
 final String URL="http://192.168.0.4:8084/ServicioWebSoap/WsProgComPy?wsdl";
 final String METHOD_NAME = "suma";
 final String SOAP_ACTION = "http://ws/suma";

Cabe recalcar que en éste caso utilizo mi ip privada que es 192.168.0.4 y el puerto 8084 del Tomcat, eso deben de cambiar con la dirección IP de sus computadoras o bien ingresar 10.0.2.2 si es localhost.

En primer lugar crearemos la petición (request) a nuestro método suma. Para ello crearemos un nuevo objeto SoapObject pasándole el namespace y el nombre del método web. A esta petición tendremos que asociar los parámetros de entrada mediante el método addProperty()al que pasaremos los nombres y valores de los parámetros (que en nuestro caso se obtendrán de los cuadros de texto de la vista principal).


 SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME);
 request.addProperty("nro1", nro1.getText().toString());
 request.addProperty("nro2", nro2.getText().toString());

El segundo paso será crear el contenedor SOAP (envelope) y asociarle nuestra petición. Para ello crearemos un nuevo objeto SoapSerializationEnvelope indicando la versión de SOAP que vamos a usar (versión 1.1 en nuestro caso, como puede verse en la imagen anterior).


 SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
 envelope.setOutputSoapObject(request);

Como tercer paso crearemos el objeto que se encargará de realizar la comunicación HTTP con el servidor, de tipo HttpTransportSE, al que pasaremos la URL de conexión a nuestro servicio web. Por último, completaremos el proceso realizando la llamada al servicio web mediante el métodocall().

Tras la llamada al servicio ya estamos en disposición de obtener el resultado devuelto por el método web llamado. Esto lo conseguimos mediante el método getResponse(). Dependiendo del tipo de resultado que esperemos recibir deberemos convertir esta respuesta a un tipo u otro. En este caso, como el resultado que esperamos es un valor simple (un número entero) convertiremos la respuesta a un objeto SoapPrimitive, que directamente podremos convertir a una cadena de caracteres llamado a toString().


 HttpTransportSE ht = new HttpTransportSE(URL);
 try {
 ht.call(SOAP_ACTION, envelope);
 SoapPrimitive response = (SoapPrimitive)envelope.getResponse();
 resultado=response.toString();
 Log.i("Resultado: ",resultado);
 }
 catch (Exception e)
 {
 e.printStackTrace();
 }

Y listo, con esto ya tenemos preparada la llamada a nuestro servicio web y el tratamiento de la respuesta recibida.

Un detalle más antes de poder probar todo el sistema. Debemos acordarnos de conceder permiso de acceso a internet a nuestra aplicación, añadiendo la linea correspondiente al Android Manifest:


<uses-permission android:name="android.permission.INTERNET" />

Para probar lo que llevamos hasta ahora podemos ejecutar ambos proyectos simultáneamente, en primer lugar el de Netbeans para iniciar la ejecución del servidor local que alberga nuestro servicio web (hay que dejar abierto el explorador una vez que se abra), y posteriormente el de Eclipse para iniciar nuestra aplicación Android en el Emulador. Una vez están los dos proyectos en ejecución, podemos rellenar los datos  y pulsar el botón “Enviar” para realizar la llamada al servicio web. Si todo va bien y no se produce ningún error, deberíamos poder visualizar el resultado de la suma en la pantalla y en la consola.

En la imagen vemos el resultado de la suma:

Screenshot_2014-06-20-17-43-54

El código anterior debe funcionar correctamente sobre un dispositivo o emulador con versión de Android anterior a la 3.0. Sin embargo, si intentamos ejecutar la aplicación sobre una versión posterior obtendremos una excepción de tipoNetworkOnMainThread. Esto es debido a que en versiones recientes de Android no se permite realizar operaciones de larga duración directamente en el hilo principal de la aplicación. Para solucionar esto y que nuestra aplicación funcione bajo cualquier versión de Android será necesario trasladar el código que hemos escrito para llamar al servicio web a una AsyncTask que realice las operaciones en segundo plano utilizando un hilo secundario.


private class TareaSumar extends AsyncTask<Void, Void, Boolean> {
@Override
protected Boolean doInBackground(Void... params) {
// TODO: attempt authentication against a network service.
//WebService - Opciones
final String NAMESPACE = "http://ws/";
final String URL="http://192.168.0.4:8084/ServicioWebSoap/WsProgComPy?wsdl";
final String METHOD_NAME = "suma";
final String SOAP_ACTION = "http://ws/suma";

SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME);

request.addProperty("nro1", nro1.getText().toString());
request.addProperty("nro2", nro2.getText().toString());

SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
envelope.setOutputSoapObject(request);

HttpTransportSE ht = new HttpTransportSE(URL);
try {
ht.call(SOAP_ACTION, envelope);
SoapPrimitive response = (SoapPrimitive)envelope.getResponse();
resultado=response.toString();
Log.i("Resultado: ",resultado);
}
catch (Exception e)
{
Log.i("Error: ",e.getMessage());
e.printStackTrace();
return false;
}

return true;
}

@Override
protected void onPostExecute(final Boolean success) {
if(success==false){
Toast.makeText(getApplicationContext(), "Error", Toast.LENGTH_LONG).show();
}
else{
Toast.makeText(getApplicationContext(), "El resultado es: "+resultado, Toast.LENGTH_LONG).show();
}
}

@Override
protected void onCancelled() {
Toast.makeText(getApplicationContext(), "Error", Toast.LENGTH_LONG).show();
}
}

Como podemos ver, prácticamente todo el código se ha trasladado al método doInBackground()de la tarea, salvo la parte en la que debemos actualizar la interfaz de usuario tras la llamada que debe ir al método onPostExecute().

Por su parte, una vez creada la tarea asíncrona, en el evento click del botón nos limitaremos a instanciar la tarea y ejecutarla llamando a su método execute().


private EditText nro1,nro2;
private Button sumar;
private String resultado="";
private TareaSumar tareaSumar = null;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
nro1=(EditText) findViewById(R.id.nro1);
nro2=(EditText) findViewById(R.id.nro2);
sumar=(Button) findViewById(R.id.suma);

sumar.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
tareaSumar = new TareaSumar();
tareaSumar.execute();
}
});
}

Espero que les sea de utilidad el artículo.

Descargar proyecto completo:

github-logo

Acerca del autor: Rodrigo Paszniuk

Ingeniero Informático, amante de la tecnología, la música, el ciclismo y aprender cosas nuevas.

Posts Relacionados

  • Crear múltiples productFlavors con Android Studio
  • Gson: Librería para parsear JSON en Android
  • Butter Knife: librería para inyectar vistas en Android
  • HTTPS y SSL en Android

  • Fabian Aspée Encina

    Buenisimo! me funciono super bien!

  • Sergio Hidalgo

    Hola. Funciona muy bien cuando llamo al primer método, pero luego quiero llamar a otro método dentro de la misma actividad pero ya no funciona.

  • Renzo Andre Condo Miranda

    Me funciono todo muy bien, el problema es el método getApplicationContext(), no me lo reconoce, cual crees que pueda ser el motivo.

    • Rodrigo Paszniuk

      Hola Renzo, podés probarlo así: getActivity().getApplicationContext();

      Lo que pasa es que Android se va actualizando y cambia mucho con el tiempo, avísame cualquier cosa que te vamos a ayudar!



SEGUÍNOS EN FACEBOOK


GITHUB