native_secured_storage 1.0.0
native_secured_storage: ^1.0.0 copied to clipboard
A Flutter plugin for securely storing primitive data types using Android Keystore and iOS Keychain.
Native Secured Storage #
native_secured_storage is a Flutter plugin designed for securely storing and retrieving primitive data types (int, double, bool, and String) using Android Keystore and iOS Keychain. This ensures data is encrypted at rest and protected against unauthorized access, even if the device is compromised.
Why Use native_secured_storage? #
Security Features #
-
Android Keystore with EncryptedSharedPreferences:
- Uses AES256 encryption with a unique key stored securely in the Android Keystore.
- Ensures encryption and decryption happen only within the device.
-
iOS Keychain:
- Integrates directly with Apple's Keychain, providing system-level security for sensitive data.
- Protects data using the device’s secure enclave, if available.
-
No Plaintext Storage:
- All data is encrypted before being saved, ensuring that sensitive information is never stored in plaintext.
-
Platform Isolation:
- Separate implementations for Android and iOS ensure data is stored securely in each platform's native environment.
Use Cases #
- Authentication: Securely store tokens, passwords, or sensitive user credentials.
- Preferences: Save encrypted app preferences such as user settings or feature flags.
- Secure Identifiers: Store unique identifiers or keys for app logic.
Features #
- Cross-platform: Supports both Android and iOS.
- Type Support: Securely handles
int,double,bool, andStringtypes. - Easy-to-use API: Simplified Dart API for saving, retrieving, and deleting data.
- Error Handling: Comprehensive error handling to catch issues during encryption or storage operations.
Installation #
Add native_secured_storage to your pubspec.yaml:
dependencies:
native_secured_storage: ^1.0.0
Run the following command to install the package:
flutter pub get
Usage #
Import the Package #
import 'package:native_secured_storage/native_secured_storage.dart';
Save a Value #
await NativeSecuredStorage.save('key_name', 123); // Save an integer
await NativeSecuredStorage.save('key_name', 45.67); // Save a double
await NativeSecuredStorage.save('key_name', true); // Save a boolean
await NativeSecuredStorage.save('key_name', 'Hello World'); // Save a string
Retrieve a Value #
final value = await NativeSecuredStorage.retrieve('key_name');
if (value != null) {
print('Retrieved value: $value');
} else {
print('No value found for the given key.');
}
Delete a Value #
await NativeSecuredStorage.delete('key_name');
print('Value deleted successfully.');
Example #
Below is a complete example using native_secured_storage:
import 'package:flutter/material.dart';
import 'package:native_secured_storage/native_secured_storage.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Native Secured Storage Example',
theme: ThemeData(primarySwatch: Colors.blue),
home: SecureStorageDemo(),
);
}
}
class SecureStorageDemo extends StatefulWidget {
@override
_SecureStorageDemoState createState() => _SecureStorageDemoState();
}
class _SecureStorageDemoState extends State<SecureStorageDemo> {
final TextEditingController _keyController = TextEditingController();
final TextEditingController _valueController = TextEditingController();
String? _retrievedValue;
Future<void> _saveValue() async {
final key = _keyController.text;
final value = _valueController.text;
if (key.isEmpty || value.isEmpty) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Key and value cannot be empty')),
);
return;
}
dynamic parsedValue;
if (value.toLowerCase() == 'true' || value.toLowerCase() == 'false') {
parsedValue = value.toLowerCase() == 'true';
} else if (double.tryParse(value) != null) {
parsedValue = value.contains('.') ? double.parse(value) : int.parse(value);
} else {
parsedValue = value;
}
try {
await NativeSecuredStorage.save(key, parsedValue);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Value saved successfully')),
);
} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Error saving value: $e')),
);
}
}
Future<void> _retrieveValue() async {
final key = _keyController.text;
if (key.isEmpty) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Key cannot be empty')),
);
return;
}
try {
final value = await NativeSecuredStorage.retrieve(key);
setState(() {
_retrievedValue = value?.toString();
});
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Value retrieved successfully')),
);
} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Error retrieving value: $e')),
);
}
}
Future<void> _deleteValue() async {
final key = _keyController.text;
if (key.isEmpty) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Key cannot be empty')),
);
return;
}
try {
await NativeSecuredStorage.delete(key);
setState(() {
_retrievedValue = null;
});
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Value deleted successfully')),
);
} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Error deleting value: $e')),
);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Secure Storage Example'),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TextField(
controller: _keyController,
decoration: InputDecoration(labelText: 'Key'),
),
TextField(
controller: _valueController,
decoration: InputDecoration(labelText: 'Value'),
),
SizedBox(height: 16),
Row(
children: [
ElevatedButton(
onPressed: _saveValue,
child: Text('Save'),
),
SizedBox(width: 8),
ElevatedButton(
onPressed: _retrieveValue,
child: Text('Retrieve'),
),
SizedBox(width: 8),
ElevatedButton(
onPressed: _deleteValue,
child: Text('Delete'),
),
],
),
SizedBox(height: 16),
if (_retrievedValue != null)
Text('Retrieved Value: $_retrievedValue'),
],
),
),
);
}
}
Testing #
Run the example app and perform the following actions:
- Save values of different types (
int,double,bool,String). - Retrieve and verify the values.
- Delete a value and confirm it’s removed.
License #
This plugin is released under the MIT License.