
Encrypted Shared Preferences Manager
Version 2.0
import android.content.Context
import android.content.SharedPreferences
import android.security.keystore.KeyGenParameterSpec
import android.security.keystore.KeyProperties
import androidx.security.crypto.EncryptedSharedPreferences
import androidx.security.crypto.MasterKey
import kotlin.reflect.KProperty
/**
* # Encrypted SharedPreferences Manager
* @author Sergey Kalinovsky
*
* ## Dependency:
*
* androidx.security:security-crypto:VERSION (tested with 1.1.0-alpha02)
*
* ## Initialization:
*
* This manager must be initialized by application context in Application class:
*
* [EncryptedSharedPreferencesManager.init(this)][init]
*
* ## Usage in Kotlin code:
*
* Declare variable by Kotlin delegate.
*
* var str by EncryptedSharedPreferencesManager.prefs.string("SHARED_PREFERENCES_KEY")
*
* after that property can be used as usual variable (str = "some text" or println(str))
*
* ## Usage in Java code:
*
* EncryptedSharedPreferencesManager.setString("SHARED_PREFERENCES_KEY", myText)
*
* or
*
* text = EncryptedSharedPreferencesManager.getString("SHARED_PREFERENCES_KEY", null)
*
* Second parameter (default value) can be skipped
*/
@Suppress("unused")
object EncryptedSharedPreferencesManager {
//region Init
/**
* Shared preferences instance
*/
lateinit var prefs: SharedPreferences
/**
* Initialization method. Must be called in inheritor of [Application][android.app.Application] class
* @param context application context
*/
fun init(context: Context) {
if (::prefs.isInitialized) throw IllegalStateException("EncryptedSharedPreferencesManager already initialized!")
val spec = KeyGenParameterSpec.Builder(
"_androidx_security_master_key_",
KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT
)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.setKeySize(256)
.build()
val masterKey: MasterKey = MasterKey.Builder(context)
.setKeyGenParameterSpec(spec)
.build()
prefs = EncryptedSharedPreferences.create(
context,
"secret_shared_prefs",
masterKey,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)
}
// endregion
// region Java methods
/**
* Getter for Shared Preferences boolean value
* @param name shared preferences key
* @return Shared Preferences value
*/
@JvmStatic fun getBoolean(name: String) = getBoolean(name, false)
/**
* Getter for Shared Preferences boolean value
* @param name shared preferences key
* @param defValue default value
* @return Shared Preferences value
*/
@JvmStatic fun getBoolean(name: String, defValue: Boolean) = prefs.getBoolean(name, defValue)
/**
* Setter for Shared Preferences boolean value
* @param name shared preferences key
* @param value value to store in Shared Preferences
*/
@JvmStatic fun setBoolean(name: String, value: Boolean) = prefs.edit().putBoolean(name, value).apply()
/**
* Getter for Shared Preferences float value
* @param name shared preferences key
* @return Shared Preferences value
*/
@JvmStatic fun getFloat(name: String) = getFloat(name, 0f)
/**
* Getter for Shared Preferences float value
* @param name shared preferences key
* @param defValue default value
* @return Shared Preferences value
*/
@JvmStatic fun getFloat(name: String, defValue: Float) = prefs.getFloat(name, defValue)
/**
* Setter for Shared Preferences float value
* @param name shared preferences key
* @param value value to store in Shared Preferences
*/
@JvmStatic fun setFloat(name: String, value: Float) = prefs.edit().putFloat(name, value).apply()
/**
* Getter for Shared Preferences int value
* @param name shared preferences key
* @return Shared Preferences value
*/
@JvmStatic fun getInt(name: String) = getInt(name, 0)
/**
* Getter for Shared Preferences int value
* @param name shared preferences key
* @param defValue default value
* @return Shared Preferences value
*/
@JvmStatic fun getInt(name: String, defValue: Int) = prefs.getInt(name, defValue)
/**
* Setter for Shared Preferences int value
* @param name shared preferences key
* @param value value to store in Shared Preferences
*/
@JvmStatic fun setInt(name: String, value: Int) = prefs.edit().putInt(name, value).apply()
/**
* Getter for Shared Preferences long value
* @param name shared preferences key
* @return Shared Preferences value
*/
@JvmStatic fun getLong(name: String) = getLong(name, 0L)
/**
* Getter for Shared Preferences long value
* @param name shared preferences key
* @param defValue default value
* @return Shared Preferences value
*/
@JvmStatic fun getLong(name: String, defValue: Long) = prefs.getLong(name, defValue)
/**
* Setter for Shared Preferences long value
* @param name shared preferences key
* @param value value to store in Shared Preferences
*/
@JvmStatic fun setLong(name: String, value: Long) = prefs.edit().putLong(name, value).apply()
/**
* Getter for String Shared Preferences value
* @param name shared preferences key
* @return Shared Preferences value
*/
@JvmStatic fun getString(name: String) = getString(name, null)
/**
* Getter for String Shared Preferences value
* @param name shared preferences key
* @param defValue default value
* @return Shared Preferences value
*/
@JvmStatic fun getString(name: String, defValue: String?) = prefs.getString(name, defValue)
/**
* Setter for String Shared Preferences value
* @param name shared preferences key
* @param value value to store in Shared Preferences
*/
@JvmStatic fun setString(name: String, value: String) = prefs.edit().putString(name, value).apply()
/**
* Getter for Set<String> Shared Preferences value
* @param name shared preferences key
* @return Shared Preferences value
*/
@JvmStatic fun getStringSet(name: String): Set<String>? = getStringSet(name, null)
/**
* Getter for Set<String> Shared Preferences value
* @param name shared preferences key
* @param defValue default value
* @return Shared Preferences value
*/
@JvmStatic fun getStringSet(name: String, defValue: Set<String>?): Set<String>? = prefs.getStringSet(name, defValue)
/**
* Setter for Set<String> Shared Preferences value
* @param name shared preferences key
* @param value value to store in Shared Preferences
*/
@JvmStatic fun setStringSet(name: String, value: Set<String>?) = prefs.edit().putStringSet(name, value).apply()
// endregion
// region Kotlin extensions
/**
* Delegate for accessing to Shared Preferences Boolean value
* @param name shared preferences key
* @param defValue default value. Can be skipped
*/
fun SharedPreferences.boolean(name: String, defValue: Boolean = false) = BooleanPrefs(name, defValue, this)
/**
* Delegate for accessing to Shared Preferences Float value
* @param name shared preferences key
* @param defValue default value. Can be skipped
*/
fun SharedPreferences.float(name: String, defValue: Float = 0f) = FloatPrefs(name, defValue, this)
/**
* Delegate for accessing to Shared Preferences Int value
* @param name shared preferences key
* @param defValue default value. Can be skipped
*/
fun SharedPreferences.int(name: String, defValue: Int = 0) = IntPrefs(name, defValue, this)
/**
* Delegate for accessing to Shared Preferences Long value
* @param name shared preferences key
* @param defValue default value. Can be skipped
*/
fun SharedPreferences.long(name: String, defValue: Long = 0L) = LongPrefs(name, defValue, this)
/**
* Delegate for accessing to Shared Preferences String value
* @param name shared preferences key
* @param defValue default value. Can be skipped
*/
fun SharedPreferences.string(name: String, defValue: String = "") = StringPrefs(name, defValue, this)
/**
* Delegate for accessing to Shared Preferences String? value
* @param name shared preferences key
* @param defValue default value. Can be skipped
*/
fun SharedPreferences.nullableString(name: String, defValue: String? = null) = NullableStringPrefs(name, defValue, this)
/**
* Delegate for accessing to Shared Preferences Set<String>? value
* @param name shared preferences key
* @param defValue default value. Can be skipped
*/
fun SharedPreferences.stringSet(name: String, defValue: Set<String> = setOf()) = StringSetPrefs(name, defValue, this)
// endregion
// region Kotlin delegates
class BooleanPrefs(private val name: String, private val defValue: Boolean, private val prefs: SharedPreferences) {
operator fun getValue(thisRef: Any, property: KProperty<*>) = prefs.getBoolean(name, defValue)
operator fun setValue(thisRef: Any, property: KProperty<*>, b: Boolean) = prefs.edit().putBoolean(name, b).apply()
}
class FloatPrefs(private val name: String, private val defValue: Float, private val prefs: SharedPreferences) {
operator fun getValue(thisRef: Any, property: KProperty<*>) = prefs.getFloat(name, defValue)
operator fun setValue(thisRef: Any, property: KProperty<*>, f: Float) = prefs.edit().putFloat(name, f).apply()
}
class IntPrefs(private val name: String, private val defValue: Int, private val prefs: SharedPreferences) {
operator fun getValue(thisRef: Any, property: KProperty<*>) = prefs.getInt(name, defValue)
operator fun setValue(thisRef: Any, property: KProperty<*>, i: Int) = prefs.edit().putInt(name, i).apply()
}
class LongPrefs(private val name: String, private val defValue: Long, private val prefs: SharedPreferences) {
operator fun getValue(thisRef: Any, property: KProperty<*>) = prefs.getLong(name, defValue)
operator fun setValue(thisRef: Any, property: KProperty<*>, l: Long) = prefs.edit().putLong(name, l).apply()
}
class StringPrefs(private val name: String, private val defValue: String, private val prefs: SharedPreferences) {
operator fun getValue(thisRef: Any, property: KProperty<*>): String = prefs.getString(name, defValue) ?: defValue
operator fun setValue(thisRef: Any, property: KProperty<*>, s: String) = prefs.edit().putString(name, s).apply()
}
class NullableStringPrefs(private val name: String, private val defValue: String?, private val prefs: SharedPreferences) {
operator fun getValue(thisRef: Any, property: KProperty<*>): String? = prefs.getString(name, defValue)
operator fun setValue(thisRef: Any, property: KProperty<*>, s: String?) = prefs.edit().putString(name, s).apply()
}
class StringSetPrefs(private val name: String, private val defValue: Set<String>, private val prefs: SharedPreferences) {
operator fun getValue(thisRef: Any, property: KProperty<*>): Set<String>? = prefs.getStringSet(name, defValue)
operator fun setValue(thisRef: Any, property: KProperty<*>, ss: Set<String>?) = prefs.edit().putStringSet(name, ss).apply()
}
// endregion
}