Skip to main content

Custom Storage

By default, Android SDK uses an internal SharedPreferences-based storage implementation.

If your app requires encrypted storage, DataStore, or another persistence layer, pass a custom DetourStorage via DetourConfig.storage.

Storage interface

interface DetourStorage {
suspend fun getItem(key: String): String?
suspend fun setItem(key: String, value: String)
suspend fun removeItem(key: String) { }
}

What SDK persists

SDK stores internal keys for:

  • first-launch detection (Detour_firstEntranceFlag)
  • analytics device identifier (Detour_deviceId)

Custom storage should preserve values across app restarts to keep deferred-flow and analytics behavior consistent.

Example: EncryptedSharedPreferences

import android.content.Context
import androidx.security.crypto.EncryptedSharedPreferences
import androidx.security.crypto.MasterKey
import com.swmansion.detour.storage.DetourStorage
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext

class EncryptedStorageProvider(context: Context) : DetourStorage {
private val masterKey = MasterKey.Builder(context)
.setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
.build()

private val prefs = EncryptedSharedPreferences.create(
context,
"DetourSecureStorage",
masterKey,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)

override suspend fun getItem(key: String): String? = withContext(Dispatchers.IO) {
prefs.getString(key, null)
}

override suspend fun setItem(key: String, value: String) = withContext(Dispatchers.IO) {
prefs.edit().putString(key, value).apply()
}
}
val config = DetourConfig(
apiKey = BuildConfig.DETOUR_API_KEY,
appId = BuildConfig.DETOUR_APP_ID,
storage = EncryptedStorageProvider(this)
)