Flutter Multi-Platform Development
Flutter Hive Local Data Storage



Introduction
Step 1: Add Dependencies
Open your pubspec.yaml
file and add the following dependencies:
dependencies:
hive: ^2.2.3
dev_dependencies:
hive_generator: ^2.0.0
build_runner: ^2.3.3
Run:
flutter pub get
Step 2: Initialize Hive
Import Hive and a path provider for directory management. Initialize Hive in your main.dart
file:
import 'package:flutter/material.dart';
import 'package:hive/hive.dart';
import 'package:path_provider/path_provider.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
final directory = await getApplicationDocumentsDirectory();
Hive.init(directory.path); // Initialize Hive
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(home: HomePage());
}
}
Step 3: Open a Hive Box
A Hive "box" is like a small database. Open a box to store data:
final box = await Hive.openBox('myBox');
Step 4: Add, Get, and Delete Data
Hive stores data as key-value pairs. Here's how to perform basic operations:
Add Data
await box.put('username', 'JohnDoe'); // Save "JohnDoe" with key "username"
Get Data
String username = box.get('username'); // Retrieve data using the key
print(username); // Output: JohnDoe
Delete Data
await box.delete('username'); // Remove data associated with the key
Step 5: Use Hive in a Flutter App
Example of using Hive in a simple counter app:
import 'package:flutter/material.dart';
import 'package:hive/hive.dart';
import 'package:path_provider/path_provider.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
final directory = await getApplicationDocumentsDirectory();
Hive.init(directory.path);
await Hive.openBox('counterBox'); // Open box before using it
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(home: CounterPage());
}
}
class CounterPage extends StatelessWidget {
final box = Hive.box('counterBox'); // Access the box
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Hive Counter')),
body: Center(
child: ValueListenableBuilder(
valueListenable: box.listenable(), // React to changes
builder: (context, box, _) {
final counter = box.get('counter', defaultValue: 0);
return Text('Counter: $counter', style: TextStyle(fontSize: 24));
},
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
final currentCounter = box.get('counter', defaultValue: 0);
box.put('counter', currentCounter + 1); // Increment counter
},
child: Icon(Icons.add),
),
);
}
}
Step 6: Close the Box
Always close Hive when the app is terminated:
@override
void dispose() {
Hive.close();
super.dispose();
}
Custom Models in Hive
Step 1: Create a Custom Model
Define a Dart class to represent your data. For example, a User
model:
class User {
final String name;
final int age;
User({required this.name, required this.age});
}
Step 2: Annotate the Model
Hive uses code generation to create adapters. To enable this, annotate your model with @HiveType
and its fields with @HiveField
.
import 'package:hive/hive.dart';
part 'user.g.dart'; // Required for code generation
@HiveType(typeId: 0) // Unique ID for this model
class User {
@HiveField(0) // Field index, must be unique within the class
final String name;
@HiveField(1)
final int age;
User({required this.name, required this.age});
}
Step 3: Generate the Adapter
Run the following command to generate the adapter:
flutter pub run build_runner build
This creates a user.g.dart
file with a UserAdapter
class.
Step 4: Register the Adapter
Register the adapter with Hive before using it:
import 'package:flutter/material.dart';
import 'package:hive/hive.dart';
import 'package:path_provider/path_provider.dart';
import 'user.dart'; // Import the model
import 'user.g.dart'; // Import the generated adapter
void main() async {
WidgetsFlutterBinding.ensureInitialized();
final directory = await getApplicationDocumentsDirectory();
Hive.init(directory.path);
Hive.registerAdapter(UserAdapter()); // Register the adapter
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(home: HomePage());
}
}
Step 5: Use the Model in Hive
Save a Custom Object
final box = await Hive.openBox('userBox');
final user = User(name: 'John Doe', age: 25);
await box.put('user1', user); // Save the user object
Retrieve a Custom Object
final user = box.get('user1') as User;
print('Name: ${user.name}, Age: ${user.age}');
Delete a Custom Object
await box.delete('user1');
Understanding the Adapter
The adapter handles:
- Serialization: Converts the object into a format Hive can store.
- Deserialization: Converts the stored data back into an object.
Example of an auto-generated adapter (user.g.dart
):
class UserAdapter extends TypeAdapter<User> {
@override
final int typeId = 0;
@override
User read(BinaryReader reader) {
final name = reader.readString();
final age = reader.readInt();
return User(name: name, age: age);
}
@override
void write(BinaryWriter writer, User obj) {
writer.writeString(obj.name);
writer.writeInt(obj.age);
}
}
Benefits of Using Custom Models and Adapters
- Organized Code: Models make it easier to work with structured data.
- Performance: Hive uses binary storage, making it fast.
- Flexibility: You can easily update your models and manage complex data relationships.
Encryption in Hive
Step 1: Generate an Encryption Key
You need a 256-bit encryption key. You can generate it programmatically using the crypto
package.
import 'dart:convert';
import 'dart:math';
import 'package:crypto/crypto.dart';
Uint8List generateEncryptionKey() {
final key = sha256.convert(utf8.encode('your-secret-key')).bytes;
return Uint8List.fromList(key);
}
final encryptionKey = generateEncryptionKey(); // Use this key for encryption
Alternatively, you can use Random.secure()
for a random key:
import 'dart:math';
import 'dart:typed_data';
Uint8List generateEncryptionKey() {
return Uint8List.fromList(List.generate(32, (_) => Random.secure().nextInt(256)));
}
Step 2: Open an Encrypted Box
When opening a box, pass the encryption key to Hive’s HiveAesCipher
.
import 'package:hive/hive.dart';
import 'dart:typed_data';
void main() async {
final encryptionKey = generateEncryptionKey();
// Initialize Hive
final directory = await getApplicationDocumentsDirectory();
Hive.init(directory.path);
// Open an encrypted box
var box = await Hive.openBox(
'secureBox',
encryptionCipher: HiveAesCipher(encryptionKey),
);
// Save and retrieve data
await box.put('key', 'secureData');
print(box.get('key')); // Outputs: secureData
}
Step 3: Save the Encryption Key Securely
Since the encryption key is essential for decrypting the data, never hardcode it in your app. Instead, store it securely:
- Use Secure Storage (e.g.,
flutter_secure_storage
) to store the key. - Retrieve the key at runtime when needed.
Example:
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
final secureStorage = FlutterSecureStorage();
Future<void> storeEncryptionKey(Uint8List key) async {
await secureStorage.write(key: 'hiveKey', value: base64UrlEncode(key));
}
Future<Uint8List> getEncryptionKey() async {
final key = await secureStorage.read(key: 'hiveKey');
return base64Url.decode(key!);
}
Advantages of Hive Encryption
- AES-256 Security: Industry-standard encryption.
- Easy Implementation: Built into Hive's API.
- Full-Box Encryption: Encrypts all data in a box.
Important Notes
- If you lose the encryption key, the data in the box cannot be recovered.
- For sensitive apps, always store the encryption key in a secure location.
- Use encrypted boxes only when necessary since encryption may slightly impact performance.