Distribuyendo una app de escritorio en Java

Java es un gran lenguaje, y como todos tiene ventajas y desventajas. Al momento de distribuir nuestra aplicación, se pueden realizar (y mejor aún, automatizar) algunas adecuaciones para ofrecer un paquete fácil de usar, pues una de las desventajas en Java es la falta de una integración adecuada para cada una de las plataformas soportadas.

Impresión de algunos al recibir un JAR y sus librerías
Impresión de algunos al recibir un JAR y sus librerías

Siguiendo esta guía vamos a generar un proceso en Ant que construirá paquetes para Windows, OS X, Linux y multiplataforma. Los paquetes específicos para plataforma tendrán un ejecutable nativo, en tanto que el multiplataforma llevará el JAR optimizado. Los tres paquetes incluirán también archivos varios necesarios para la distribución como licencias o instructivos.

El JAR de la aplicación usado para las distribuciones será optimizado en tamaño, desempeño y código usando Proguard, que es una excelente herramienta para pulir un JAR a distribuir. Para generar el ejecutable de Windows se usará la herramienta Launch4j. Para la app de OS X se usará jarbundler.

Primero hay que crear un directorio para almacenar las herramientas a usar, un buen lugar puede ser dentro de la raiz del proyecto pero puedes ponerla donde mejor te ajuste. Descarga Proguard y coloca el JAR (proguard-*.**.jar) en tu directorio de herramientas de construcción. Ahora Descarga Launch4j y descomprime el paquete en el mismo lugar donde hayas colocado Proguard. Finalmente desarcarga appblundler y coloca el jar en el mismo directorio que las herramientas anteriores.

Si usas Linux x64 y en caso de que quieras hacer el ejecutable de Windows, es muy probable que debas agregar soporte para procesar librerías de 32 bits (por el binario windres incluido en la distribución de Linux). Si usas una distro basada en Debian puedes habilitar el uso de paquetes de 32 bits con las siguientes instrucciones:

Notas: Esta guia la he implementado en #! 11 x64 y NetBeans 8 y posiblemente necesites hacer adaptaciones dependiendo de tu SO e IDE. Al ir pegando el código, revisa los valores de las variables o propiedades para ajustarlas a tus necesidades, algunos valores incluyen rutas que deberás actualizar.

Primero vamos a definir un nuevo archivo build que contendrá la automatización del proceso. Para esto necesitamos crear un nuevo archivo: build-dist.xml. Hazlo copiando el archivo build.xml en la misma ubicación (la raiz del proyecto).

Edita build.xml dejándolo con algo como:

Nota la importación de build-dist.xml y el llamado antcall para controlar la ejecución del proceso.

Ahora edita build-dist.xml para dejarlo con la siguiente estructura inicial:

Lo que haremos ahora será agregar cada bloque correspondiente a cada llamado antcall. Descomenta/comenta los llamados según vayas avanzando para hacer pruebas.

Lo primero será pulir nuestro JAR utilizando Proguard. Esta aplicación se encargará de remover código sin usar, optimizar a nivel bytecode nuestra aplicación y además obfuscar la estructura del fuente, todo esto nos viene genial.

Agrega el siguiente target a build-dist.xml:

Verifica que la configuración de las propiedades sea correcta y construye tu paquete. Después de compilar y con ‘algo de suerte’ se generará un nuevo JAR con el nombre definido en la propiedad ob.jar.name, este JAR es la aplicación optimizada. Observa que he dejado en la sección de código configuraciones de ejemplo particulares a una aplicación. En caso de que tengas errores consulta la traza y agrega las configuraciones propias para tu aplicación. Consulta el manual de uso en el sitio de Proguard para esto.

El segundo paso es generar un solo JAR que contenga la aplicación procesada y las librerías. Apendiza el siguiente target en build-dist.xml:

Igualmente, verifica la configuración de las propiedades del target y compila. El proceso de construcción ahora generará un nuevo archivo que contendrá a nuestra aplicación y sus librerías en un solo .jar.

 
Desde este momento tenemos un JAR más facil de distribuir. La tarea ahora es ofrecer métodos para ejecutar nuestra aplicación de una manera más amigable, algo que conseguiremos creando lanzadores nativos para algunas plataformas.

Para Windows generaremos un .exe a través de Launch4j. Crea un archivo .xml dentro del directorio del Launch4j para establecer la configuración necesaria. El siguiente ejemplo generará un ejecutable que requirá una JVM 1.6.0+ instalada para funcionar, redireccionando a la página de descarga en español para instalar JAVA cuando no esté disponible, y con preferencia por una JVM de 64bits:

Agrega el ícono que usarás para el .exe en el mismo directorio en que has puesto la configuración anterior. Consulta la documentación para configuraciones más específicas.

Ahora, para ejecutar el proceso, agrega a build-dist.xml el siguiente target:

 
Para generar la aplicación de OS X usaremos el siguiente target:

Para linux usaremos la estrategia de agregar payloads a scripts, que apendizará un lanzador y el JAR en un solo archivo. Crea el lanzador dentro del directorio de herramientas de construcción con el siguiente contenido:

Ahora, agrega a build-dist.xml un nuevo tarjet con la ejecución del cat que unirá el lanzador y el JAR:

(Si te preguntas por que usar sh como ejecutable en lugar de cat directamente, es porque la manera en que se envían los parametros impide la redirección y tanto el atributo output de <exec> como el uso del subelemento <redirector> modifican la salida generando archivos corruptos.)

cat-package

Para terminar vamos a agregar las instrucciones que generan los archivos de ditribución: un ZIP para Windows, un TAR.GZ para OS X, un TAR.BZ2 para Linux y un TAR.GZ multiplataforma.

Los tres target siguientes generarán archivos comprimidos que contendrán un directorio raiz, éste a su vez contendrá el wrapper o jar y un directorio con documentos varios.

Para Windows agrega el siguiente target:

Para OS X agrega el siguiente target:

Para Linux agrega el siguiente target:

Para la distribución multiplataforma agrega el siguiente target:

En este target además estoy agregando archivos run.* que son lanzadores comunes para ejecutar un JAR en diferentes plataformas.

Este último paso es realmente innecesario y elimina todos los archivos y directorios excepto nuestros paquetes distribuibles:

El archivo de construcción seguro es ahora considerablemente más largo pero muy versatil y adaptable. Aun cuando hay muchas mejoras posibles, esta es una buena base, así que agrega los cambios propios para tu proyecto y facilita la vida a tus usuarios (y la tuya por supuesto).

Compartir es querer...Tweet about this on TwitterShare on FacebookShare on Google+Share on StumbleUponShare on RedditEmail this to someone

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *