Tutorial: 3 Pasos para Desplegar Proyectos SQLite en Desktop, Web y iOS

Este tutorial te mostrará cómo desplegar proyectos basados en SQLite sobre Desktop, Web e iOS, copiando el archivo de base de datos SQLite en el lugar adecuado para cada plataforma de despliegue.

1. Añadir el archivo de base de datos

Probablemente hayas creado tu archivo de base de datos SQLite utilizando un editor externo; de modo que lo primero que hemos de hacer es añadir dicho archivo al proyecto de Xojo. Puedes hacerlo de varias formas, pero lo mejor es crear un Paso de Compilación (Build Step). De esta forma el archivo se añadirá automáticamente a la carpeta designada cada vez que compiles tu aplicación.

Extra: Hacerlo así te permitirá utilizar rutas de destino diferentes para cuando quieras ejecutar tu app en modo de depuración o bien cuando se esté ejecutando como una app independiente, fuera del IDE.

Añadir un Paso de Compilación en Xojo es idéntico para proyectos Desktop y Web. Selecciona el destino en Build Settings y, a continuación, elige la opción Add to Build Settings > Build Step > Copy Files en el menú contextual.

La anterior acción te permitirá acceder al Panel Inspector asociado con el paso recién añadido, donde puedes teclear un nombre para el paso de compilación, elegir si la copia de archivo se realizará tanto en modo de depuración o despliegue (o ambos) y, lo más importante, también te permitirá seleccionar la ubicación sobre la cuál ha de copiarse el archivo de destino cuando se compile la aplicación.

El menú Destination incluye una serie de rutas típicas (es decir, las carpetas de destino más relevantes). Por ejemplo, una buena opción como destino podría sería Resources Folder. No te olvides de añadir el archivo de base de datos propiamente dicho utilizando para ello los botones disponibles en la barra de herramientas de la ventana Build Editor.

En iOS, añadir un Paso de Compilación es prácticamente igual que en Desktop o Web. La única diferencia es que tendrás que hacer clic sobre el icono que tiene la imagen de un iPhone en el panel Navegador para acceder al menú contextual de Build Step. Además, cada recurso añadido ha de ser firmado con un certificado.

2. Copiar el archivo de Base de Datos a una carpeta de “trabajo”

Puede que pienses que con añadir un Paso de Compilación ya está, dado que este se encargará de copiar el archivo de base de datos sobre la ruta de destino indicada. Así, sólo tendrías que utilizar dicha ruta en la propiedad DatabaseFile de una nueva instancia SQLiteDatabase. Pero no es así.

Son varios los motivos por los cuales no deberías de hacerlo de ese modo, especialmente porque es más que probable que quieras utilizar la base de datos en modo de lectura/escritura; y si vas a escribir en un archivo de base de datos que esté almacenada dentro del bundle de la aplicación… entonces estarías invalidando la firma del certificado realizada sobre dicho recurso de la app, y esta dejaría de funcionar (además de que tendrías problemas de rechazo en el caso de que estuvieras pensando en publicarla en la AppStore).

Lo mejor que puedes hacer es comprobar cada vez que ejecutes la aplicación si dicho archivo de base de datos ya se ha copiado desde el bundle de la aplicación (o cualquier otra carpeta de la aplicación) sobre un directorio que no tenga problemas de acceso cuando se trate de leer o escribir sobre la base de datos. La carpeta Application Support es una buena ubicación en el caso de las aplicaciones de Escritorio, mientras que la carpeta Documents está bien para las aplicaciones Web e iOS.

Por ejemplo, si nuestro archivo de base de datos se llama “EddiesElectronics.sqlite” y el nombre de nuestra app es “XojoTest”, entonces podemos añadir el siguiente fragmento de código en el evento Open de nuestra app Desktop. Asegúrate también de añadir una propiedad con el nombre pDatabase de tipo SQLiteDatabase al objeto App en el Navegador.

Var source As FolderItem = SpecialFolder.Resource("EddiesElectronics.sqlite")
Var name As String = app.ExecutableFile.name.NthField(".", 1)

// Check if there is a folder with the App name in special Application Data
// if not, create it and copy the database file from Resources bundle/directory
If Not (SpecialFolder.ApplicationData.Child(name).Exists And SpecialFolder.ApplicationData.Child(name).IsFolder) Then SpecialFolder.ApplicationData.Child(name).CreateFolder

If Not SpecialFolder.ApplicationData.child(name).child(source.name).exists Then source.CopyTo(SpecialFolder.ApplicationData.Child(name))

Try
// Create a SQLiteDatabase instance and try to open our database file from
// the path
pDatabase = New SQLiteDatabase
pDatabase.DatabaseFile = SpecialFolder.ApplicationData.Child(name).Child("EddiesElectronics.sqlite")
pDatabase.Connect

Catch e As DatabaseException
MessageBox(e.Message)
End Try

Para una app iOS, el código será:

Var source As FolderItem = SpecialFolder.Resource("EddiesElectronics.sqlite")
// Check if our database file already copied on the Documents Sandbox folder
// if not, copy the database file from Resources bundle/directory

If Not SpecialFolder.Documents.Child("EddiesElectronics.sqlite").Exists Then
source.CopyTo(SpecialFolder.documents)
End If

Try
// Create a SQLiteDatabase instance and try to open database file from
// the path
pDatabase = New SQLiteDatabase
Var f As FolderItem = SpecialFolder.Documents
pDatabase.DatabaseFile = f.Child("EddiesElectronics.sqlite")
Call pDatabase.Connect

Catch e As RuntimeException
MessageBox(e.Message)
End Try

Si estás trabajando con Xojo Cloud, el código necesario es más breve. En primer lugar, asegúrate de que el paso Copy File Build tenga los siguientes valores en el Panel Inspector:

  • Destination: Contents Folder
  • Subdirectory: Documents

Luego, el código será:

Try
pDatabase = New SQLiteDatabase
pDatabase.DatabaseFile = SpecialFolder.Documents.Child("EddiesElectronics.sqlite")
pDatabase.Connect
Catch e As RuntimeException
MessageBox(e.Message)
End Try

¿Y qué ocurre en el caso de las apps Web que alojes en tus propios servidores? En ese caso significa que tienes total control sobre la carpeta/directorio en la que quieres guardar los recursos de la app. Por tanto, no tendría mucho sentido automatizar este proceso (aunque puedes hacerlo perfectamente siguiendo los mismos principios).

3. Simplificar el Proceso

Lo que tenemos hasta ahora, funciona; pero también significa que tendrías que cambiar el nombre del archivo de base de datos para cada una de las apps que vayas a crear. También significa que tendrías que escribir el mismo fragmento de código de nuevo para cada nueva app. ¿No sería genial ampliar la clase SQLiteDatabase para simplificarlo?

¡Eso es lo que haremos! Comienza añadiendo un nuevo Módulo al proyecto de ejemplo (por ejemplo, puede ser uno con el nombre “DatabaseExtensions”) y que albergará un par de métodos. El primer método será el que se ejecute para las aplicaciones Desktop, Web y Consola:

Añade un nuevo método utilizando la siguiente signatura en el módulo recién creado:

OpenDatabase(databaseName As String)

Este amplía la clase SQLiteDatabase añadiendo un nuevo método que toma como parámetro el nombre del archivo que queremos copiar sobre la carpeta/Directorio de “trabajo”.

Escribe el siguiente código en el método:

pDatabase = New SQLiteDatabase

#If TargetDesktop Or TargetConsole Or TargetWeb Then

Var source As FolderItem = SpecialFolder.Resource(databaseName)
Var name As String = app.ExecutableFile.name.NthField(".", 1)
// Check if there is a folder with the App name in special Application Data
// if not, create it and copy the database file from Resources bundle/directory
If Not (SpecialFolder.ApplicationData.Child(name).Exists And SpecialFolder.ApplicationData.Child(name).IsFolder) Then
SpecialFolder.ApplicationData.Child(name).CreateFolder
If Not SpecialFolder.ApplicationData.Child(nam).Child(Source.name).Exists Then source.CopyTo(SpecialFolder.ApplicationData.Child(name))

Try
// Create a SQLiteDatabase instance and try to open database file from
// the path
pDatabase.DatabaseFile = SpecialFolder.ApplicationData.Child(name).Child(databaseName)
pDatabase.Connect

Catch e As DatabaseException
MessageBox(e.Message)
End Try

#ElseIf TargetXojoCloud
Try
pDatabase.DatabaseFile = SpecialFolder.Documents.Child(databaseName)
pDatabase.Connect
Catch e As RuntimeException
MessageBox(e.Message)
End Try
#EndIf

Por supuesto, también hemos de añadir la propiedad pDatabase a nuestro Módulo: pDatabase As SQLiteDatabase.

Ahora sólo tendremos que usar:

OpenDatabase("EddiesElectronics.sqlite")

Con el método seleccionado en el Navegador de proyecto, haz clic en la sección de Atributos en el Panel Inspector (la que tiene un icono con forma de rueda dentada), y qita la selección de la casilla de verificación correspondiente a “iOS 64”. De esta forma, no se incluirá dicho método cuando se compilen las apps para iOS.

El segundo método será el que se utilice en el caso de las apps iOS. La firma del método sería:

OpenDatabase(databaseName As String)

Escribe el siguiente fragmento de código en el Editor de Código asociado:

pDatabase = New SQLiteDatabase

Var source As FolderItem = SpecialFolder.Resource(databaseName)

// Check if the database file is already copied on the Documents Sandbox folder
// if not, copy the database file from Resources bundle/directory

If Not SpecialFolder.Documents.Child(databaseName).Exists Then
source.CopyTo(SpecialFolder.Documents)
End If

Try
// Create a SQLiteDatabase instance and try to open database file from
// the path

Var f As FolderItem = SpecialFolder.Documents
pDatabase.DatabaseFile = f.Child(databaseName)
pDatabase.Connect

Catch e As RuntimeException
MessageBox(e.Message)
End Try

Por último, y con el método aún seleccionado en el Navegador, dirígete a la sección Atributos del Panel Inspector y asegúrate de que sólo esté marcada la casilla de verificación correspondiente a “iOS 64” en el apartado “Include In”. De esta forma te asegurarás de que el método sólo se compile para proyectos iOS.

Conclusión

El uso de Módulos en combinación con las Extensiones de Clase es un buen modo de obtener más flexibilidad cuando desarrolles tus apps, sin importar que sea para Desktop, Web o iOS. Además, también significa una mayor reutilización del código y menos mantenimiento del mismo a lo largo y ancho de todos tus proyectos.

Deja un comentario

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