flutter_secure_storage_plus 0.1.0 copy "flutter_secure_storage_plus: ^0.1.0" to clipboard
flutter_secure_storage_plus: ^0.1.0 copied to clipboard

Enhanced secure storage with biometric unlock and key rotation.

example/lib/main.dart

import 'package:flutter/material.dart';
import 'dart:async';

import 'package:flutter/services.dart';
import 'package:flutter_secure_storage_plus/flutter_secure_storage_plus.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({super.key});

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  String _platformVersion = 'Unknown';
  String? _storedValue;
  String? _status;
  bool _useBiometrics = false;
  bool _isLoading = false;
  final _storage = FlutterSecureStoragePlus();
  final _keyController = TextEditingController(text: 'token');
  final _valueController = TextEditingController(text: 'abc');

  @override
  void initState() {
    super.initState();
    initPlatformState();
  }

  Future<void> initPlatformState() async {
    String platformVersion;
    try {
      platformVersion =
          await _storage.getPlatformVersion() ?? 'Unknown platform version';
    } on PlatformException {
      platformVersion = 'Failed to get platform version.';
    }
    if (!mounted) return;
    setState(() {
      _platformVersion = platformVersion;
    });
  }

  Future<void> _write({bool requireBiometrics = false}) async {
    setState(() {
      _isLoading = true;
      _status = null;
    });
    try {
      await _storage.write(
        key: _keyController.text,
        value: _valueController.text,
        requireBiometrics: requireBiometrics,
      );
      setState(() {
        _status = requireBiometrics
            ? '✓ Value written with biometric protection!'
            : '✓ Value written!';
      });
    } catch (e) {
      setState(() {
        _status = '✗ Write failed: $e';
      });
    } finally {
      setState(() {
        _isLoading = false;
      });
    }
  }

  Future<void> _read({bool requireBiometrics = false}) async {
    setState(() {
      _isLoading = true;
      _status = null;
    });
    try {
      final value = await _storage.read(
        key: _keyController.text,
        requireBiometrics: requireBiometrics,
      );
      setState(() {
        _storedValue = value;
        if (value != null) {
          _status = requireBiometrics
              ? '✓ Value read with biometric authentication: $value'
              : '✓ Value read: $value';
        } else {
          _status = 'ℹ No value found.';
        }
      });
    } catch (e) {
      setState(() {
        _status = '✗ Read failed: $e';
      });
    } finally {
      setState(() {
        _isLoading = false;
      });
    }
  }

  Future<void> _delete() async {
    setState(() {
      _isLoading = true;
      _status = null;
    });
    try {
      await _storage.delete(key: _keyController.text);
      setState(() {
        _storedValue = null;
        _status = '✓ Value deleted!';
      });
    } catch (e) {
      setState(() {
        _status = '✗ Delete failed: $e';
      });
    } finally {
      setState(() {
        _isLoading = false;
      });
    }
  }

  Future<void> _rotateKeys() async {
    setState(() {
      _isLoading = true;
      _status = null;
    });
    try {
      final rotatedCount = await _storage.rotateKeys();
      setState(() {
        _status = '✓ Keys rotated successfully! ($rotatedCount items)';
      });
    } catch (e) {
      setState(() {
        _status = '✗ Key rotation failed: $e';
      });
    } finally {
      setState(() {
        _isLoading = false;
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Secure Storage Plus'),
          backgroundColor: Colors.blue.shade700,
        ),
        body: SingleChildScrollView(
          padding: const EdgeInsets.all(16.0),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.stretch,
            children: [
              // Platform info
              Card(
                color: Colors.blue.shade50,
                child: Padding(
                  padding: const EdgeInsets.all(16.0),
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      const Text(
                        'Platform Info',
                        style: TextStyle(
                          fontSize: 18,
                          fontWeight: FontWeight.bold,
                        ),
                      ),
                      const SizedBox(height: 8),
                      Text('Running on: $_platformVersion'),
                    ],
                  ),
                ),
              ),
              const SizedBox(height: 16),

              // Input fields
              Card(
                child: Padding(
                  padding: const EdgeInsets.all(16.0),
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      const Text(
                        'Key-Value Storage',
                        style: TextStyle(
                          fontSize: 18,
                          fontWeight: FontWeight.bold,
                        ),
                      ),
                      const SizedBox(height: 16),
                      TextField(
                        controller: _keyController,
                        decoration: const InputDecoration(
                          labelText: 'Key',
                          border: OutlineInputBorder(),
                        ),
                      ),
                      const SizedBox(height: 16),
                      TextField(
                        controller: _valueController,
                        decoration: const InputDecoration(
                          labelText: 'Value',
                          border: OutlineInputBorder(),
                        ),
                      ),
                      const SizedBox(height: 16),
                      CheckboxListTile(
                        title: const Text('Use Biometric Authentication'),
                        subtitle: const Text(
                          'Protect with Face ID/Touch ID/Fingerprint',
                        ),
                        value: _useBiometrics,
                        onChanged: (value) {
                          setState(() {
                            _useBiometrics = value ?? false;
                          });
                        },
                      ),
                    ],
                  ),
                ),
              ),
              const SizedBox(height: 16),

              // Basic operations
              Card(
                child: Padding(
                  padding: const EdgeInsets.all(16.0),
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      const Text(
                        'Basic Operations',
                        style: TextStyle(
                          fontSize: 18,
                          fontWeight: FontWeight.bold,
                        ),
                      ),
                      const SizedBox(height: 16),
                      Wrap(
                        spacing: 8,
                        runSpacing: 8,
                        children: [
                          ElevatedButton.icon(
                            onPressed: _isLoading
                                ? null
                                : () =>
                                      _write(requireBiometrics: _useBiometrics),
                            icon: const Icon(Icons.save),
                            label: const Text('Write'),
                          ),
                          ElevatedButton.icon(
                            onPressed: _isLoading
                                ? null
                                : () =>
                                      _read(requireBiometrics: _useBiometrics),
                            icon: const Icon(Icons.read_more),
                            label: const Text('Read'),
                          ),
                          ElevatedButton.icon(
                            onPressed: _isLoading ? null : _delete,
                            icon: const Icon(Icons.delete),
                            label: const Text('Delete'),
                            style: ElevatedButton.styleFrom(
                              backgroundColor: Colors.red.shade400,
                              foregroundColor: Colors.white,
                            ),
                          ),
                        ],
                      ),
                    ],
                  ),
                ),
              ),
              const SizedBox(height: 16),

              // Biometric-only section
              Card(
                color: Colors.amber.shade50,
                child: Padding(
                  padding: const EdgeInsets.all(16.0),
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      Row(
                        children: [
                          Icon(Icons.fingerprint, color: Colors.amber.shade700),
                          const SizedBox(width: 8),
                          const Text(
                            'Biometric Protected Operations',
                            style: TextStyle(
                              fontSize: 18,
                              fontWeight: FontWeight.bold,
                            ),
                          ),
                        ],
                      ),
                      const SizedBox(height: 8),
                      const Text(
                        'These operations require biometric authentication',
                        style: TextStyle(fontSize: 12, color: Colors.grey),
                      ),
                      const SizedBox(height: 16),
                      Wrap(
                        spacing: 8,
                        runSpacing: 8,
                        children: [
                          ElevatedButton.icon(
                            onPressed: _isLoading
                                ? null
                                : () => _write(requireBiometrics: true),
                            icon: const Icon(Icons.fingerprint),
                            label: const Text('Write (Biometric)'),
                            style: ElevatedButton.styleFrom(
                              backgroundColor: Colors.amber.shade700,
                              foregroundColor: Colors.white,
                            ),
                          ),
                          ElevatedButton.icon(
                            onPressed: _isLoading
                                ? null
                                : () => _read(requireBiometrics: true),
                            icon: const Icon(Icons.fingerprint),
                            label: const Text('Read (Biometric)'),
                            style: ElevatedButton.styleFrom(
                              backgroundColor: Colors.amber.shade700,
                              foregroundColor: Colors.white,
                            ),
                          ),
                        ],
                      ),
                    ],
                  ),
                ),
              ),
              const SizedBox(height: 16),

              // Key rotation section
              Card(
                color: Colors.green.shade50,
                child: Padding(
                  padding: const EdgeInsets.all(16.0),
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      Row(
                        children: [
                          Icon(Icons.vpn_key, color: Colors.green.shade700),
                          const SizedBox(width: 8),
                          const Text(
                            'Key Rotation',
                            style: TextStyle(
                              fontSize: 18,
                              fontWeight: FontWeight.bold,
                            ),
                          ),
                        ],
                      ),
                      const SizedBox(height: 8),
                      const Text(
                        'Re-encrypt all stored values with new encryption keys',
                        style: TextStyle(fontSize: 12, color: Colors.grey),
                      ),
                      const SizedBox(height: 16),
                      ElevatedButton.icon(
                        onPressed: _isLoading ? null : _rotateKeys,
                        icon: const Icon(Icons.refresh),
                        label: const Text('Rotate Keys'),
                        style: ElevatedButton.styleFrom(
                          backgroundColor: Colors.green.shade700,
                          foregroundColor: Colors.white,
                          minimumSize: const Size(double.infinity, 48),
                        ),
                      ),
                    ],
                  ),
                ),
              ),
              const SizedBox(height: 16),

              // Status display
              if (_status != null)
                Card(
                  color: _status!.startsWith('✓')
                      ? Colors.green.shade50
                      : _status!.startsWith('✗')
                      ? Colors.red.shade50
                      : Colors.blue.shade50,
                  child: Padding(
                    padding: const EdgeInsets.all(16.0),
                    child: Row(
                      children: [
                        if (_isLoading)
                          const SizedBox(
                            width: 20,
                            height: 20,
                            child: CircularProgressIndicator(strokeWidth: 2),
                          )
                        else if (_status!.startsWith('✓'))
                          Icon(Icons.check_circle, color: Colors.green.shade700)
                        else if (_status!.startsWith('✗'))
                          Icon(Icons.error, color: Colors.red.shade700)
                        else
                          Icon(Icons.info, color: Colors.blue.shade700),
                        const SizedBox(width: 12),
                        Expanded(
                          child: Text(
                            _status!,
                            style: TextStyle(
                              color: _status!.startsWith('✓')
                                  ? Colors.green.shade900
                                  : _status!.startsWith('✗')
                                  ? Colors.red.shade900
                                  : Colors.blue.shade900,
                              fontWeight: FontWeight.w500,
                            ),
                          ),
                        ),
                      ],
                    ),
                  ),
                ),

              if (_storedValue != null) ...[
                const SizedBox(height: 16),
                Card(
                  child: Padding(
                    padding: const EdgeInsets.all(16.0),
                    child: Column(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: [
                        const Text(
                          'Current Value',
                          style: TextStyle(
                            fontSize: 16,
                            fontWeight: FontWeight.bold,
                          ),
                        ),
                        const SizedBox(height: 8),
                        SelectableText(
                          _storedValue!,
                          style: const TextStyle(fontSize: 16),
                        ),
                      ],
                    ),
                  ),
                ),
              ],
            ],
          ),
        ),
      ),
    );
  }

  @override
  void dispose() {
    _keyController.dispose();
    _valueController.dispose();
    super.dispose();
  }
}