Last active
April 19, 2024 04:50
-
-
Save arafaysaleem/afd3a33ff912d2f0e19379b762b0e0a7 to your computer and use it in GitHub Desktop.
Key Value Storage Service
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'dart:async'; | |
import 'package:flutter/cupertino.dart'; | |
import 'package:flutter/services.dart'; | |
import 'package:flutter_secure_storage/flutter_secure_storage.dart'; | |
import 'package:shared_preferences/shared_preferences.dart'; | |
/// Base class containing a unified API for key-value pairs' storage. | |
/// This class provides low level methods for storing: | |
/// - Sensitive keys using [FlutterSecureStorage] | |
/// - Insensitive keys using [SharedPreferences] | |
class KeyValueStorageBase { | |
/// Instance of shared preferences | |
static SharedPreferences? _sharedPrefs; | |
/// Instance of flutter secure storage | |
static FlutterSecureStorage? _secureStorage; | |
/// Singleton instance of KeyValueStorage Helper | |
static KeyValueStorageBase? _instance; | |
/// Get instance of this class | |
factory KeyValueStorageBase() => _instance ??= const KeyValueStorageBase._(); | |
/// Private constructor | |
const KeyValueStorageBase._(); | |
/// Initializer for shared prefs and flutter secure storage | |
/// Should be called in main before runApp and | |
/// after WidgetsBinding.FlutterInitialized(), to allow for synchronous tasks | |
/// when possible. | |
static Future<void> init() async { | |
_sharedPrefs ??= await SharedPreferences.getInstance(); | |
_secureStorage ??= const FlutterSecureStorage(); | |
} | |
/// Reads the value for the key from common preferences storage | |
T? getCommon<T>(String key) { | |
try { | |
switch (T) { | |
case String: | |
return _sharedPrefs!.getString(key) as T?; | |
case int: | |
return _sharedPrefs!.getInt(key) as T?; | |
case bool: | |
return _sharedPrefs!.getBool(key) as T?; | |
case double: | |
return _sharedPrefs!.getDouble(key) as T?; | |
default: | |
return _sharedPrefs!.get(key) as T?; | |
} | |
} on Exception catch (ex) { | |
debugPrint('$ex'); | |
return null; | |
} | |
} | |
/// Reads the decrypted value for the key from secure storage | |
Future<String?> getEncrypted(String key) { | |
try { | |
return _secureStorage!.read(key: key); | |
} on PlatformException catch (ex) { | |
debugPrint('$ex'); | |
return Future<String?>.value(); | |
} | |
} | |
/// Sets the value for the key to common preferences storage | |
Future<bool> setCommon<T>(String key, T value) { | |
switch (T) { | |
case String: | |
return _sharedPrefs!.setString(key, value as String); | |
case int: | |
return _sharedPrefs!.setInt(key, value as int); | |
case bool: | |
return _sharedPrefs!.setBool(key, value as bool); | |
case double: | |
return _sharedPrefs!.setDouble(key, value as double); | |
default: | |
return _sharedPrefs!.setString(key, value as String); | |
} | |
} | |
/// Sets the encrypted value for the key to secure storage | |
Future<bool> setEncrypted(String key, String value) { | |
try { | |
_secureStorage!.write(key: key, value: value); | |
return Future.value(true); | |
} on PlatformException catch (ex) { | |
debugPrint('$ex'); | |
return Future.value(false); | |
} | |
} | |
/// Erases common preferences keys | |
Future<bool> clearCommon() => _sharedPrefs!.clear(); | |
/// Erases encrypted keys | |
Future<bool> clearEncrypted() async { | |
try { | |
await _secureStorage!.deleteAll(); | |
return true; | |
} on PlatformException catch (ex) { | |
debugPrint('$ex'); | |
return false; | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'dart:convert'; | |
// Services | |
import 'key_value_storage_base.dart'; | |
// Models | |
import '../../features/profile/models/student_model.codegen.dart'; | |
// Helpers | |
import '../../helpers/typedefs.dart'; | |
/// A service class for providing methods to store and retrieve key-value data | |
/// from common or secure storage. | |
class KeyValueStorageService { | |
/// The name of auth token key | |
static const _authTokenKey = 'authToken'; | |
/// The name of user password key | |
static const _authPasswordKey = 'authPasswordKey'; | |
/// The name of user model key | |
static const _authUserKey = 'authUserKey'; | |
/// Instance of key-value storage base class | |
final _keyValueStorage = KeyValueStorageBase(); | |
/// Returns logged in user password | |
Future<String> getAuthPassword() async { | |
return await _keyValueStorage.getEncrypted(_authPasswordKey) ?? ''; | |
} | |
/// Returns last authenticated user | |
StudentModel? getAuthUser() { | |
final user = _keyValueStorage.getCommon<String>(_authUserKey); | |
if (user == null) return null; | |
return StudentModel.fromJson(jsonDecode(user) as JSON); | |
} | |
/// Returns last authentication token | |
Future<String> getAuthToken() async { | |
return await _keyValueStorage.getEncrypted(_authTokenKey) ?? ''; | |
} | |
/// Sets the authentication password to this value. Even though this method is | |
/// asynchronous, we don't care about it's completion which is why we don't | |
/// use `await` and let it execute in the background. | |
void setAuthPassword(String password) { | |
_keyValueStorage.setEncrypted(_authPasswordKey, password); | |
} | |
/// Sets the authenticated user to this value. Even though this method is | |
/// asynchronous, we don't care about it's completion which is why we don't | |
/// use `await` and let it execute in the background. | |
void setAuthUser(StudentModel user) { | |
_keyValueStorage.setCommon<String>(_authUserKey, jsonEncode(user.toJson())); | |
} | |
/// Sets the authentication token to this value. Even though this method is | |
/// asynchronous, we don't care about it's completion which is why we don't | |
/// use `await` and let it execute in the background. | |
void setAuthToken(String token) { | |
_keyValueStorage.setEncrypted(_authTokenKey, token); | |
} | |
/// Resets the authentication. Even though these methods are asynchronous, we | |
/// don't care about their completion which is why we don't use `await` and | |
/// let them execute in the background. | |
void resetKeys() { | |
_keyValueStorage | |
..clearCommon() | |
..clearEncrypted(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment