Allez directement au contenu principal

Stockage Clé-Valeur dans Capacitor: Préférences vs SQLite

Compare le stockage clé-valeur dans Capacitor: les préférences, les magasins de clés-valeurs SQLite et le stockage Keychain. Découvrez lequel convient aux paramètres, à la cache et aux secrets.

Crédits de l'article

Martin Donadieu

Auteur

Valeria

Relecteur

Jordan

Éditeur

Stockage de clés-valeurs dans Capacitor: Préférences vs SQLite

Pour le stockage de clés-valeurs dans Capacitor, utilisez @capacitor/preferences for a handful of small settings, a SQLite-backed key-value store for anything larger or more numerous, and the Keychain or Keystore for secrets. This guide compares the options available on Capacitor 8, shows working code for each, and explains how to move from one to another without losing user data.

Most apps end up using two of these at once: Preferences or SQLite for app state, and secure storage for the auth token.

Vue d'ensemble des options

localStorage / IndexedDB @capacitor/preferences SQL rapide KeyValueStore @capgo/capacitor-data-storage-sqlite @capgo/capacitor-native-biometric setData
Appuyé par Stockage de la vue Web UserDefaults / SharedPreferences Fichier SQLite Fichier SQLite Clé / Keystore
Survit la suppression de stockage système Non garanti Oui Oui Oui Oui
Types de valeurs Chaine de caractères (localStorage) Strings Valeurs JSON, nombres, booléens, Uint8Array Strings Strings
Bonnes tailles de plage Petit Petit, quelques Mo de valeurs par valeur Valeurs importantes, nombreuses clés Nombreuses clés Très petites (sous ~8 Ko sur Android)
Chiffrement Non Non SQLCipher facultatif, clé depuis stockage sécurisé SQLCipher facultatif, mot de passe dans la configuration Oui, sécurisé par matériel
Noms d'espace Par origine group option store option Tables Noms de clés
Rechercher par préfixe Non Non Lister les clés filtervalues Non
Web Oui localStorage SQLite Wasm (OPFS) IndexedDB Not pour les secrets

Pourquoi pas localStorage

localStorage et IndexedDB fonctionnent à l'intérieur d'un Capacitor WebView, mais les données appartiennent au WebView, et non à l'entrepôt de stockage natif de votre application. Le système d'exploitation peut récupérer l'espace de stockage WebView lorsque le dispositif manque d'espace, et Capacitor recommande dans sa propre documentation de ne pas s'appuyer dessus pour des données que vous ne pouvez pas perdre. La modification de l'hôte de l'application ou du schéma dans capacitor.config change également l'origine, qui pointe le WebView vers un entrepôt de stockage vide différent.

Utilisez-les comme un cache qui peut disparaître. Utilisez l'une des options basées sur l'entrepôt natif pour tout le reste.

Option 1 : Capacitor Préférences pour les paramètres de petite taille

@capacitor/preferences est le plugin officiel pour les données de clé-valeur légères. Sur iOS, il écrit dans UserDefaultssur Android dans SharedPreferenceset sur le web dans localStorage.

bun add @capacitor/preferences
bunx cap sync
import { Preferences } from '@capacitor/preferences';

interface Settings {
  theme: 'light' | 'dark' | 'system';
  fontScale: number;
}

const DEFAULTS: Settings = { theme: 'system', fontScale: 1 };

export async function loadSettings(): Promise<Settings> {
  const { value } = await Preferences.get({ key: 'settings' });
  return value ? { ...DEFAULTS, ...JSON.parse(value) } : DEFAULTS;
}

export async function saveSettings(settings: Settings): Promise<void> {
  await Preferences.set({ key: 'settings', value: JSON.stringify(settings) });
}

Utilisez-le pour : thème, langue, drapeaux d'inscription, dernier onglet sélectionné, commutateurs de fonctionnalité.

Ne l'utilisez pas pour :

  • Les secrets. Values are stored in plaintext inside the app sandbox, and are included in device backups.
  • Valeurs importantes. UserDefaults et SharedPreferences charge leur fichier entier en mémoire. Les gros blobs JSON ralentissent chaque lecture et écriture.
  • Beaucoup de clés que vous devez lister ou effacer par préfixe. keys() renvoie tout, donc vous filtrez en JavaScript.

Preferences.configure({ group: 'MyApp' }) modifie l'espace de noms dans lequel les clés sont stockées. Le groupe par défaut est CapacitorStorage.

Option 2 : un stockage clé-valeur SQLite

Une fois que vous stockez des réponses API mises en cache, des brouillons, des files d'attente hors ligne ou des centaines d'entrées, un fichier SQLite est un meilleur domicile. Il gère les valeurs importantes, les écritures sont atomiques, et vous pouvez le chiffrer.

Stockage clé-valeur SQL rapide

@capgo/capacitor-fast-sql comprend un KeyValueStore classe au-dessus de sa connexion SQLite. Elle crée un __kv_store table, conserve le type de valeur, et prend en charge plusieurs magasins nommés dans une seule base de données.

bun add @capgo/capacitor-fast-sql
bunx cap sync

Fast SQL a besoin de deux paramètres natifs (réseautique locale iOS dans Info.plist, une règle de clartext localhost sur Android). Ils sont couverts dans Comment utiliser SQLite dans une application Capacitor.

import { KeyValueStore } from '@capgo/capacitor-fast-sql';

const cache = await KeyValueStore.open({ database: 'app', store: 'api-cache' });

// Objects, arrays, numbers, booleans, null and Uint8Array are stored as-is
await cache.set('user:42', { id: 42, name: 'Ada', roles: ['admin'] });
await cache.set('lastSync', Date.now());

const user = (await cache.get('user:42')) as { id: number; name: string } | null;
const exists = await cache.has('lastSync');
const allKeys = await cache.keys();

await cache.remove('user:42');
await cache.clear(); // only clears the 'api-cache' store
await cache.close();

Résumé API: open(options), fromConnection(connection, store), set, get (retourne null lorsque manquant), has, remove, clear, keys, close.

Deux modèles dignes de connaître:

Plusieurs magasins, une base de données. La store options des namespaces des clés settings, drafts et api-cache peuvent coexister et être supprimés séparément.

Clés-valeurs à côté des tables réelles. Si votre application utilise déjà Fast SQL pour les données relationnelles, réutilisez la connexion au lieu d'ouvrir une deuxième connexion :

import { FastSQL, KeyValueStore } from '@capgo/capacitor-fast-sql';

const db = await FastSQL.connect({ database: 'app' });
const drafts = await KeyValueStore.fromConnection(db, 'drafts');
// You own `db`: drafts.close() does not disconnect it

Plus tard, lorsque le blob clés-valeurs augmente en taille et que vous souhaitez le requêter (tous les brouillons plus anciens d'une semaine, par exemple), vous pouvez le déplacer dans une table propre dans la même base de données.

Stockage clés-valeurs chiffré

KeyValueStore.open accepte les mêmes options que FastSQL.connect, y compris encrypted et encryptionKey sur iOS et Android :

import { KeyValueStore } from '@capgo/capacitor-fast-sql';
import { NativeBiometric } from '@capgo/capacitor-native-biometric';

async function getKey(): Promise<string> {
  const { isSaved } = await NativeBiometric.isDataSaved({ key: 'kv.key' });
  if (isSaved) return (await NativeBiometric.getData({ key: 'kv.key' })).value;
  const bytes = crypto.getRandomValues(new Uint8Array(32));
  const key = Array.from(bytes, (b) => b.toString(16).padStart(2, '0')).join('');
  await NativeBiometric.setData({ key: 'kv.key', value: key });
  return key;
}

const secureStore = await KeyValueStore.open({
  database: 'secure-kv',
  encrypted: true,
  encryptionKey: await getKey(),
});

Cela nécessite SQLCipher dans les builds natifs. La configuration, ainsi que ce qu'il faut faire lorsque la clé est perdue après un rétablissement de sauvegarde, est dans Comment chiffrer une base de données SQLite dans Capacitor.

à @capgo/capacitor-data-storage-sqlite

@capgo/capacitor-data-storage-sqlite est un plugin de clés-valeurs dédié sur SQLite (initialement par Jean Pierre Quéau, maintenant maintenu par Capgo). Les valeurs sont des chaînes de caractères, et il ajoute quelques extras : plusieurs tables par magasin, filtrage par préfixe et suffixe, et import et export JSON.

bun add @capgo/capacitor-data-storage-sqlite
bunx cap sync
import { CapgoCapacitorDataStorageSqlite as Store } from '@capgo/capacitor-data-storage-sqlite';

await Store.openStore({ database: 'appStore', table: 'settings' });

await Store.set({ key: 'locale', value: 'fr' });
await Store.set({ key: 'profile', value: JSON.stringify({ name: 'Ada' }) });

const { value } = await Store.get({ key: 'locale' });
const { result: hasProfile } = await Store.iskey({ key: 'profile' });
const { keys } = await Store.keys();

// Switch table inside the same store
await Store.setTable({ table: 'drafts' });
const { values } = await Store.filtervalues({ filter: 'note%' }); // values whose key starts with "note"

await Store.remove({ key: 'note-1' });
await Store.clear(); // clears the current table

filtervalues applique le filtre comme un modèle SQL LIKE motif sur la clé ("note% pour un préfixe, %note pour un suffixe, texte brut pour contient). Le modèl’est inséré dans la chaîne SQL, passez donc uniquement des filtres que vous contrôlez, jamais des entrées utilisateur brutes.

Sur le web, il utilise IndexedDB via localforageque vous installez séparément :

bun add localforage

À propos de son chiffrement : openStore({ encrypted: true, mode: 'secret' }) utilise SQLCipher avec un mot de passe provenant de capacitor.config sous plugins.CapgoCapacitorDataStorageSqlite.encryptionSecretCe mot de passe est embarqué dans votre bundle d'application, et si vous ne le définissez pas, le plugin retombe sur une valeur par défaut intégrée. Traitez cela comme une protection contre l'inspection de fichiers non autorisée, pas contre quelqu'un qui décompresse votre application. Pour les secrets réels, utilisez une clé de la Keychain ou du Keystore, comme dans l'exemple Fast SQL ci-dessus.

KeyValueStore SQL rapide ou data-storage-sqlite ?

  • Choisissez SQL rapide KeyValueStore Si vous souhaitez des valeurs typées sans JSON manuel, des valeurs binaires, une clé de chiffrement en temps réel ou utilisez déjà Fast SQL pour les tables.
  • Choisissez stockage-de-données-sqlite Si vous avez besoin de ses fonctionnalités de table et de filtre, de l'export-import JSON ou de l'appui à Electron.

Option 3 : Clés de chaîne et coffre-fort pour les secrets

Auth tokens, refresh tokens, API keys and database encryption keys belong in platform secure storage. @capgo/capacitor-native-biometric (8.6.0 et ultérieur) expose une clé-valeur générique API au-dessus de la clé de chiffrement iOS et du coffre-fort Android.

bun add @capgo/capacitor-native-biometric
bunx cap sync
import { AccessControl, NativeBiometric } from '@capgo/capacitor-native-biometric';

// Silent read and write
await NativeBiometric.setData({ key: 'session.refreshToken', value: token });
const { value: refreshToken } = await NativeBiometric.getData({ key: 'session.refreshToken' });

// Require Face ID / Touch ID / fingerprint to read
await NativeBiometric.setData({
  key: 'wallet.pin',
  value: pin,
  accessControl: AccessControl.BIOMETRY_ANY,
});
const { value: secretPin } = await NativeBiometric.getSecureData({
  key: 'wallet.pin',
  reason: 'Confirm it is you',
});

await NativeBiometric.deleteData({ key: 'session.refreshToken' });

Conservez les valeurs petites. Le plugin indique que le chiffrement basé sur le coffre-fort Android fonctionne le mieux sous environ 8 Ko par valeur. Si vous avez besoin de protéger beaucoup de données, stockez une clé aléatoire ici et utilisez-la pour chiffrer une base de données SQLite. Notre article sur le stockage sécurisé des jetons hors ligne explique plus en détail la gestion des jetons.

Remember that Keychain items on iOS can outlive an app uninstall. On first launch after a fresh install, clear stale secrets if your app expects a clean slate (store a “first run done” flag in Preferences, which is removed on uninstall, and wipe Keychain entries when it is missing).

Choisir : une liste de décision

  1. Est-ce un secret ? Mot de passe, jeton, clé. Utilisez le stockage de Keychain ou Keystore.
  2. Est-ce quelques petites paramètres ? Utilisez les Préférences.
  3. Voulez-vous expirer et effacer de nombreux entrées, de grandes données JSON, de données binaires ou une cache en groupes ? Utilisez un stockage clé-valeur SQLite.
  4. Avez-vous besoin de filtrer, trier ou le joindre ? Ce n'est plus des données clé-valeur. Créez une table, consultez le guide Guide de SQLite, ou utilisez une couche de type comme Kysely.

Migrer les données existantes entre les magasins

Passer de localStorage ou Préférences à un magasin SQLite est une copie unique au démarrage. Faites-l’avant que le reste de l'application ne lit les données, et enregistrez que cela a fonctionné.

import { Preferences } from '@capacitor/preferences';
import { KeyValueStore, type KeyValueValue } from '@capgo/capacitor-fast-sql';

export async function migrateToSqliteStore(): Promise<KeyValueStore> {
  const kv = await KeyValueStore.open({ database: 'app', store: 'settings' });
  if (await kv.has('__migrated_v1')) return kv;

  const { keys } = await Preferences.keys();
  for (const key of keys) {
    const { value } = await Preferences.get({ key });
    if (value === null) continue;
    let parsed: KeyValueValue = value;
    try {
      parsed = JSON.parse(value) as KeyValueValue;
    } catch {
      // keep plain strings as strings
    }
    await kv.set(key, parsed);
  }

  // Also copy from localStorage if older versions used it
  for (let i = 0; i < localStorage.length; i++) {
    const key = localStorage.key(i);
    if (key && !(await kv.has(key))) {
      await kv.set(key, localStorage.getItem(key));
    }
  }

  await kv.set('__migrated_v1', true);
  // Remove the old copies only after a release or two, once you are confident
  return kv;
}

Supprimez les secrets du magasin ancien dès qu'ils sont copiés dans un stockage sécurisé. Laisser un jeton dans Préférences après le déplacement vers la clé de cryptage conserve l'exposition initiale.

Puisque ce code fonctionne en JavaScript, vous pouvez le livrer avec un Capgo live updateLe plugin SQLite lui-même est natif, donc la mise à jour qui l'ajoute nécessite une construction de magasin. Livrez le plugin en premier, puis la migration code.

Troubleshooting

Valeurs de préférences sont null Les valeurs de Préférences sont L'origine a changé (port, nom de hôte ou schéma), donc localStorage est un magasin vide différent.

SQL rapide KeyValueStore.open lance une erreur sur iOS. Le canal HTTP local est bloqué. Ajoutez NSAllowsLocalNetworking à Info.plist et reconstruisez l'application native.

get renvoie une chaîne au lieu d'un objet dans data-storage-sqlite. Ce plugin ne stocke que des chaînes. JSON.parse la valeur.

Les secrets manquent après restauration d'un sauvegarde sur un nouveau téléphone. Keystore keys and device-only Keychain items do not transfer to new hardware. Treat secure storage as a cache of credentials you can re-obtain by signing in again.

Paramètres perdus après réinstallation mais les jetons sont toujours présents sur iOS. Préférences : supprimées avec l'application, les éléments de Keychain peuvent rester. Utilisez le modèle de flag de première utilisation ci-dessus.

Résumé

  • Préférences : paramètres petits et non sensibles.
  • Stockage clé-valeur SQLite (Fast SQL KeyValueStore ou @capgo/capacitor-data-storage-sqlitebeaucoup de valeurs ou de grande taille, cache, brouillons, chiffrés optionnellement.
  • Cléchain ou Cléstockage@capgo/capacitor-native-biometric setDataclés de secrets et de clés d'encryption.

Références de plugins : Stockage SQL rapide, stockage-de-données-sqlitecontext page native de plugin biométrique.

Mises à jour instantanées pour les applications Capacitor

When a web-layer bug is live, ship the fix through Capgo instead of waiting days for app store approval. Users get the update in the background while native changes stay in the normal review path.

Dernières actualités de notre Blog

Capgo vous offre les meilleures informations nécessaires pour créer une application mobile véritablement professionnelle.