Lompat ke konten utama

Penggunaan Penyimpanan Nilai Kunci di Capacitor: Preferensi vs SQLite

Pilih penyimpanan kunci-nilai di Capacitor: Preferensi, penyimpanan kunci-nilai SQLite, dan penyimpanan kunci Keychain.

Kredit artikel

Martin Donadieu

Pengarang

Valeria

Pengulas

Jordan

Pengedit

Penyimpanan Kunci-Nilai di Capacitor: Preferensi vs SQLite

Untuk penyimpanan kunci-nilai di Capacitor, gunakan @capacitor/preferences untuk beberapa pengaturan kecil, penyimpanan kunci-nilai SQLite yang didukung untuk apa pun yang lebih besar atau lebih banyak, dan Keychain atau Keystore untuk rahasia. Panduan ini membandingkan opsi yang tersedia di Capacitor 8, menampilkan contoh kerja code untuk setiap opsi, dan menjelaskan cara beralih dari satu ke opsi lainnya tanpa kehilangan data pengguna.

Banyak aplikasi akhirnya menggunakan dua di antara mereka secara bersamaan: Preferensi atau SQLite untuk keadaan aplikasi, dan penyimpanan aman untuk token autentikasi.

Ringkasan pilihan

localStorage / IndexedDB @capacitor/preferences Fast SQL KeyValueStore @capgo/capacitor-data-storage-sqlite @capgo/capacitor-native-biometric setData
Ditopang oleh Penyimpanan WebView Pengaturan Nilai Pengguna File SQLite File SQLite Penyimpanan Kunci
Tahan terhadap pembaruan penyimpanan OS Tidak dijamin Iya Ya Ya Ya
Jenis nilai Nilai string (localStorage) Nilai string Nilai JSON, bilangan, boolean, Uint8Array Nilai string Nilai string
Rentang ukuran yang baik Kecil Kecil, beberapa KB per nilai Nilai besar besar, banyak kunci Banyak kunci Terlalu kecil (di bawah ~8 KB pada Android)
Enkripsi Tidak Tidak Opsional SQLCipher, kunci dari penyimpanan yang aman Opsional SQLCipher, sandi dalam konfigurasi Ya, didukung oleh perangkat keras
Nama Ruang Per asal group Pilihan store pilihan Tabel Nama kunci
Cari dengan awalan Tidak Tidak Tampilkan kunci filtervalues Tidak
Web Iya localStorage SQLite Wasm (OPFS) IndexedDB Not untuk rahasia

Mengapa tidak menggunakan localStorage

localStorage and IndexedDB work inside a Capacitor WebView, but the data belongs to the WebView, not to your app’s native storage. The OS can reclaim WebView storage when the device runs low on space, and Capacitor’s own documentation recommends against relying on it for data you cannot lose. Changing the app’s hostname or scheme in capacitor.config juga mengubah asal, yang menunjuk WebView ke penyimpanan kosong yang berbeda.

Pakai mereka sebagai cache yang dapat menghilang. Gunakan salah satu pilihan yang didukung oleh penyimpanan asli untuk semua yang lain.

Option 1: Capacitor Preferensi untuk pengaturan ringan

@capacitor/preferences adalah plugin resmi untuk data nilai kunci ringan. Pada iOS, menulis ke UserDefaultspada Android ke SharedPreferencespada web ke 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) });
}

Pakai untuk: tema, bahasa, flag onboarding, tab terakhir yang dipilih, toggle fitur.

Tidak pakai untuk: Rahasia.

  • Secrets. Nilai disimpan dalam teks biasa di dalam sandbox aplikasi, dan termasuk dalam cadangan perangkat.
  • Nilai besar. UserDefaults dan SharedPreferences mengisi seluruh file mereka ke dalam memori. Blok JSON besar memperlambat setiap baca dan tulis.
  • Banyak kunci yang perlu Anda daftar atau hapus dengan awalan. keys() mengembalikan semuanya, sehingga Anda dapat menyaring di JavaScript.

Preferences.configure({ group: 'MyApp' }) mengubah nama ruang kunci yang disimpan di bawahnya. Kelompok default adalah CapacitorStorage.

Pilihan 2: penyimpanan kunci-nilai SQLite

Setelah Anda menyimpan respons API yang dicadangkan, draft, antrian offline, atau ratusan entri, file SQLite adalah rumah yang lebih baik. Ini mengatasi nilai besar, tulisan atomik, dan Anda dapat mengenkripsinya.

Penyimpanan Kunci-Nilai SQL Cepat

@capgo/capacitor-fast-sql termasuk KeyValueStore kelas di atas koneksi SQLite-nya. Ini menciptakan __kv_store mengatur jenis nilai, dan mendukung beberapa penyimpanan bernama dalam satu database.

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

Fast SQL memerlukan dua pengaturan asli (jaringan lokal iOS di Info.plist, aturan localhost jelas pada Android). Mereka dibahas dalam Cara Menggunakan SQLite di Aplikasi 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();

Ringkasan API: open(options), fromConnection(connection, store), set, get (mengembalikan null ketika hilang), has, remove, clear, keys, close.

Beberapa pola yang perlu diketahui:

Beberapa penyimpanan, satu database. Opsi store menggunakan namespace kunci, sehingga settings, drafts dan (And) api-cache bisa hidup berdampingan dan dihapus secara independen.

Kunci-nilai di samping tabel nyata. Jika aplikasi Anda sudah menggunakan Fast SQL untuk data relasional, gunakan koneksi yang sama lagi daripada membuka koneksi kedua:

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

Di kemudian hari, ketika blob kunci-nilai tumbuh menjadi sesuatu yang ingin Anda cari (contoh: semua draft yang lebih tua dari seminggu), Anda bisa memindahkannya ke tabel yang tepat di database yang sama.

Penyimpanan kunci-nilai yang dienkripsi

KeyValueStore.open menerima opsi yang sama seperti FastSQL.connecttermasuk encrypted dan encryptionKey di iOS dan 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(),
});

Ini memerlukan SQLCipher pada bangun native. Konfigurasi, serta apa yang harus dilakukan ketika kunci hilang setelah restorasi backup, dapat ditemukan di Cara mengenkripsi basis data SQLite di Capacitor.

@capgo/capacitor-data-storage-sqlite

@capgo/capacitor-data-storage-sqlite is sebuah plugin kunci-nilai yang khusus untuk SQLite (dahulu oleh Jean Pierre Quéau, sekarang dipelihara oleh Capgo). Nilai-nilai adalah string, dan itu menambahkan beberapa fitur tambahan: beberapa tabel per toko, penyaringan awalan dan akhir, dan import dan 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 menerapkan penyaringan sebagai SQL LIKE polanya pada kunci (note% untuk awalan, %note untuk akhir, teks biasa untuk mengandung). Pola tersebut dimasukkan ke dalam string SQL, jadi hanya lewatkan penyaringan yang Anda kendalikan, tidak pernah input pengguna mentah.

Pada web itu menggunakan IndexedDB melalui localforageyang Anda instal secara terpisah:

bun add localforage

Tentang enkripsinya: openStore({ encrypted: true, mode: 'secret' }) menggunakan SQLCipher dengan kata sandi dari capacitor.config bawah plugins.CapgoCapacitorDataStorageSqlite.encryptionSecretKata sandi tersebut dikirimkan bersama dengan bundle aplikasi Anda, dan jika Anda tidak menyetelnya plugin tersebut akan kembali ke default bawaan. Tidaklah aman untuk menyimpan rahasia yang penting menggunakan metode ini. Gunakan kunci dari Keychain atau Keystore, seperti dalam contoh Fast SQL di atas.

Fast SQL KeyValueStore atau data-storage-sqlite?

  • Pilih Fast SQL KeyValueStore Jika Anda ingin nilai yang tipe dan tidak perlu JSON manual, nilai biner, kunci enkripsi waktu eksekusi, atau sudah menggunakan Fast SQL untuk tabel.
  • Pilih data-storage-sqlite Jika Anda membutuhkan fitur tabel dan filter, ekspor dan impor JSON, atau dukungan Electron.

Pilihan 3: Keychain dan Keystore untuk rahasia

Token autentikasi, token refresh, kunci API dan kunci enkripsi database masuk ke penyimpanan aman platform. @capgo/capacitor-native-biometric (8.6.0 dan lebih lanjut) mengungkapkan kunci nilai yang umum API di atas Keychain iOS dan Keystore 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' });

Pertahankan nilai kecil. Dokumen plugin menyatakan bahwa enkripsi Keystore Android bekerja dengan baik di bawah sekitar 8 KB per nilai. Jika Anda membutuhkan melindungi banyak data, simpan satu kunci acak di sini dan gunakan untuk mengenkripsi database SQLite. Artikel kami tentang penyimpanan aman untuk token offline menggali lebih dalam tentang pengelolaan token.

Ingatlah bahwa item Keychain di iOS dapat bertahan lebih lama dari penghapusan aplikasi. Pada pertama kali menjalankan setelah instalasi segar, hapus rahasia yang kering jika aplikasi Anda mengharapkan permukaan yang bersih (simpan flag 'sudah dilakukan pertama kali' di Preferensi, yang dihapus pada penghapusan, dan hapus entri Keychain ketika itu hilang).

Pemilihan: daftar keputusan

  1. Apakah itu rahasia? Token, kata sandi, PIN, kunci. Gunakan penyimpanan Keychain atau Keystore.
  2. Apakah itu beberapa pengaturan kecil? Gunakan Preferensi.
  3. Apakah itu beberapa entri, JSON besar, data biner, atau cache yang ingin Anda hapus dan kelompokkan? Gunakan penyimpanan key-value SQLite.
  4. Do you need to filter, sort or join it? Tidak lagi data key-value. Buatlah tabel, lihat panduan SQLite Petunjuk SQLiteatau gunakan layer yang ditipekan seperti Kysely.

Migrasikan data yang sudah ada antara penyimpanan

Pindah dari localStorage atau Preferensi ke penyimpanan SQLite adalah salinan sekali saja pada startup. Lakukan sebelum aplikasi lain membaca data, dan catat bahwa itu sudah berjalan.

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

Hapus rahasia dari penyimpanan lama segera setelah mereka dicopy ke penyimpanan yang lebih aman. Tinggalkan token di Preferensi setelah memindahkannya ke Keychain tetap menjaga eksposur asli.

Karena ini code berjalan di JavaScript, Anda dapat mengirimkannya dengan Capgo live updateRilis SQLite plugin itu sendiri adalah native, jadi rilis yang menambahkannya membutuhkan build penyimpanan. Kirim plugin terlebih dahulu, kemudian migrasi code.

Troubleshooting

Nilai Preferensi null setelah pembaruan di web. Perubahan asal (port, hostname, atau scheme), sehingga localStorage is sebuah penyimpanan kosong yang berbeda.

SQL Cepat KeyValueStore.open mengeluarkan kesalahan pada iOS. Saluran HTTP lokal diblokir. Tambahkan NSAllowsLocalNetworking ke Info.plist rebuild aplikasi native.

get mengembalikan string di mana Anda mengharapkan objek di penyimpanan data-sqlite. dan bangun kembali aplikasi asli. JSON.parse Nilainya.

Rahasia hilang setelah mengembalikan cadangan pada ponsel baru. 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.

Rahasia hilang setelah mengembalikan cadangan di ponsel baru. Diharapkan: Preferensi dihapus bersama aplikasi, tetapi item Keychain dapat tetap ada. Gunakan pola flag pertama kali di atas.

Ringkasan

  • Preferensi: pengaturan kecil, tidak sensitif.
  • Penyimpanan nilai SQLite (SQL Cepat) KeyValueStore atau @capgo/capacitor-data-storage-sqliteBanyak nilai atau nilai besar, cache, draft, dengan kemampuan enkripsi opsional.
  • Penyimpanan Nilai Kunci@capgo/capacitor-native-biometric setDataPenyimpanan nilai SQLite (SQL Cepat)

Referensi Plugin: Penyimpanan nilai SQLite (SQL Cepat), Penyimpanan Data SQLitedan plugin biometrik native halaman.

Update terus untuk Capacitor aplikasi

Ketika bug layer web masih aktif, kirimkan perbaikan melalui Capgo daripada menunggu hari-hari untuk persetujuan toko aplikasi. Pengguna mendapatkan update di latar belakang sementara perubahan native tetap dalam jalur review normal.

Terbaru dari Blog kami

Capgo memberikan Anda wawasan terbaik yang Anda butuhkan untuk membuat aplikasi mobile profesional sebenarnya.