fr_storage
Encrypted string key-value storage for native Flutter applications. fr_storage
uses named boxes, ObjectBox persistence, AES-256-GCM authenticated encryption,
keyed HMAC-SHA256 indexes, and flutter_secure_storage for encryption keys.
Platform support
This package targets Flutter platforms supported by ObjectBox and
flutter_secure_storage. Web is not supported.
Default storage
Initialize Flutter bindings and the default storage before requesting a box:
import 'package:flutter/widgets.dart';
import 'package:fr_storage/fr_storage.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await FrStorage.init();
final session = FrStorage.box('session');
await session.put('token', 'secret');
final token = session.get('token');
runApp(MyApp(token: token));
}
get and containsKey are synchronous. put, delete, clear, and owner
close operations return Future<void> and should be awaited. Requesting a
box before initialization, or using an old box after its owner closes, throws
StateError.
Dependency injection and multiple instances
Application repositories should normally depend on the box they own:
final class SessionRepository {
SessionRepository(this._box);
final FrBox _box;
String? get token => _box.get('token');
Future<void> saveToken(String token) => _box.put('token', token);
}
Create an independent, already initialized owner with a distinct ObjectBox directory and secure-storage key:
final accountStorage = await FrStorage.newInstance(
directory: accountDirectory,
secureStorageKey: 'account_42_storage_key_v1',
);
final session = accountStorage.box('session');
await session.put('token', token);
await accountStorage.close();
The default owner and independent owners have separate box caches and lifecycles. Two live owners cannot open the same directory.
Key and recovery behavior
The platform key and ObjectBox files form one inseparable data set. Losing or
replacing the key makes existing values unrecoverable. An invalid stored key,
wrong injected key, unknown payload version, authentication failure, or damaged
payload throws StateError; the package never silently clears corrupted data.
Tests may bypass platform secure storage with exactly 32 bytes:
final storage = await FrStorage.newInstance(
directory: tempPath,
secureStorageKey: 'unused_in_test',
encryptionKey: Uint8List(32),
);
This package intentionally does not read or migrate databases created by the
template application's AppStorage implementation.