Edit module build.gradle
dependencies {
implementation("androidx.security:security-crypto:1.1.0-alpha04")
}
Edit AppSingleton.kt
import android.content.Contextimport android.content.SharedPreferencesimport androidx.security.crypto.EncryptedSharedPreferencesimport androidx.security.crypto.MasterKeyclass AppSingleton { companion object { private var secureSharedPreferences: SharedPreferences? = null fun getSecurePreferences(context: Context): SharedPreferences { return secureSharedPreferences ?: let { val masterKey: MasterKey = MasterKey.Builder(context) .setKeyScheme(MasterKey.KeyScheme.AES256_GCM) .build() secureSharedPreferences = EncryptedSharedPreferences.create( context, "secureSharedPrefs", masterKey, EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV, EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM ) secureSharedPreferences!! } } }}
Remove secureSharedPrefs
from backup rules.
Edit AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.luasoftware.sampleApp">
<application
android:name=".sampleApp"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
>
</application>
</manifest>
NOTE: If allowBackup=false
, setup for dataExtractionRules
and fullBackupContent
is not required.
Edit @xml/backup_rules
<?xml version="1.0" encoding="utf-8"?><!--
Sample backup rules file; uncomment and customize as necessary.
See https://developer.android.com/guide/topics/data/autobackup
for details.
Note: This file is ignored for devices older that API 31
See https://developer.android.com/about/versions/12/backup-restore
-->
<full-backup-content>
<!--
<include domain="sharedpref" path="."/>
<exclude domain="sharedpref" path="device.xml"/>
-->
<exclude domain="sharedpref" path="secureSharedPrefs"/>
</full-backup-content>
Edit @xml/data_extraction_rules
<?xml version="1.0" encoding="utf-8"?><!--
Sample data extraction rules file; uncomment and customize as necessary.
See https://developer.android.com/about/versions/12/backup-restore#xml-changes
for details.
-->
<data-extraction-rules>
<cloud-backup>
<!-- TODO: Use <include> and <exclude> to control what is backed up.
<include .../>
<exclude .../>
-->
<exclude domain="sharedpref" path="secureSharedPrefs"/>
</cloud-backup>
<!--
<device-transfer>
<include .../>
<exclude .../>
</device-transfer>
-->
</data-extraction-rules>
ViewModel
class HomeViewModel() : ViewModel() { private const val PREFERENCES_PASSCODE = "passcode" fun isPasscodeAvailable(context: Context): Boolean { val sharedPreferences = AppSingleton.getSecurePreferences(context) return sharedPreferences.getString(PREFERENCES_PASSCODE, null) != null } fun setPasscode(context: Context, passcode: String?) { val sharedPreferences = AppSingleton.getSecurePreferences(context) with (sharedPreferences.edit()) { if (passcode == null) remove(PREFERENCES_PASSCODE) else putString(PREFERENCES_PASSCODE, passcode) apply() } }}
Usage in compose
@Composablefun HomeScreen( viewModel: HomeViewModel = viewModel()) { val context = LocalContext.current var isPasscodeAvailable by remember { mutableStateOf(viewModel.isPasscodeAvailable(context)) } fun submit(passcode: String) { viewModel.setPasscode(context, "1234") } Button(onClick = { submit("1234") }) { Text("Set Passcode") } if (isPasscodeAvailable) { Button(onClick = { submit(null) }) { Text("Remove Passcode") } }}
References: