6 de Julio, 2008

Aplicaciones portables con Mono

Hay una guía sobre portabilidad de aplicaciones, que me ha resultado bastante útil, aunque la mayoría de las cosas ya las tenía en mente de cuando programé una aplicación GUI en Java (y quise que fuera portable, claro :P).

Mi entorno de desarrollo es Linux con MonoDevelop y Mono 1.9.1 (que viene a ser Mono 2.0 Beta).

En general he identificado dos clases de problema a la hora de que la aplicación sea portable, aunque el segundo es solo porque quería que el programa funcionara con el runtime de Microsoft aparte del de Mono.

  1. Problemas derivados de la interacción con el sistema que se encuentra fuera de la máquina virtual.
  2. Problemas derivados de cambios en la implementación de las máquinas virtuales por cada runtime.

En el primer caso el documento citado más arriba es útil, porque nos encontramos con los siguientes retos:

  • ¿Dónde guardamos la configuración? De entrada he descartado el registro de Windows, porque en el resto de plataformas no existe :D. Así que elegí la aproximación más fácil, que es crear un directorio en el HOME del usuario, y almacenar la configuración, caché, etc, allí.

    La clave nos la da System.Environment:

    Environment.GetFolderPath(System.Environment.SpecialFolder.Personal)
    

    En Linux (imagino que en cualquier UNIX-like, lo que incluye a Mac), se trata de $HOME, y en Windows parece ser Mis Documentos :D.

  • ¿Cómo se construyen las rutas a directorios? Este es un problema clásico. Como sabemos en los sistemas UNIX-like trabajamos con la barra a la derecha como caracter separador, mientras que Windows emplea la barra a la izquierda (o barra invertida).

    Esto se soluciona con System.IO.Path, que nos proporciona dos métodos estáticos muy útiles:

    // Nos da el caracter separador
    Path.DirectorySeparatorChar
    // Permite añadir un subdirectorio a una path existente
    Path.Combine (basePath, subDir)
    

Y hasta aquí los problemas de portabilidad del primer grupo, ya que el resto de características nos las proporciona GTK# y el API estándar de .NET 2.0.

Respecto a los problemas derivados de los runtime, hay cosas evidentes, y otras... no tanto :(

  • No podemos usar clases de la jeraquía Mono.*: esto está claro, al menos si queremos que funcione la aplicación con el runtime de Microsoft, que no implementa estas clases.
  • Elegir el uso de las clases propuesto por Microsoft: si tenemos dos runtimes que no se comportan igual, en este caso el de Mono es el más flexible porque que es el que busca ser compatible, tendremos que hacer que funcione en el restrictivo.

Entonces es cuando te das cuenta de lo complicado que es :(.

Si trabajamos con Mono en Linux nos encontraremos con que, siguendo la documentación (que es excelente), tenemos código que funciona perfectamente, pero que en el runtime de Microsoft... casca (o directamente ¡no compila!).

En Desknote lo he solucionado buscando en la otra documentación y, haciendo cambios medio a ciegas (no tengo un Windows a mano, las pruebas las hacía Felipe en casa), conseguir que funcionara en Windows.

Cualquiera que haya programado sabe lo frustrante que es buscar una forma de reescribir un trozo de código que funciona de otra manera, por un motivo poco claro :D.

Mis principales batallas han sido contra XmlDocument y Process.Start, pero en general era viable conseguirlo... y lo hemos conseguido :).

Anotación por Juan J. Martínez, clasificada en: desknote, mono, csharp, programming.

Los comentarios están cerrados: los comentarios se cierran automáticamente una vez pasados 30 días. Si quieres comentar algo acerca de la anotación, puedes hacerlo por e-mail.

Algunas anotaciones relacionadas: