Hasta ahora hemos visto que cuando queremos obtener información primero debemos abrir la aplicación cliente que nos da acceso a esa información. Para recibir algo antes tenemos que solicitarlo desde nuestra aplicación, esto es lo que se conoce como una conexión pull, en la que el cliente debe "tirar" de los datos para obtenerlos.
Para determinadas aplicaciones puede ser interesante poder recibir datos sin tener que solicitarlos. Por ejemplo pensemos en una aplicación de foro, en el que varios usuarios pueden publicar mensajes. Nosotros querremos visualizar en nuestro cliente la lista de mensajes publicados en el servidor, pero no sabemos cuando llega un mensaje al servidor, ya que puede haberlo enviado cualquier otro cliente, sólo el servidor sabe cuando llegan nuevos mensajes.
Cuando el usuario abra la aplicación del foro se descargarán todos los mensajes publicados y se mostrarán. Esto sigue un modelo pull, en el que el usuario tiene que abrir la aplicación para obtener los datos deseados, debe "tirar" de los datos.
Pero imaginemos que queremos implementar una función de avisos en el foro, con la cual un usuario puede programar un aviso, de forma que cuando alguien publique una contestación a un tema que sea de su interés, el usuario reciba una notificación. De esta forma se evita tener que estar entrando en la aplicación periódicamente para ver si alguien ha contestado. Esto es un modelo push, en el que es la aplicación la que "empuja" los datos hacia nosotros en el momento en el que llegan.
Para implementar este comportamiento podríamos utilizar una técnica conocida como polling, que consiste en interrogar al servidor cada cierto periodo de tiempo para comprobar si han llegado mensajes nuevos, y en tal caso recibirlos y mostrarlos al usuario. Esto nos obligará a estar continuamente realizando peticiones al servidor, aunque no se haya recibido ningún mensaje, con lo que se estará produciendo un tráfico innecesario en la red. Además deberemos tener la aplicación continuamente en funcionamiento, aunque sea en segundo plano, para que haga las comprobaciones.
Con un modelo de tipo push podremos solucionar este problema, ya que en este caso el servidor podrá enviarnos información sin tener que pedirla nosotros previamente. De esta forma cuando el servidor haya recibido nuevos mensajes nos los enviará mediante push, sin tener que estar interrogándolo nosotros continuamente.
Es decir, push es un mecanismo que nos va a permitir recibir información de forma asíncrona, sin tenerla que solicitar nosotros previamente, y evitando el elevado consumo de recursos que producen las técnicas de polling.
En MIDP 2.0 aparece el registro push, que nos permitirá utilizar este mecanismo de recepción de información de forma asíncrona en nuestro dispositivo.
El registro push nos permitirá que nuestras aplicaciones sean activadas automáticamente mediante push. Es decir, no hará falta que nosotros abramos la aplicación manualmente para que esta pueda realizar alguna función, sino que se podrá activar automáticamente cuando suceda algún evento externo.
Por ejemplo, una utilidad bastante clara de este mecanismo es la programación de alarmas. Imaginemos una agenda que deba hacer sonar una alarma cuando llegue la hora de una reunión. En MIDP 1.0 una aplicación sólo podrá programar una alarma si abrimos manualmente esa aplicación, y deberemos mantener esta aplicación abierta en segundo plano permanentemente, ya que si la cerrásemos también se cerraría la alarma programada. Esto hace que en MIDP 1.0 este tipo de aplicaciones sea poco útiles, ya que si se nos olvida abrir la aplicación cuando encendamos el móvil no sonará ninguna de las alarmas programadas.
Sin embargo, en MIDP 2.0 con el registro push podremos hacer que la aplicación se abra automáticamente cuando llegue la hora de la alarma, es decir, la aplicación se estará activando automáticamente mediante push. En este caso el evento externo que activa la aplicación será un temporizador.
La activación mediante push puede suceder por dos tipos de eventos:
Figura 5. Métodos de activación de MIDlets
Deberemos tener en cuenta que el registro push sólo estará pendiente de estos eventos externos mientras nuestra aplicación esté cerrada. Cuando ejecutemos la aplicación, será responsabilidad suya escuchar las conexiones entrantes y registrar los temporizadores adecuados para que se disparen las alarmas.
Es decir, que la responsabilidad de la escucha y la gestión de los eventos push será compartida entre el MIDlet y el AMS:
La facilidad que nos proporciona el registro push es esta capacidad de ejecutar la aplicación automáticamente cuando se produzca un determinado evento externo, pero mientras nuestra aplicación se esté ejecutando este registro no realizará ninguna función.
A partir de WTK 2.0 se puede utilizar la activación push en los emuladores. Pero para disponer de esta funcionalidad deberemos cargar la aplicación utilizando provisionamiento OTA, instalando de esta forma la aplicación utilizando el AMS del emulador.
Vamos a ver cómo podemos registrar un temporizador push, para
que la aplicación se ejecute automáticamente a una determinada
hora. Para hacer esto deberemos utilizar la API de PushRegistry
,
que nos permitirá registrar este tipo de eventos en el registro push.
Podremos registrar una alarma push con el siguiente método:
long t = PushRegistry.registerAlarm(String midletClassName, long hora);
Deberemos proporcionar como parámetros el nombre de la clase del MIDlet que queremos que se ejecute, y el tiempo del sistema en milisegundos del instante en el que queremos que se produzca la alarma.
Hemos de tener en cuenta que sólo podemos registrar una alarma por MIDlet, de forma que si hubiésemos registrado otra alarma previamente, al invocar este método de sobrescribirá.
Si hubiese una alarma registrada previamente, la llamada a esta función
nos devolverá como valor de tiempo t
el instante en el que
estaba programada la alarma previa que ha sido sobrescrita. En caso contrario,
nos devolverá 0
.
Si nuestra aplicación tuviese que programar varias alarmas, lo que deberíamos hacer es registrar mediante push la alarma que tenga la fecha más temprana, y una vez se haya producido esta alarma, se registrará la siguiente, y así consecutivamente.
Si queremos programar una alarma para que se produzca en una determinada fecha,
independientemente de la fecha actual, simplemente deberemos proporcionar al
método registerAlarm
el tiempo del sistema en milisegundos
de la hora en la que queremos que se produzca.
Para hacer esto simplemente deberemos obtener un objeto Date
que
represente dicha hora. Podemos o bien solicitar que el usuario introduzca la
fecha manualmente en un campo de fecha, y leer de ese campo el objeto Date
con la fecha introducida, o bien generar desde nuestra aplicaciones una determinada
fecha utilizando un objeto Calendar
.
Una vez tengamos el objeto Date
correspondiente a esta fecha,
obtendremos de él el tiempo en milisegundos de dicha fecha para proporcionárselo
a la función registerAlarm
:
Date fecha = obtenerFecha(); long t = PushRegistry.registerAlarm(midlet.getClass().getName(), fecha.getTime());
Es posible que no queramos dar una fecha absoluta a la alarma, sino que queramos establecer una alarma que suene pasado cierto tiempo desde el instante actual. Por ejemplo, podemos querer poner una alarma para que suene dentro de 5 minutos.
Para hacer esto deberemos establecer la fecha de forma relativa a la fecha
actual. Primero obtendremos la fecha actual mediante un objeto Date
,
y a esta fecha podremos sumarle el número de milisegundos del intervalo
de tiempo que queremos que tarde en sonar la alarma:
Date ahora = new Date(); // Obtiene la fecha actual long t = PushRegistry.registerAlarm(midlet.getClass().getName(), ahora.getTime() + intervalo);
Cuando el MIDlet esté en ejecución, los temporizadores registrados mediante push no tendrán efecto, estos temporizadores sólo servirán para activar la aplicación cuando esté cerrada.
Por lo tanto, normalmente durante la ejecución de la aplicación
crearemos temporizadores utilizando la clase Timer
de Java. Como
estos temporizadores serán hilos de la aplicación, cuando ésta
se cierre los temporizadores también se anularán. Entonces será
este el momento en el que deberemos registrar el temporizador push.
El lugar adecuado para registrar los temporizadores push será
el método destroyApp
del MIDlet. De esta forma, si al destruirse
la aplicación todavía tuviésemos algún temporizador
pendiente, los registraremos mediante push para que siga siendo efectivo.
Cuando el MIDlet se active vía push, debido a un temporizador, simplemente se pondrá en marcha la aplicación como si la hubiésemos abierto manualmente, y no tendrá constancia en ningún momento de que se ha abierto debido a un temporizador.
Si queremos que cuando se abra automáticamente se ejecute la alarma, deberemos implementar este comportamiento manualmente. Para hacer esto deberemos registrar las alarmas pendientes utilizando RMS.
Cuando queramos programar una alarma, los datos de esta alarma se registrarán
de forma persistente utilizando RMS, y se programará un Timer
para ella.
Si salimos de la aplicación, en el método destroyApp
se buscará la siguiente alarma pendiente, si hay alguna, y la registrará
mediante push.
Cuando la aplicación se active la próxima vez, podrá leer
las alarmas pendientes en RMS y programar un Timer
para la siguiente.
De esta forma, si la aplicación se hubiese abierto de forma manual y
no correspondiese activar ninguna alarma, como en RMS no hay ninguna alarma
programada para este momento no sucederá nada. Si por el contrario, se
hubiese abierto debido al temporizador push, como tendremos en RMS una alarma
programada justo para el momento actual, se activará la alarma. Así,
aunque la aplicación no sepa cual ha sido la forma de activarse, mediante
la información almacenada en RMS podremos saber cuándo debemos
disparar las alarmas y cuando no.
Podemos hacer que las aplicaciones se activen mediante conexiones de red entrantes. Utilizando protocolo HTTP no tenemos este tipo de conexiones, ya que éste es un protocolo síncrono en el que debemos realizar una petición para obtener una respuesta.
Sin embargo, en MIDP 2.0 se definen otros tipos de conexiones a bajo nivel que si que soportan conexiones entrantes. Estas son las conexiones de sockets y datagramas. Podremos hacer que el dispositivo escuche en un determinado puerto conexiones entrantes mediante sockets o datagramas.
El problema de estos tipos de conexiones es que en la mayoría de los casos los operadores de telefonía móvil actuales utilizan IPs dinámicas, por lo que cada vez que se establezca una nueva conexión (por ejemplo mediante GPRS) se obtendrá una IP distinta. Esto complica la tarea de registrar nuestro móvil para recibir avisos, ya que si la IP cambia frecuentemente no se sabrá a qué dirección se debe enviar la información.
Otro tipo de conexión que tenemos disponible en un gran número de dispositivos y que nos resultará más útil es la conexión de mensajes que aporta la API WMA. Los mensajes de texto se envían a un número de teléfono que sabemos que no va a cambiar. De esta manera podremos tener identificado claramente el dispositivo en el cual queremos recibir notificaciones.
Tenemos dos formas de registrar conexiones push entrantes:
PushRegistry
para registrar las conexiones en tiempo de ejecución, de la misma forma
en la que se registran los temporizadores.Podremos utilizar registro estático cuando las direcciones de nuestras conexiones entrantes sean estáticas. Este será el caso de las conexiones de mensajes (SMS) en cualquier dispositivo, o de las conexiones de sockets y datagramas en aquellos dispositivos que tengan asignada una IP estática y su puerto se configure también de forma estática.
Para registrar una conexión push entrante añadiremos un atributo como el siguiente en el fichero JAD:
MIDlet-Push-<n>: <URL>, <NombreClaseMIDlet>, <RemitentesPermitidos>
Debemos especificar para cada conexión push que queramos permitir
la URL de la conexión entrante y el MIDlet que se ejecutará cuando
recibamos datos. Además como tercer elemento podemos indicar los remitentes
a los que les permitimos enviarnos datos. Con *
indicamos que aceptamos
datos de cualquier remitente.
Estas conexiones se registrarán en el momento en que se instale la aplicación, y se eliminarán cuando se desinstale.
Este tipo de registro no es posible cuando tengamos asignación dinámica de IPs, ya que en tiempo de despliegue no podremos conocer cual será la IP que tenga el dispositivo cuando se utilice la aplicación. En este caso deberemos utilizar registro dinámico, como veremos más adelante.
Para configurar conexiones entrantes de sockets, datagramas y mensajes podremos utilizar URLs de los siguientes tipos:
socket://:<puerto> datagram://:<puerto>
sms://:<puerto>
Al utilizar registro estático siempre deberemos indicar explícitamente el puerto, ya que si dejamos que el puerto se asigne dinámicamente no sabremos a qué puerto del móvil hay que conectarse para activar la aplicación.
Por ejemplo, podemos registrar una conexión de mensajes entrantes de la siguiente forma:
MIDlet-Push-1: sms://:4444, es.ua.jtech.sms.MIDletRecibirSMS, *
De esta forma se escuchará la llegada de SMSs en el puerto 4444, y en
el momento que llegue uno se ejecutará el MIDlet MIDletRecibirSMS
,
permitiendo que lleguen desde cualquier remitente.
Cuando utilicemos registro dinámico podremos configurar, además de las conexiones anteriores, las conexiones de sockets y datagramas para las que se asigne el puerto de forma dinámica:
socket:// datagram://
Utilizaremos este tipo de registro cuando estemos utilizando direcciones dinámicas, o bien cuando utilizando direcciones estáticas queramos registrar la conexión sólo si se cumplen ciertas condiciones.
En este caso el registro lo realizaremos en tiempo de ejecución, utilizando
la API de PushRegistry
. Podemos registrar una conexión entrante
dinámicamente de la siguiente forma:
PushRegistry.registerConnection(url, nombreClaseMIDlet, remitentesPermitidos);
Si estamos utilizando una conexión entrante asignada dinámicamente, encontramos el problema de que el sistema externo no sabrá a qué dirección debe enviar la información para contactar con nuestra aplicación. Para solucionar este problema deberemos comunicar a este sistema externo la dirección en la que estamos escuchando. Esto podemos hacerlo de la siguiente forma:
// Creamos socket servidor asignando el puerto dinámicamente
ServerSocketConnection ssc = (ServerSocketConnection)Connector.open("socket://");
// Obtenemos el puerto que ha asignado el sistema
String url = "socket://:" + ssc.getLocalPort();
// Registramos en push una conexion entrante con este mismo puerto
PushRegistry.registerConnection(url, midletClassName, filter);
// Obtenemos la URL completa de nuestra aplicación
url = "socket://" + ssc.getLocalAddress() + ":" + ssc.getLocalPort();
// Publicamos la URL en el sistema externo
publicarURL(url);
De esta forma cada vez que el sistema asigne un nuevo puerto a nuestra aplicación deberemos publicar la nueva URL en el sistema externo.
Hemos visto que publicando la dirección en el sistema externo podemos utilizar direcciones en las que el puerto de asigna de forma dinámica por el sistema. Sin embargo, el caso en el que nuestro operador de telefonía asigne al dispositivo la IP de forma dinámica será más complicado, ya que cualquier pérdida de la conexión hará que la IP cambie y el sistema externo será incapaz de comunicarse con nuestra aplicación.
En este caso los cambios de dirección pueden ser muy frecuentes, y si la aplicación Java está cerrada no tendremos constancia del momento en el que esto ocurra, por lo que estos tipos de conexión push no serán de utilidad. En ese caso la solución será utilizar conexiones de mensajes, para las que si que tenemos una dirección (número de teléfono) asignada de forma estática.
Las conexiones entrantes push que registremos de forma dinámica podrán ser eliminadas. Para eliminar una conexión utilizaremos el siguiente método:
try { boolean estado = PushRegistry.unregisterConnection(url); } catch(SecurityException e) { // Error de seguridad
}
El método unregisterConnection
nos devolverá true
si ha podido eliminar la conexión push correctamente, y false
en caso contrario.
Cuando la aplicación haya sido activada mediante una conexión entrante push, a diferencia de la activación mediante temporizador, si que tendremos constancia de la forma en la que se ha activado.
Para esto utilizaremos el método listConnections
, que nos
devuelve la lista de conexiones push registradas para el MIDlet. Si a este método
le pasamos true
como parámetro, nos devolverá sólo
aquellas conexiones en las que tengamos datos disponibles para ser leidos.
De esta forma, si al ejecutarse la aplicación existe alguna conexión push con datos disponibles sabremos que la aplicación se ha activado mediante push debido a la recepción de datos en dichas conexiones.
public boolean isPushActivated() {
String [] conexiones = PushRegistry.listConnections(true);
if (conexiones != null && conexiones.length > 0) { for (int i=0; i < conexiones.length; i++) { leerDatos(conexiones[i]);
} return true ;
} else {
return false;
} }
Cuando hayamos recibido datos en una de estas conexiones será responsabilidad de nuestro MIDlet abrir esta conexión y leer los datos.
Hemos de tener en cuenta que en conexiones como los sockets el AMS no creará ningún buffer con los datos, sino que será el MIDlet activado el que los lea directamente de la red. Por lo tanto, deberemos leerlos lo más rápidamente posible, ya que si demorásemos la lectura de datos se podría producir un timeout.
Vamos a estudiar la seguridad de las aplicaciones MIDP. Nos referiremos a seguridad en cuanto a que las aplicaciones que se instale el usuario en el móvil no puedan realizar actividades dañinas para él. Otros tipos de seguridad dependientes de la aplicación, como son la autentificación y la confidencialidad de la información transmitida por la red los estudiaremos en el tema de aplicaciones corporativas.
El usuario navegando por la red puede encontrar aplicaciones MIDP que para utilizarlas deberán ser instaladas de forma local en su móvil. Si permitiésemos que estas aplicaciones, una vez instaladas, pudiesen realizar cualquier acción, sería bastante peligroso utilizar este tipo de aplicaciones. El usuario debería estar muy seguro que la aplicación que se instala es de su confianza, porque de no serlo la aplicación podría realizar tareas como por ejemplo:
Por lo tanto, es importante garantizar que las aplicaciones MIDP son seguras y no pueden realizar ninguna acción dañina, para que de esta forma los usuarios puedan confiar en ellas y descargárselas sin ningún temor. A continuación veremos cómo se garantiza esta seguridad en las aplicaciones MIDP.
La seguridad de las aplicaciones MIDP se debe a que estás aplicaciones se debe a que éstas se ejecutan en un entorno restringido y controlado. Al ejecutarse sobre una máquina virtual, y no directamente sobre el dispositivo, se puede limitar el número de acciones que estas aplicaciones pueden realizar, evitando de esta forma que se realicen acciones que puedan resultar dañinas.
Las aplicaciones se ejecutan dentro de lo que se conoce como un cajón de arena (sandbox), como los que existen en los parques para que los niños jueguen de forma segura. Este cajón de arena es un entorno limitado y cerrado en el que podrá trabajar la aplicación, y en el que no se tendrá acceso a nada que pudiera resultar dañino.
En el caso de las aplicaciones MIDP, este sandbox será la suite de MIDlets. Es decir, ninguna aplicación podrá acceder a nada externo a su suite:
Como las aplicaciones MIDP no permiten acceder al sistema de ficheros del dispositivo, ni tampoco permiten utilizar su API nativa, no tendremos problemas de seguridad en este aspecto.
La única funcionalidad que podría resultar peligrosa es la capacidad que tienen estas aplicaciones de establecer conexiones de red. Una aplicación podría estar intercambiando información por la red, lo cual le costará dinero al usuario, sin que éste se diese cuenta. Sin embargo, esta es una funcionalidad imprescindible de las aplicaciones MIDP, por lo que no podemos privar a estas aplicaciones de su API de red. Por esta razón, a partir de MIDP 2.0 surge un modelo de seguridad que limitará la utilización de estas funciones a las aplicaciones que obtengan permiso para hacerlo.
En la API de MIDP 2.0 existen diferentes permisos para cada tipo de conexión que pueda realizar el dispositivo. Estos permisos son los siguientes:
javax.microedition.io.Connector.http javax.microedition.io.Connector.socket javax.microedition.io.Connector.https javax.microedition.io.Connector.ssl javax.microedition.io.Connector.datagram javax.microedition.io.Connector.serversocket javax.microedition.io.Connector.datagramreceiver javax.microedition.io.Connector.comm javax.microedition.io.PushRegistry
Cuando en nuestra aplicación necesitemos utilizar alguna conexión
de cualquiera de estos tipos, deberemos solicitar el permiso para poder hacerlo.
Solicitaremos los permisos en el fichero JAD, mediante las propiedades MIDlet-Permissions
y MIDlet-Permissions-Opt
, en las que especificaremos todos los
permisos solicitados separados por comas:
MIDlet-Permissions: javax.microedition.io.Connector.http,javax.microedition.io.PushRegistry MIDlet-Permissions-Opt: javax.microedition.io.Connector.https
El atributo MIDlet-Permissions
indicará aquellos permisos
que son esenciales para que nuestra aplicación pueda funcionar. Si el
dispositivo en el que se va a instalar la aplicación no pudiese conceder
estos permisos a nuestra aplicación, debido a que no confía en
ella, se producirá un error en la instalación ya que la aplicación
no funcionará sin estos permisos.
En el caso de MIDlet-Permissions-Opt
, especificamos permisos que
solicitamos, pero que son opcionales. Si no se pudiesen obtener estos permisos
la aplicación podría funcionar.
En WTK podremos introducir esta información en la pestaña Permissions de la ventana Settings... de nuestra aplicación:
Desde esta ventana, pulsando sobre Add podremos añadir permisos de forma visual:
Aquí podremos seleccionar los permisos deseados entre todos los permisos proporcionados por la API que estemos utilizando.
Los permisos que se le otorguen a cada aplicación MIDP dependerán del dominio en el que se encuentre dicha aplicación. Un dominio comprende:
Podemos distinguir distintos tipos de dominios según lo restrictivos que sean:
SecurityException
. SecurityException
.Hemos visto tres casos de dominios extremos como ejemplo, pero podemos tener muchos más tipos de dominios distintos. Un dominio se definirá otorgando a cada operación sensible un determinado tipo de permiso. En un dominio se pueden conceder permisos de dos formas distintas:
allow
): Se concede el permiso para que
la aplicación pueda realizar la correspondiente operación sin
tener que obtener la confirmación del usuario.oneshot
: Se pedirá confirmación al usuario
cada vez que se vaya a realizar la operación.session
: Se pedirá confirmación al usuario
sólo la primera vez que se vaya a realizar la operación
en cada sesión. Cuando se cierre la aplicación y vuelva
a abrirse, se volverá a realizar la pregunta.blanket
: Se pedirá confirmación sólo
la primera vez que se vaya a realizar la operación. La aplicación
recordará la opción que tomó el usuario en las sucesivas
sesiones, hasta que sea desinstalada.Esta definición de los dominios será responsabilidad del fabricante del dispositivo, por lo que no deberemos ocuparnos de ello. Nuestras aplicaciones simplemente serán asignadas a uno de los dominios disponibles en el dispositivo que las instalemos.
Normalmente, los dispositivos reales incluyen a las aplicaciones por defecto en un dominio como el último. Es decir, cualquier aplicación que instalemos se considera que no es de confianza, y se le preguntará al usuario cada vez que la aplicación vaya a realizar una operación restringida.
Además, en el caso de los dispositivos reales, también se suele poder cambiar la configuración de este dominio por defecto en la pantalla de configuración del AMS de nuestro móvil. Por ejemplo, en el caso del Nokia 6600, podremos cambiar los permisos que se le otorgan a cada aplicación manualmente. Para cada operación restringida nos dará 4 posibilidades:
Deberemos tener cuidado de no asignarle permisos a una aplicación que no sea de nuestra confianza.
La forma en la que el dispositivo decide en qué dominio se debe incluir la aplicación no está especificada en MIDP, sin embargo se recomienda la utilización de firmas criptográficas y certificados.
De esta forma, si la aplicación instalada no lleva una firma de confianza, la aplicación se incluirá en el dominio definido por defecto de aplicaciones que no son de confianza. Si por el contrario, contiene una firma reconocida por el dispositivo, la aplicación se añadirá a un dominio de confianza correspondiente a dicha firma, que nos otorgará un determinado conjunto de permisos para los cuales no será necesaria la confirmación del usuario.
Según la firma se puede añadir la aplicación a diferentes dominios, y en cada uno de ellos se pueden conceder o denegar distintas operaciones. De esta forma, puede ocurrir que una aplicación firmada por A tenga sólo permiso para utilizar conexiones HTTP, una aplicación firmada por B tenga sólo permiso para utilizar sockets, y una firmada por C tenga permiso para utilizar cualquier tipo de conexión. Los distintos tipos de dominios definidos y la asignación de permisos a cada uno de ellos dependerá del fabricante del dispositivo.
Los emuladores incluidos en WTK definen un conjunto de 4 dominios en los que se podrán incluir las aplicaciones. Estos dominios son:
SecurityException
directamente.Podemos indicar en la configuración de WTK cual será el dominio por defecto en el que se ejecutarán las aplicaciones cuando las carguemos directamente en el emulador (sin utilizar OTA). Podemos cambiar este dominio por defecto en la ventana de preferencias (Preferences...) del WTK.
Cuando se utilice provisionamiento OTA, el emulador se comportará como un dispositivo real, asignando a la aplicación un dominio según su firma.
En la especificación de MIDP no se establece ningún método para decidir a qué dominio corresponde cada MIDlet, pero se recomienda que para tomar esta decisión se utilicen firmas y certificados.
Cada dispositivo contendrá una serie de certificados de confianza. Cada uno de estos certificados estará asociado a un determinado dominio. Es responsabilidad del fabricante decidir qué certificados se incluyen en el dispositivo y a qué dominio se asocia cada uno.
Para que a un MIDlet se le otorguen ciertos permisos, deberá estar firmado por un certificado que sea conocido por el dispositivo donde se instala. Al instalar el MIDlet en el dispositivo, si está firmado se comprobará si el dispositivo contiene el certificado que se ha utilizado para firmarlo. De ser así, se comprobará la autenticidad de la aplicación descargada mediante este certificado, y de ser correcta se instalará la aplicación en el dominio que el dispositivo tuviese asociado a dicho certificado.
Si el certificado con el que se ha firmado la aplicación no fuese conocido por el dispositivo, simplemente instalará la aplicación en el dominio de aplicaciones que no son de confianza. Normalmente en este dominio se preguntará al usuario cada vez que se va a realizar una operación restringida.
Por lo tanto, para conseguir que a nuestro MIDlet se le otorguen permisos deberemos firmarlo por un certificado que esté incluido en el dispositivo.
La especificación de MIDP 2.0 recomienda que se incluyan 3 tipos de certificados:
Si el certificado con el que hemos firmado nuestra aplicación no está entre los anteriores, o bien no hemos firmado la aplicación, ésta se instalará en el dominio de aplicaciones no fiables que existirá en cualquier dispositivo.
Para que nuestra aplicación obtenga permisos en un dispositivo móvil real deberíamos tenerla firmada por un certificado incorporado en el dispositivo en el que la instalamos. Sin embargo, cuando la probemos en emuladores podremos crear nuestros propios certificados y añadirlos al emulador, sin necesidad de obtenerlos a partir de una Autoridad Certificadora. De esta forma en el emulador las aplicaciones firmadas por nosotros podrán obtener los permisos que solicitemos.
Vamos a ver como firmar aplicaciones MIDP utilizando WTK. Para firmar una aplicación, lo primero que deberemos hacer es crear el paquete con la aplicación, ya que es necesario contar con el fichero JAR para obtener su digest. Una vez creado el paquete utilizaremos la opción Project > Sign para firmar la aplicación. Aparecerá la siguiente ventana:
Aquí podremos utilizar alguna de las claves disponibles para firmar nuestra aplicación, o bien crear un nuevo par de claves. Pulsaremos sobre New Key Pair... para crear nuestras propias claves:
Aquí introducimos información sobre nuestra compañía, para crear un certificado correspondiente a esta compañía. Cuando pulsemos sobre Create se creará este certificado asignándole su correspondiente par de claves, y nos mostrará la siguiente ventana para indicar a qué dominio se asignarán las aplicaciones firmadas por nosotros:
De esta forma, nuestro certificado será instalado en el emulador. Cuando instalemos una aplicación firmada por nosotros en el emulador, esta aplicación se instalará en el dominio que hayamos indicado aquí. Si elegimos trusted, nuestras aplicaciones dispondrán de todos los permisos sin tener que pedir la confirmación del usuario.
El último paso que debemos realizar es firmar nuestra aplicación utilizando el certificado que acabamos de crear. Para esto simplemente seleccionaremos en la ventana Sign MIDlet Suite el certificado que queremos utilizar, y pulsaremos sobre el botón Sign MIDlet Suite...
Una vez firmada, podremos probarla en el emulador para comprobar que se le otorgan los permisos correspondientes. Para que esto sea así, deberemos probarla utilizando provisionamiento OTA, ya que si lo hacemos de otra forma la firma no se tendría en cuenta.
Recordemos que si ejecutamos la aplicación directamente se tiene en cuenta el dominio que se haya configurado por defecto para los emuladores. Cuando utilizamos OTA se comportará como un dispositivo real, utilizando los certificados de los que dispone para asignar un dominio a nuestra aplicación.