Flutter Hive

20. September 2024

Hive ist eine schnelle und einfache Möglichkeit, um Key-Value Paare lokal zu speichern. Hive ist effizienter als die übliche Methode shared_preferences und bietet mehr Features, wie zum Beispiel die Speicherung eigener Datentypen oder die Verschlüsselung von Daten.

In Hive werden die Daten in sogenannten Boxen gespeichert. Eine Box kann viele verschiedene Datentypen speichern.

Hive einrichten

Um Hive zu nutzen, musst du folgende Pakete zur pubspex.yaml Datei hinzufügen:

dependencies:
  hive: ^2.2.3
  hive_flutter: ^1.1.0

dev_dependencies:
  hive_generator: ^2.0.1
  build_runner: ^2.4.6

Die neusten Versionen kannst du hier finden:

Zuerst muss Hive initialisiert werden. Dafür die main Funktion wie folgt verändern:

import 'package:hive/hive.dart';

void main() async {
  await Hive.initFlutter();

  runApp(myApp());
}

Um nun Daten zu speichern und auszulesen, muss man eine Box öffnen.

var box = await Hive.openBox();

Beim Öffnen einer Box, kann der Name der Box spezifiziert werden. Für jeden Namen wird einen andere Box geöffnet, wird kein Name angegeben, eine bestimmte Standardbox.

var box = await Hive.openBox('name');

Nachdem eine Box geöffnet wurde, kann diese einfach mit Hive.box('name') wird genutzt werden. Dabei muss hier nicht await genutzt werden, da dieser Befehl synchron ausgeführt wird. Beispielsweise kann man direkt man der Initialisierung von Hive in der main Funktion eine Box öffnen und sie dann später einfach nutzen ohne asynchronen Code schreiben zu müssen.

Sobald man die Box nicht mehr öffnen muss, kann diese mit box.close(); geschlossen werden. Dies muss allerdings nicht gemacht werden, da sich die Box allein schließt, wenn sie nicht mehr gebraucht wird.

Normalerweise können in einer Box viele verschiedene Daten mit unterschiedlichen Datentypen gespeichert werden. Um in einer Box nur einen Datentypen z.B. Strings speichern zu können, benutzt man folgenden Befehl:

var box = await Hive.openBox('myBox');

Wenn die gleiche Box nun erneut geöffnet wird, muss darauf geachtet werden, dass nur dieser Datentyp gespeichert wird und wieder die gleiche Notation beim Öffnen verwendet wird.

Daten speichern, auslesen und löschen

Um Daten in einer Box zu speichern, weißt man einem Textschlüssel ein Objekt zu. Es können primitive Darttypen, Listen und Directories gespeichert werden. Außerdem kann man mit einem TypeAdapter eigene Datentypen speichern.

Dies sieht beispielsweise so aus:

box.put("key", 0);
box.putAll({"k1": "val", "k2": 2});

var val = box.get("key");
var values = box.values;

box.delete("key");
box.clear();

Um einen Eintrag hinzuzufügen, wird put benutzt, für mehrere Einträge nutzt man putAll.

Mit get wird der Wert zurückgegeben, der dem Schlüssel zugeordnet ist. Wenn dem Schlüssel kein Wert zugeordnet ist, wird null zurückgegeben. Mit box.values erhält man alle Werte in der Box.

Mit del wird ein Eintrag gelöscht. Mit clear werden alle Einträge gelöscht und.

Eigene Datentypen: TypeAdapter

Um eigene Datentypen in einer Box zu speichern, muss zuerst die entsprechende Klasse erstellt werden.

import 'package:hive/hive.dart';

part ‘person.g.dart’;

@HiveType(typeId: 0)
class Person {
  Person({required this.name, required this.age});

  @HiveField(0)
  String name;

  @HiveField(1)
  int age;
}

Jedem Attribut der Klasse wird ein HiveField zugewiesen und der Klasse ein HiveType. Hier ist der Code beinhaltet in der Datei person.dart. Je nachdem wie die Datei heißt, sollte man die Zeile mit part ‘person.g.dart’; anpassen. Die Datei person.g.dart wird automatisch generiert, sobald man im Terminal flutter packages pub run build_runner build ausführt. Diese Datei beinhaltet einen TypeAdapter, den man zuerst in Hive registrieren muss, bevor die Daten der eigene Klasse gespeichert werden können.

Hive.registerAdapter(PersonAdapter());

Dies sollte man direkt nach der Initialisierung von Hive machen. Also:

import 'package:hive_flutter/hive_flutter.dart';

void main() async {
  await Hive.initFlutter();
  Hive.registerAdapter(PersonAdapter());

  runApp(myApp());
}

Große Datenmengen: Lazy box

Bei Benutzung der üblichen Box von Hive wird der gesamte Inhalt der Box im Arbeitsspeicher gespeichert, sobald die Box geöffnet wird. Für kleinere Datenmengen ist dies unproblematisch und praktisch, da so die Daten später synchron aufgerufen werden können.

Für größere Datenmengen belastet dies allerdings zunehmend den Arbeitsspeicher. Deswegen sollte man in diesen Fälle die lazy box benutzen. Diese lädt beim Öffnen alle Schlüssel und die Orte der Werte. Bei Bedarf werden die Werte dann aufgerufen.

var lazyBox = await Hive.openLazyBox('myLazyBox'); 

var value = await lazyBox.get('lazyVal');

Hier müssen Datenaufrufe mit await gekennzeichnet werden. Ist eine lazy box bereits geöffnet, kann diese synchron mit Hive.lazyBox('myLazyBox') zurückgegeben werden.

Vertrauliche Daten: Verschlüsselte box

Möchte man vertrauliche Daten in einer Box speichern, sollte eine verschlüsselte Box verwenden. Diese Box verschlüsselt alle Werte, die einem Schlüssel zugewiesen wurden mit der AES-256 Verschlüsselung. Die Schlüssel werden nicht verschlüsselt. Der Verschlüsselungsschlüssel muss auch sicher gespeichert werden, wie zum Beispiel mit dem Paket flutter_secure_storage.

import 'dart:convert';
import 'package:hive/hive.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';

const secureStorage = FlutterSecureStorage();
final encryptionKeyString = await secureStorage.read(key: 'key');
if (encryptionKeyString == null) {
  final key = Hive.generateSecureKey();
  await secureStorage.write(
    key: 'key',
    value: base64UrlEncode(key),
  );
}
final key = await secureStorage.read(key: 'key');
final encryptionKey = base64Url.decode(key!);

final encryptedBox = await Hive.openBox('vaultBox', encryptionCipher: HiveAesCipher(encryptionKey));
var value = encryptedBox.put('secret');

Hier wird mit flutter_secure_storage ein Schlüssel gespeichert. Wenn es noch keinen gibt, wird automatisch ein sicherer Schlüssel von Hive erzeugt und dieser wird mit flutter_secure_storage in der Base64 Kodierung gespeichert. Dann wird der Schlüssel ausgelesen, der nun auf jeden Fall existiert, von Base64 dekodiert und aus Entschlüsselungsschlüssel der Box angegeben.

Fazit

Wie man sieht, bietet Hive eine einfache und effiziente Möglichkeit Daten zu speichern. Hive hat viele wichtige Features wie synchrone, asynchrone Boxen und verschlüsselte Boxen. Hive eignet sich sowohl für kleine Datenmengen als auch für größere Datenmengen. Mehr Informationen kannst du in der Hive Dokumentation finden.