Saltar al contenido principal

Almacenamiento de claves-valor en Capacitor: Preferencias vs SQLite

Compare el almacenamiento de clave-valor en Capacitor: Preferencias, almacenes de clave-valor de SQLite y almacenamiento de Keychain.

Almacenamiento de clave-valor en Capacitor: Preferencias vs SQLite

For key-value storage in Capacitor, use @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.

La mayoría de las aplicaciones utilizan dos de estos al mismo tiempo: Preferencias o SQLite para el estado de la aplicación, y almacenamiento seguro para el token de autenticación.

Vista general de opciones

localStorage / IndexedDB @capacitor/preferences SQL rápido KeyValueStore @capgo/capacitor-data-storage-sqlite @capgo/capacitor-native-biometric setData
Basado en Almacenamiento de WebView Almacenamiento de Clave-Valor Archivo SQLite Archivo SQLite Clave / Almacén de claves
Resiste la limpieza de almacenamiento del sistema No está garantizado Sí Sí Sí Sí
Tipos de valor Cadenas (localStorage) Cadenas Valores JSON, números, booleanos Uint8Array Cadenas Cadenas
Buena gama de tamaños Pequeño Pequeño, unos pocos KB por valor Valores grandes, muchas claves Muchas claves Muy pequeño (menos de ~8 KB en Android)
Cifrado No No SQLCipher opcional, clave desde almacenamiento seguro SQLCipher opcional, contraseña en configuración Sí, respaldado por hardware
Nombres de espacio Por origen group opción store opción Tablas Nombres de clave
Consulta por prefijo No No Listar claves filtervalues No
Web Sí localStorage SQLite Wasm (OPFS) IndexedDB Not para secretos

¿Por qué no localStorage

localStorage y IndexedDB funcionan dentro de un WebView Capacitor, pero los datos pertenecen al WebView, no a la almacenamiento nativo de tu aplicación. El sistema operativo puede reclamar el almacenamiento del WebView cuando el dispositivo tenga poco espacio, y Capacitor recomienda en su propia documentación no confiar en él para datos que no puedes perder. Cambiar el nombre de host o el esquema de la aplicación capacitor.config también cambia el origen, que apunta el WebView a un almacenamiento vacío diferente.

Utilízalos como una caché que puede desaparecer. Utiliza una de las opciones respaldadas nativamente para todo lo demás.

Opción 1: Capacitor Preferencias para ajustes pequeños

@capacitor/preferences es el plugin oficial para datos de valor clave ligeros. En iOS escribe a UserDefaultsen Android a SharedPreferencesy en la web a 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) });
}

Usa para: tema, idioma, banderas de onboarding, la última pestaña seleccionada, interruptores de características.

No uses para:

  • Secretos. Los valores se almacenan en texto plano dentro del entorno de la aplicación, y se incluyen en respaldos de dispositivos.
  • Valores grandes. UserDefaults y SharedPreferences cargar su archivo completo en memoria. Los grandes blobs JSON ralentizan cada lectura y escritura.
  • Muchas claves que necesitas listar o borrar por prefijo. keys() Muchos claves que necesitas listar o eliminar por prefijo.

Preferences.configure({ group: 'MyApp' }) cambia el espacio de nombres donde se almacenan las claves. El grupo predeterminado es CapacitorStorage.

Opción 2: un almacén de claves-valor SQLite

Once you store cached API responses, drafts, offline queues or hundreds of entries, a SQLite file is a better home. It handles large values, writes are atomic, and you can encrypt it.

Almacenamiento de Clave y Valor de SQL Rápido

@capgo/capacitor-fast-sql incluye KeyValueStore Clase encima de su conexión a SQLite. Crea un __kv_store tabla, mantiene el tipo de valor y admite múltiples almacenes con nombres en una base de datos.

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

Fast SQL necesita dos ajustes nativos (red de área local en iOS en) Info.plistFast SQL necesita dos ajustes nativos (red de área local en iOS en) Cómo usar SQLite en una aplicación 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();

API resumen: open(options), fromConnection(connection, store), set, get (devuelve null cuando falta) has, remove, clear, keys, close.

Dos patrones que vale la pena conocer:

Varios almacenes, una base de datos. La store espacios de nombres opciones claves settings, drafts y api-cache pueden vivir lado a lado y ser eliminados de manera independiente.

Valor clave junto a las tablas reales. Si su aplicación ya utiliza Fast SQL para datos relacionales, reutilice la conexión en lugar de abrir una segunda:

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

Posteriormente, cuando un blob de valor clave crece hasta algo que desea consultar (por ejemplo, todos los borradores más antiguos de una semana), puede moverlo a una tabla adecuada en la misma base de datos.

Almacenamiento de valor clave cifrado

KeyValueStore.open acepta las mismas opciones que FastSQL.connectincluyendo encrypted y encryptionKey en iOS y 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(),
});

Este requiere SQLCipher en las compilaciones nativas. La configuración, más lo que hacer cuando la clave se pierda después de una restauración de respaldo, está en Cómo cifrar una base de datos SQLite en Capacitor.

@capgo/capacitor-almacenamiento-de-datos-sqlite

@capgo/capacitor-data-storage-sqlite is un plugin de valor clave dedicado en SQLite (originalmente por Jean Pierre Quéau, ahora mantenido por Capgo). Los valores son cadenas de texto, y agrega algunas extras: múltiples tablas por almacén, filtrado por prefijo y sufijo, y importación y exportación de 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 aplica el filtro como un patrón SQL LIKE patrón en la clave ("note% para un prefijo, %note para un sufijo, texto plano para contiene). El patrón se inserta en la cadena SQL, así que solo pasa filtros que controlas, nunca entrada de usuario bruta.

En la web utiliza IndexedDB a través de localforageque instalas por separado:

bun add localforage

Sobre su cifrado: openStore({ encrypted: true, mode: 'secret' }) usa SQLCipher con una contraseña de capacitor.config bajo plugins.CapgoCapacitorDataStorageSqlite.encryptionSecretLa contraseña se envía dentro de tu paquete de la aplicación, y si no la estableces el plugin cae en un valor predeterminado incorporado. Trátalo como protección contra inspección de archivos casual, no contra alguien que desempaqueta tu aplicación. Para secretos reales usa una clave de la Keychain o Keystore, como en el ejemplo de Fast SQL anterior.

Fast SQL KeyValueStore o data-storage-sqlite?

  • Elige SQL rápido KeyValueStore si deseas valores tipados sin JSON manual, valores binarios, una clave de cifrado en tiempo de ejecución o ya usas SQL rápido para tablas.
  • Elige datos-storage-sqlite si necesitas sus características de tabla y filtro, exportación e importación de JSON o soporte para Electron.

Opción 3: Clave maestra y almacén de claves para secretos

Auth tokens, refresh tokens, API keys and database encryption keys belong in platform secure storage. @capgo/capacitor-native-biometric (8.6.0 y posterior) expone un almacenamiento de claves-valor genérico API sobre el Keychain de iOS y el Keystore de 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' });

Mantén los valores pequeños. El plugin documenta que el cifrado respaldado por el Almacén de claves de Android funciona mejor con unos 8 KB por valor. Si necesitas proteger una gran cantidad de datos, almacena una clave aleatoria aquí y úsala para cifrar una base de datos SQLite. Nuestro post sobre almacenamiento seguro para tokens offline explora más a fondo el manejo de tokens.

Recuerde que los elementos de Keychain en iOS pueden sobrevivir a la desinstalación de la aplicación. Al iniciar la aplicación por primera vez después de una instalación fresca, elimine secretos caducos si su aplicación espera una pizarra limpia (almacenar una bandera de 'primera ejecución realizada' en Preferencias, que se elimina al desinstalar, y borrar entradas de Keychain cuando no está presente).

Elige: una lista de decisiones

  1. ¿Es un secreto? Token, contraseña, PIN, clave. Utilice el almacenamiento de Keychain o Keystore.
  2. ¿Es un par de ajustes pequeños? Utilice Preferencias.
  3. ¿Son varias entradas, grandes JSON, datos binarios o caché que desee eliminar y borrar en grupos? Utilice un almacén de clave-valor SQLite.
  4. ¿Necesita filtrar, ordenar o unirlo? No es más datos de clave-valor. Crea una tabla, consulte el Guía de SQLiteo utilice una capa tipificada como Kysely.

Migrar datos existentes entre almacenes

Desplazarse desde localStorage o Preferencias a un almacén SQLite es una copia única en arranque. Hazlo antes de que el resto de la aplicación lea datos, y registra que se ejecutó.

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;
}

Elimina secretos del almacén antiguo tan pronto como se copien en almacenamiento seguro. Dejar un token en Preferencias después de moverlo a la Caja de Clave mantiene la exposición original.

Porque este code se ejecuta en JavaScript, puedes enviarlo con un Capgo live updateLa propia extensión SQLite es nativa, por lo que la versión que la agrega necesita un build de almacenamiento. Envíe la extensión primero, luego la migración code.

Solución de problemas

Preferencias de valores son null Los valores de Preferencias son después de una actualización en la web. localStorage es un almacenamiento diferente y vacío.

Fast SQL KeyValueStore.open lanza una excepción en iOS. El canal HTTP local está bloqueado. Agregue NSAllowsLocalNetworking a Info.plist y reconstruya la aplicación nativa.

get devuelve una cadena donde esperabas un objeto en data-storage-sqlite. Ese plugin almacena solo cadenas. JSON.parse el valor.

Faltan secretos después de restaurar una copia de seguridad en un nuevo teléfono. Las claves del keystore y los elementos de Keychain solo para dispositivos no se transfieren a nuevos hardware. Trata el almacenamiento seguro como una caché de credenciales que puedes recuperar nuevamente al iniciar sesión de nuevo.

Configuraciones perdidas después de reinstalar pero tokens todavía presentes en iOS. Esperado: Las preferencias se eliminan con la aplicación, pero los elementos de Keychain pueden permanecer. Utilice el patrón de bandera de ejecución inicial arriba.

Resumen

  • Preferencias: ajustes pequeños y no sensibles.
  • Almacén de claves de SQLite (Fast SQL KeyValueStore o @capgo/capacitor-data-storage-sqliteo valores muchos o grandes, caché, borradores, opcionalmente cifrados.
  • Keychain o Keystore (@capgo/capacitor-native-biometric setDataReferencias de plugins:

Documentación de Fast SQL Documentación de data-storage-sqlite, almacenamiento-de-datos-sqlitey el plugin de biometría nativa de página.

Actualizaciones en vivo para aplicaciones 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.

Últimas noticias de nuestro Blog

Capgo gives you the best insights you need to create a truly professional mobile app.