Actualités

[21/07/2017] Smile lance les premiers vélos solaires connectés à l’occasion du Sun Trip Tour 2017

Smile, leader des solutions IoT et open source, confirme sa solide expertise sur le marché de l’embarqué en participant activement à la course de vélos solaires du Sun Trip Tour.

[03/07/2017] Smile remporte le Drupagora d'Or 2017 du meilleur site e-commerce

Le vendredi 30 juin, la 3ème édition des Drupagora d'Or s'est déroulée à Paris.

[30/06/2017] Découvrez les projets de nos équipes au Hackathon Data Énergie

Les 29 et 30 juin, le Hackathon Data Énergie s'est déroulé au Liberté Living Lab à Paris.

Toutes les actualités picto
       

Vous avez besoin de mettre à jour votre Lecteur Flash Flash 7

Guillemet ouvrant l'actualité des solutions
et des technologies open source Guillemet fermant
picto

Initialiser une base de données locale pour une application PhoneGap

Cet article fait suite à l’article “Créer une application PhoneGap pour Windows Phone en utilisant une base de données locale” concernant l’implémentation de l’API Web SQL Database au sein d’une application PhoneGap Windows Phone 7/8.

Dans ce second article, qui fait suite à celui-ci, nous évoquerons les étapes nécessaires pour pré-charger une base de données efficacement sous les OS suivants : iOS, Android et Windows Phone 7/8.

Pré-chargement

Deux solutions de pré-chargement s'offrent à nous :

  1. Importer les données via l'exécution d'un script SQL,
  2. Importer un binaire de la base de données.

La première solution, bien que simple à mettre en place et (relativement) agnostique du type de base de données (MySQL, Oracle, SQLite, ...) utilisé pour l'implémentation de la fonctionnalité Web SQL Database, n'est pas performante dès que la quantité de données commence à être importante. Bien que PhoneGap ait l'avantage de pouvoir cibler de nombreux terminaux, il a l’inconvénient ici de cibler aussi les smartphones d'entrée de gamme peu puissants. Si une latence au démarrage de l'application (due au pré-chargement de la base de données) peut être limitée à quelques secondes sur les terminaux les plus puissants, elle peut s'étendre à plusieurs minutes pour les terminaux d'entrée de gamme.  

Cette latence risque, dans la grande majorité des cas, d'amener l'utilisateur à une désinstallation immédiate de l'application.

Nous ne retiendrons donc pas cette solution pour les mobiles. Notez cependant que cette solution peut (et sera dans la majorité des cas) utilisée pour initialiser la base de données pendant la phase de développement de l'application sur navigateur desktop.

La seconde solution consiste à générer a priori le binaire de la base et à le charger à la première exécution de l'application. L'implémentation retenue sur iOS et Android est SQLite. De même pour Windows Phone si le plugin cordova-plugin-websqldatabase est utilisé. Cela permet donc de n'avoir besoin que d'un seul binaire au format SQLite pour l’ensemble des OS cibles.

Que ce soit sur iOS, Android ou Windows Phone 7/8, l'espace de stockage des données de l'application est distinct de celui utilisé pour le stockage de la base de données Web SQL Database. Ainsi, le chargement initial de la base binaire se fait, pour chacun des OS, par copie du fichier binaire embarqué dans l'application vers le répertoire de destination.

Notons qu’il n'est pas possible de supprimer un fichier présent dans l'espace de stockage des données de l'application. La base de données sera donc présente en deux exemplaires (la version packagée dans l'application et la version copiée dans l'espace réservé aux bases de données Web SQL Database). À des fins d'optimisation de la taille prise par l'application une fois installée, nous choisissons de fournir une version compressée (zip) de la base de données SQLite. L'initialisation consiste donc à extraire cette archive dans le répertoire de destination.

Dans les cas d'Android et d'iOS, l'implémentation de Web SQL Database nécessite la présence d'une base de données SQLite qui référence la liste des bases de données. Nous devons donc, en plus du fichier binaire contenant les données de l'application, fournir une base de données « Databases.db » dont le contenu sera une ligne de métadonnées (chemin, nom, taille, …) de la base de données de l'application.

Création du fichier Databases.db pour Android et iOS

La création du fichier Databases.db peut être effectuée grâce à un client SQLite (sqlite3, sqlitebrowser, …) à partir des commandes SQL ci-dessous (en remplaçant correctement les valeurs) :

CREATE TABLE DATABASES (guid INTEGER PRIMARY KEY AUTOINCREMENT, origin TEXT, name TEXT, displayName TEXT, estimatedSize INTEGER, path TEXT);
INSERT INTO DATABASES VALUES(1, 'file__0', 'myDemoSQLiteDB.db', 'Proto DB', 1000000, 'myDemoSQLiteDB.db');
CREATE TABLE Origins (origin TEXT UNIQUE ON CONFLICT REPLACE, quota INTEGER NOT NULL ON CONFLICT FAIL);
INSERT INTO Origins VALUES('file__0',52428800);

Voici à quoi correspondent les valeurs :

  • Le premier “myDemoSQLiteDB.db” correspond au “name” (1er paramètre de la fonction JavaScript “openDatabase” tel que défini par la spécification W3C). Lors de l’appel à la fonction “openDatabase”, il faudra renseigner la même valeur. Noter qu’il est préférable d’utiliser le suffixe “.db” dans cet identifiant car le plugin cordova-plugin-websqldatabase pour Windows Phone crée un fichier portant le nom de cet identifiant,
  • La valeur “Proto DB” n’a a priori aucune importance. Il est cependant préférable d’utiliser la même valeur que pour le “displayName” (3ème paramètre de la fonction “openDatabase”),
  • La valeur “1000000” correspond à la valeur “estimatedSize” (4ème paramètre de la fonction “openDatabase”). Cette valeur ne semble pas être prise en compte par les différentes implémentations,
  • Le second “myDemoSQLiteDB.db” correspond au nom du fichier binaire comportant les données de la base (cf. ci-dessous).
Création de la base de données applicative commune à tous les OS

La création de la base de données consiste à créer un fichier myDemoSQLiteDB.db contenant les données de votre application. Vous pouvez créer les données à partir d’un client SQLite ou, plus simplement, récupérer une base de données SQLite générée par Chrome/Chromium via l’API Web SQL Database. Le fichier généré peut être trouvé dans le répertoire “databases” du “User Data Directory”.

Pour optimiser l’espace pris par la base de données, compresser le fichier myDemoSQLiteDB.db en myDemoSQLiteDB.zip.

Cas Android
Étude de fonctionnement

Si l'on crée, sur un terminal Android, une base de données par l'API Web SQL Database en effectuant un appel à la fonction “openDatabase”, le fichier SQLite résultant est créé dans le répertoire « /data/data/[packageName]/app_database ». Voici l’arborescence obtenue :

/
├── data
│   ├── data
│   │   ├── [packageName]
│   │   │   ├── app_database
│   │   │   │   ├── Databases.db
│   │   │   │   ├── file__0
│   │   │   │   │   ├── 0000000000000001.db
│   │   │   ├── cache
│   │   │   ├── databases
│   │   │   ├── lib

Notons la présence des deux fichiers suivants :

  • Databases.db : fichier utilisé par WebKit indexant la liste des bases données,
  • 0000000000000001.db : base de données créée par l’appel à “openDatabase”.

Afin de pré-charger une base de données, il s'agit donc de respecter cette structure pour « bluffer » le système et faire croire que la base de données a été créée précédemment via l’API Web SQL Database.

Le nom “0000000000000001.db” n’étant pas parlant, nous allons l’adapter en utilisant “myDemoSQLiteDB.db” à la place. Afin que cette base soit correctement référencée par WebKit, nous veillerons à fournir le même nom lors de la création du fichier Databases.db.

Utilisation du plugin

La première étape consiste à ajouter le fichier "Databases.db" et le fichier zippé de base de données dans le dossier “assets” afin qu’ils soient packagés dans l’application. L’arborescence du projet Android est alors de la forme suivante :

.
├── AndroidManifest.xml
├── assets
│   ├── www
│   │   ├── … 
│   ├── Databases.db
│   ├── myDemoSQLiteDB.zip
├── …

Il faut ensuite ajouter le plugin via la commande suivante  (identique pour l’ensemble des OS) :

cordova plugin add org.smile.websqldatabase.initializer

Le plugin contient l’ensemble de la mécanique nécessaire à la copie des fichiers fournis dans le dossier “assets” vers le dossier de destination lors du premier lancement de l’application. La base de données est automatiquement décompressée par le plugin.

À noter qu’une exécution longue dans le processus principal d’une application Android peut mener à une erreur. En fonction de la taille de la base de données, la décompression/copie peut dépasser ce temps limite. Nous avons donc déplacé cette mécanique lourde dans une tâche asynchrone et nous affichons une boîte de dialogue qui indique que l’application est en cours d’initialisation pendant l’exécution de cette tâche.

La dernière étape consiste à intégrer le plugin dans le code d’initialisation de l’application. Cela consiste à :

  • Importer le package “org.smile.websqldatabase.*”,
  • Faire implémenter "DatabaseInitializable" à la classe principale de l’application,
  • Implémenter la méthode “getDatabaseConfig” en fournissant les noms des fichiers, vos messages internationalisés, …,
  • Implémenter la méthode “loadWebApp” en y déplaçant le code d’initialisation de l’application Cordova (présent dans la méthode “onCreate” générée par la création d’un projet PhoneGap),
  • Supprimer le code d’initialisation Cordova présent initialement dans la méthode “onCreate”,
  • Ajouter le code de chargement de la base de données au démarrage de l’application en insérant le code "DatabaseInitializer.load(this);" dans la méthode “onCreate”.

Le code résultant de la classe d’initialisation est alors de la forme suivante :

import android.os.Bundle;
import org.apache.cordova.*;
import org.smile.websqldatabase.*;
public class WebSqlDatabaseInitializerProto extends CordovaActivity implements DatabaseInitializable {
  @Override
  public void onCreate(Bundle savedInstanceState) {
     super.onCreate(savedInstanceState);
     super.init();
     DatabaseInitializer.load(this);
  }
  @Override
  public DatabaseConfig getDatabaseConfig() {
     DatabaseConfig databaseConfig = new DatabaseConfig("myDemoSQLiteDB.zip", "myDemoSQLiteDB.db");
     return databaseConfig;
  }
  @Override
  public void loadWebApp() {
     super.loadUrl(Config.getStartUrl());
  }
}
Cas iOS
Étude de fonctionnement

Si l'on crée, sur un terminal iOS, une base de données par l'API Web SQL Database en effectuant un appel à la fonction “openDatabase”, le fichier SQLite résultant est créé dans l’un des répertoires suivants en fonction de la version d’iOS :

  • /var/mobile/Applications/[ApplicationID]/Library/WebKit/Databases/ (version < 5.1),
  • /var/mobile/Applications/[ApplicationID]/Library/Caches/ (5.1 <= version < 6.0),
  • /var/mobile/Applications/[ApplicationID]/Library/WebKit/LocalStorage/ (6.0 <= version).

L’arborescence au sein du répertoire précédemment défini est la suivante :

.
├── Databases.db
├── file__0
│   ├── 0000000000000001.db

De même que pour Android, nous retrouvons les fichiers “Databases.db” et “0000000000000001.db”.

Afin de pré-charger une base de données, il s'agit donc de respecter cette structure pour « bluffer » le système et faire croire que la base de données a été créée précédemment via l’API Web SQL Database.

Le nom “0000000000000001.db” n’étant pas parlant, et afin d’uniformiser avec le nommage pour Android, nous allons l’adapter en utilisant “myDemoSQLiteDB.db” à la place. Afin que cette base soit correctement référencée par WebKit, nous veillerons à fournir le même nom lors de la création du fichier Databases.db.

Utilisation du plugin

La première étape consiste à ajouter le fichier "Databases.db" et le fichier zippé de base de données dans le dossier “Resources” afin qu’ils soient packagés dans l’application. L’arborescence du projet iOS est alors de la forme suivante :

.
├── [projectName]
│   ├── Classes
│   ├── Plugins
│   ├── Resources
│   │   ├── … 
│   │   ├── Databases.db
│   │   ├── myDemoSQLiteDB.zip

Il faut ensuite ajouter le plugin via la commande suivante (identique pour l’ensemble des OS) :

cordova plugin add org.smile.websqldatabase.initializer

Le plugin contient l’ensemble de la mécanique nécessaire à la copie des fichiers fournis dans le dossier “Resources” vers le dossier de destination lors du premier lancement de l’application.
La base de données fournie étant compressée, il est nécessaire d’avoir une bibliothèque de décompression. Pour cela, nous utilisons “ZipArchive”, qui nécessite le framework “libz.1.2.5.dylib”. Le code de “ZipArchive” est fourni dans le plugin et l’ajout de la lib “libz.1.2.5.dylib” est effectué automatiquement par l’installation du plugin via la ligne de commande ci-dessus.

À noter que, dans le cas d’une version d’iOS comprise entre 5.1 et 6 (exclus), la base étant stockée dans un dossier “Caches” dont la pérennité n’est pas assurée, Cordova inclut un mécanisme de backup/restore des bases de données dans le dossier “/var/mobile/Applications/[ApplicationID]/Documents” qui, lui, est pérenne. La base de données peut donc être présente en 3 exemplaires sur le terminal : une version zippée dans l’application packagée, une version dézippée dans le dossier Caches et une version de backup (dézippée) dans le dossier “Documents”.

La dernière étape consiste à intégrer le plugin dans le code d’initialisation de l’application. Cela consiste à :

  • Importer "LoadDatabase.h" et "DatabaseConfig.h" dans la classe principale de l’application (habituellement “AppDelegate.m”),
  • Appeler, dans la méthode “init” de la classe principale de l’application, la méthode “load” sur un objet "LoadDatabase" avec en paramètre l’objet “DatabaseConfig” correctement initialisé.

Le code résultant de la classe d’initialisation est alors de la forme suivante :

#import "AppDelegate.h"
#import "MainViewController.h"
 
#import <Cordova/CDVPlugin.h>
 
#import "LoadDatabase.h"
#import "DatabaseConfig.h"
 
@implementation AppDelegate
 
@synthesize window, viewController;
 
- (id)init
{
    [[LoadDatabase new] load:[[DatabaseConfig alloc] init:@"myDemoSQLiteDB.zip" secondValue:@"myDemoSQLiteDB.db"]];
 
    NSHTTPCookieStorage* cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
    …
}
Cas Windows Phone 7/8
Étude de fonctionnement

Si l'on utilise le plugin cordova-plugin-websqldatabase (voir l’article précédent pour plus de détails) sur un terminal Windows Phone 7/8, la création d’une base de données par l'API Web SQL Database en effectuant un appel à la fonction “openDatabase” génère un fichier dont le nom correspond au premier paramètre de l’appel de la fonction “openDatabase”.

Si l’on effectue l’appel openDatabase(“myDemoSQLiteDB.db”, ...), l’arborescence au sein de l’application est la suivante :

.
├── ...
├── myDemoSQLiteDB.db
├── myDemoSQLiteDB.db-journal

Afin de pré-charger une base de données, il s'agit donc de respecter cette structure pour « bluffer » le système et faire croire que la base de données a été créée précédemment via l’API Web SQL Database.

Notons que le fichier « -journal » permet de stocker des modifications qui n’ont pas encore été persistées dans le fichier “.db”. Si ce fichier n’est pas présent, le plugin cordova-plugin-websqldatabase ne sera pas en mesure de s’initialiser. Il est donc nécessaire de créer un fichier « -journal »vide pour que l’initialisation se passe correctement.

Utilisation du plugin

La première étape consiste à ajouter le fichier zippé de base de données dans le packaging de l’application. Pour ce faire, ajouter le fichier dans le dossier racine du projet (ou dans un dossier de votre choix) et définir la “Build Action” du fichier à “Content” (via Visual Studio) pour qu’il soit ajouté au packaging de l’application.

Il faut ensuite ajouter le plugin via la commande suivante (identique pour l’ensemble des OS) :

cordova plugin add org.smile.websqldatabase.initializer

L’ajout de ce plugin déclenche automatiquement l’ajout du plugin cordova-plugin-websqldatabase nécessaire pour ajouter la fonctionnalité Web SQL Database sous Windows Phone 7/8.

Le plugin contient l’ensemble de la mécanique nécessaire à la copie/décompression du fichier de base de données ainsi qu’à la création du « journal » lors du premier lancement de l’application.

La base de données fournie étant compressée, il est nécessaire d’avoir une bibliothèque de décompression. Pour cela, nous utilisons SharpGIS.UnZipper, dont le code source est fourni dans le plugin.

La dernière étape consiste à intégrer le plugin dans le code d’initialisation de l’application. Cela consiste à :

  • Importer "org.smile.websqldatabase" dans la classe principale de l’application (habituellement “MainPage.xaml.cs”),
  • Appeler, à l’initialisation de la classe principale de l’application, la méthode "LoadDatabase" sur un objet "DatabaseLoader" avec en paramètre l’objet “DatabaseConfig” correctement initialisé.

Le code résultant de la classe d’initialisation est alors de la forme suivante :

using System;using System.Windows.Resources;
 
using org.smile.websqldatabase;
 
namespace org.smile.proto
{
    public partial class MainPage : PhoneApplicationPage
    {
        public MainPage()
        {
            new DatabaseLoader().LoadDatabase(new DatabaseConfig(@"myDemoSQLiteDB.zip", @"myDemoSQLiteDB.db"));
 
            InitializeComponent();
            this.CordovaView.Loaded += CordovaView_Loaded;
        }
 
        private void CordovaView_Loaded(object sender, RoutedEventArgs e)
        {
            this.CordovaView.Loaded -= CordovaView_Loaded;
        }
    }
}
Mise à jour de la base de données

Par défaut, l’initialisation de la base de données n’est effectuée qu’au premier lancement de l’application après sa première installation (i.e. : lorsqu’aucune base de données Web SQL Database n’est encore présente dans le dossier de stockage des bases de données).

Afin de pouvoir traiter le cas d’une mise à jour de la base de données (lors d’une mise à jour de l’application par exemple), nous avons ajouté, pour l’ensemble des OS cibles, un attribut “forceReload” dans l’objet de configuration de la base de données.

Ainsi, il est possible de définir cet attribut à “true” pour forcer l’écrasement de la base de données par celle présente dans le packaging de l’application. Attention, toutes les données présentes dans la base pré-existante seront perdues. Par ailleurs, veillez à ne définir cet attribut à “true” qu’une seule fois pour éviter que la base soit réinitialisée à chaque démarrage de l’application.

Conclusion

Nous avons montré dans cette suite d’articles qu’il est possible d’étendre l’API Web SQL Database à Windows Phone 7/8 par le simple ajout d’un plugin PhoneGap/Cordova, et que l’initialisation de cette base de données peut être simplifiée et uniformisée pour les plates-formes iOS, Android et Windows Phone 7/8 par l’utilisation d’un second plugin PhoneGap/Cordova.

Voici enfin, un tableau récapitulatif :

 

cordova-plugin-websqldatabase

cordova-plugin-websqldatabase-initializer

Rôle

Implémente l’API Web SQL Database pour Windows Phone 7/8

Permet d’initialiser une base de données Web SQL Database à partir d’un fichier SQLite

GitHub

http://smile-sa.github.io/cordova-plugin-websqldatabase/

http://smile-sa.github.io/cordova-plugin-websqldatabase-initializer/

Cordova 3 CLI

cordova plugin add org.smile.websqldatabase.wpdb

cordova plugin add org.smile.websqldatabase.initializer

Prototype

https://github.com/Smile-SA/cordova-plugin-websqldatabase-proto

https://github.com/Smile-SA/cordova-plugin-websqldatabase-initializer-proto

Maxime ROBERT
picto

Commentaires

Soyez la premiere personne à ajouter un commentaire sur cet article.
Ecrire un nouveau commentaire