En esta ocasión el objetivo del post será el de comunicar dos tecnologías totalmente complementarias: Google Android yMicrosoft .NET, para ello nos basaremos en el protocolo SOAP, más concretamente en Web Services desde el lado Microsoft y la creación de un componente personalizado que permitirá consumir y acceder a los datos del modelo de negocio desde un dispositivo Android.
Estudiaremos los casos más sencillos para comunicar un servicio web y un dispositivo móvil, desde la interacción de datos simples hasta estructuras de datos complejas definidos por el desarrollador.
En el ejemplo que vamos a abordar el sistema comprobará un par usuario y contraseña y nos informará si el usuario en cuestión se encuentra registrado dentro del repositorio de members de nuestra aplicación. La arquitectura que entrará en juego será la siguiente, partiremos primeramente de un servicio web que será el encargado de albergar la lógica de comprobación y autenticación de usuario junto con un cliente, en este caso un dispositivo móvil que será el encargado de consumir dicho servicio e informar al usuario del resultado de la operación.
Definiendo el Web Services .NET
No profundizaremos demasiado en este aspecto puesto que no es el objetivo del post, partiremos de una clase de tipo “System.Web.Services.WebService” en la que incluiremos un método “EsUsuarioValido” que nos devolverá un objeto de tipo “Usuario” si la autenticación se ha realizado con éxito. Nos debería de quedar algo así:
[WebMethod] using (Contexto ctx = new Contexto()) return reply;
public Usuario EsUsuarioValido(string username, string password)
{
Usuario reply = null;
{
reply = new CADUsuario(ctx).ObtenerUsuario(username, password);
}
}
La clase Usuario nos debería quedar algo así:
namespace WebService.Entidades private string username; public string Username public string Password … }
{
public class Usuario
{
…
{
get { return username; }
set { username = value; }
}
private string password;
{
get { return password; }
set { password = value; }
}
}
Ya solo nos quedaría realizar el despliegue y publicarlo en un sitio visible para ser consumido desde cualquier cliente. El siguiente paso que estudiaremos será el desarrollo de la capa del cliente, encargada de consumir y comunicarse con nuestro servicio web, en este caso el dispositivo móvil elegido es Android sobre la versión1.6 aunque también funcionaría en versiones superiores 2.2
Consumiendo el servicio web .NET desde Android
Para empezar sera necesario descargar el paquete ksoap2-android de la siguiente dirección: http://code.google.com/p/ksoap2-android/downloads/list, ya solo queda incluirlo en nuestra aplicación Android (http://developer.android.com/guide/index.html, si os queréis iniciar está bastante completa), en el caso de estar trabajando con el IDE Eclipse nos situamos con el botón derecho sobre las propiedades del proyecto y añadimos la referencia bajo la opción Java Build Path.
En la estructura de nuetro proyecto nos encontraremos dos clases, una de ellas será Usuario y otra a la que llamaremos Seguridad. La primera solo la utilizaremos como objeto de transporte de datos y la segunda será la encargada de manejar y contendrá los métodos propios de acceso a la autenticación, actuará de proxy en la comunicación con el servicio web.
Os dejo el ejemplo de la clase de datos Usuario, esto es una lata pero ya sabéis que hablamos de Java así que tendremos que picar algo más de código, Microsoft nos malacostumbra a hacerlo todo con el ratón:
package jcantos.demo.entidades; import java.util.Hashtable; import org.ksoap2.serialization.KvmSerializable; public class Usuario implements KvmSerializable { public Usuario(){ PI_idUsuario.setType(PropertyInfo.INTEGER_CLASS); public int getIdUsuario() { public void setNombre(String nombre) { public String getNombre() { public void setEmail(String email) { public String getEmail() { public void setUsername(String username) { public String getUsername() { public void setPassword(String password) { public String getPassword() { @Override @Override @Override @Override Me parece algo tosco para indicar a una clase que es Serializable, en .NET simplemente marcaríamos como atributo [Serializable] pero bueno “eso es así”. Y ahora os dejo la clase correspondiente al consumo del web services. package jcantos.demo.utiles; import org.ksoap2.SoapEnvelope; import android.util.Log; public class Seguridad { private static Usuario usuario=null; public static void setUsuario(Usuario usuario) { public static Usuario getUsuario() { Me parece un tema interesantísimo, imaginaros las posibilidades que se nos abre y el abanico de oportunidades para integrar vuestros cacharritos con aplicaciones ya desarrolladas, no solamente en .NET sino cualquier otro lenguaje JAVA por ejemplo,……¿quién nos quita que pudiésemos elaborar un servicio web a modo de gateway que expusiese aquellos métodos que quisieran ser consumidos por un dispositivo móvil?. Y no solo hablamos a modo de consulta, aquí os dejo un ejemplo en el que podemos actualizar la clave de un usuario una vez que la autenticación se ha realizado con exito, básado en el ejemplo anterior. package jcantos.demo.cad; import jcantos.demo.entidades.Usuario; import org.ksoap2.SoapEnvelope; import android.util.Log; public class CADUsuario { public void ActualizarUsuario(Usuario usuario){ Como veis las posibilidades son infinitas, así que una vez más que la técnica no coarte las necesidades del cliente. Un abrazo a todos y nos vemos en el próximo post.
import org.ksoap2.serialization.PropertyInfo;
private int idUsuario;
private String nombre;
private String email;
private String username;
private String password;
PI_idUsuario.setName("IdUsuario");
PI_nombre.setName("Nombre");
PI_email.setName("Email");
PI_username.setName("Username");
PI_password.setName("Password");
PI_nombre.setType(PropertyInfo.STRING_CLASS);
PI_email.setType(PropertyInfo.STRING_CLASS);
PI_username.setType(PropertyInfo.STRING_CLASS);
PI_password.setType(PropertyInfo.STRING_CLASS);
}
public void setIdUsuario(int idUsuario) {
this.idUsuario = idUsuario;
}
return idUsuario;
}
this.nombre = nombre;
}
return nombre;
}
this.email = email;
}
return email;
}
this.username = username;
}
return username;
}
this.password = password;
}
return password;
}
private static PropertyInfo PI_idUsuario = new PropertyInfo();
private static PropertyInfo PI_nombre = new PropertyInfo();
private static PropertyInfo PI_email = new PropertyInfo();
private static PropertyInfo PI_username = new PropertyInfo();
private static PropertyInfo PI_password = new PropertyInfo();
private static PropertyInfo[] PI_PROP_ARRAY =
{
PI_idUsuario,
PI_nombre,
PI_email,
PI_username,
PI_password
};
public Object getProperty(int param) {
Object object = null;
switch(param)
{
case 0 : object = new Integer(idUsuario);break;
case 1 : object = nombre;break;
case 2 : object = email;break;
case 3 : object = username;break;
case 4 : object = password;break;
}
return object; }
public int getPropertyCount() {
return 5;
}
public void getPropertyInfo(int param, Hashtable arg1, PropertyInfo propertyInfo) {
switch(param){
case 0:
propertyInfo.type = PropertyInfo.INTEGER_CLASS;
propertyInfo.name = "IdUsuario";
break;
case 1:
propertyInfo.type = PropertyInfo.STRING_CLASS;
propertyInfo.name = "Nombre";
break;
case 2:
propertyInfo.type = PropertyInfo.STRING_CLASS;
propertyInfo.name = "Email";
break;
case 3:
propertyInfo.type = PropertyInfo.STRING_CLASS;
propertyInfo.name = "Username";
break;
case 4:
propertyInfo.type = PropertyInfo.STRING_CLASS;
propertyInfo.name = "Password";
break;
}
}
public void setProperty(int param, Object obj) {
switch(param)
{
case 0 : idUsuario = ((Integer)obj).intValue(); break;
case 1 : nombre = (String)obj; break;
case 2 : email = (String)obj; break;
case 3 : username = (String)obj; break;
case 4 : password = (String)obj; break;
}
}
}
import org.ksoap2.serialization.SoapObject;
import org.ksoap2.serialization.SoapSerializationEnvelope;
import org.ksoap2.transport.HttpTransportSE;
import jcantos.demo.entidades.*;
private static final String METHOD_NAME = "EsUsuarioValido";
private static final String NAMESPACE = "http://tempuri.org/";
private static final String URL = "http://www.jcantos.net/webservice.asmx"; //sustituir esta URL por el sitio definitivo
private static final String SOAP_ACTION = "http://tempuri.org/EsUsuarioValido";
public static Usuario EsUsuarioValido(String username, String password){
Usuario reply=null;
try {
SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME);
request.addProperty("username", username);
request.addProperty("password", password);
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
envelope.dotNet=true;
envelope.setOutputSoapObject(request);
HttpTransportSE androidHttpTransport = new HttpTransportSE(URL);
androidHttpTransport.call(SOAP_ACTION, envelope);
SoapObject result = (SoapObject)envelope.getResponse();
if (result!=null){
reply=new Usuario();
reply.setIdUsuario(Integer.parseInt(result.getProperty("IdUsuario").toString()));
reply.setNombre(result.getProperty("Nombre").toString());
reply.setEmail(result.getProperty("Email").toString());
reply.setUsername(username);
reply.setPassword(password);
}
} catch (Exception e) {
Log.e("Servicio_Web",e.getMessage());
}
return reply;
}
Seguridad.usuario = usuario;
}
return usuario;
}
public static boolean EsLogueado(){
return Seguridad.usuario!=null;
}
} Editando y actualizando objetos de negocio desde el dispositivo móvil
Supongamos que un usuario ha realizado una operación de login con éxito y desea cambiar o actualizar su perfil, informando al sistema central del cambio de su correo electrónico junto con la actualización de su nueva contraseña. Para ello podríamos tener una clase tal que esta:
import org.ksoap2.serialization.PropertyInfo;
import org.ksoap2.serialization.SoapObject;
import org.ksoap2.serialization.SoapSerializationEnvelope;
import org.ksoap2.transport.HttpTransportSE;
private static final String METHOD_NAME = "ActualizarUsuario";
private static final String NAMESPACE = "http://tempuri.org/";
private static final String URL = "http://www.jcantos.net/webservice.asmx";
private static final String SOAP_ACTION = "http://tempuri.org/ActualizarUsuario";
try {
SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME);
PropertyInfo pi=new PropertyInfo();
pi.setName("usuario");
pi.setValue(usuario);
pi.setType(usuario.getClass());
request.addProperty(pi);
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
envelope.dotNet=true;
envelope.setOutputSoapObject(request);
envelope.addMapping(NAMESPACE, "Usuario", usuario.getClass());
HttpTransportSE androidHttpTransport = new HttpTransportSE(URL);
androidHttpTransport.setXmlVersionTag("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
androidHttpTransport.debug=false;
androidHttpTransport.call(SOAP_ACTION, envelope);
envelope.getResponse();
} catch (Exception e) {
Log.e("Servicio_Web",e.getMessage());
}
}
}