Skip to content

Commit cd85286

Browse files
committed
feat(android): migrate SharedPreferences to DataStore
1 parent 7ff2441 commit cd85286

File tree

2 files changed

+48
-17
lines changed

2 files changed

+48
-17
lines changed

android/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,4 +64,5 @@ dependencies {
6464
implementation "com.squareup.okhttp3:okhttp:4.12.0"
6565
implementation "com.squareup.okhttp3:okhttp-tls:4.12.0"
6666
implementation "com.squareup.okhttp3:okhttp-urlconnection:4.12.0"
67+
implementation "androidx.datastore:datastore-preferences:1.1.1"
6768
}

android/src/main/java/com/mattermost/networkclient/ApiClientModuleImpl.kt

Lines changed: 47 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,20 @@ package com.mattermost.networkclient
22

33
import android.content.Context
44
import android.content.SharedPreferences
5+
import androidx.datastore.core.DataStore
6+
import androidx.datastore.preferences.core.Preferences
7+
import androidx.datastore.preferences.core.stringPreferencesKey
8+
import androidx.datastore.preferences.preferencesDataStore
9+
import androidx.datastore.preferences.core.edit
510
import com.facebook.react.bridge.Promise
611
import com.facebook.react.bridge.ReactApplicationContext
712
import com.facebook.react.bridge.ReadableMap
813
import com.facebook.react.bridge.WritableMap
914
import com.facebook.react.modules.network.ForwardingCookieHandler
1015
import com.facebook.react.modules.network.ReactCookieJarContainer
1116
import com.mattermost.networkclient.helpers.KeyStoreHelper
17+
import kotlinx.coroutines.flow.first
18+
import kotlinx.coroutines.runBlocking
1219
import okhttp3.Call
1320
import okhttp3.HttpUrl
1421
import okhttp3.HttpUrl.Companion.toHttpUrl
@@ -30,9 +37,12 @@ class ApiClientModuleImpl(reactApplicationContext: ReactApplicationContext) {
3037
private val calls = mutableMapOf<String, Call>()
3138
private lateinit var sharedPreferences: SharedPreferences
3239
private const val SHARED_PREFERENCES_NAME = "APIClientPreferences"
40+
private const val DATASTORE_NAME = "APIClientDataStore"
3341
internal val cookieJar = ReactCookieJarContainer()
3442
private val aliasTokenCache = mutableMapOf<String, String?>()
3543

44+
private val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = DATASTORE_NAME)
45+
3646
internal fun getClientForRequest(request: Request): NetworkClient? {
3747
var urlParts = request.url.toString().split("/")
3848
while (urlParts.isNotEmpty()) {
@@ -49,9 +59,11 @@ class ApiClientModuleImpl(reactApplicationContext: ReactApplicationContext) {
4959

5060
internal fun storeValue(value: String, alias: String) {
5161
val encryptedValue = KeyStoreHelper.encryptData(value)
52-
sharedPreferences.edit()
53-
.putString(alias, encryptedValue)
54-
.apply()
62+
runBlocking {
63+
context.dataStore.edit { preferences ->
64+
preferences[stringPreferencesKey(alias)] = encryptedValue
65+
}
66+
}
5567
}
5668

5769
internal fun retrieveValue(alias: String): String? {
@@ -60,21 +72,24 @@ class ApiClientModuleImpl(reactApplicationContext: ReactApplicationContext) {
6072
return cacheData
6173
}
6274

63-
val encryptedData = sharedPreferences.getString(alias, null)
64-
if (encryptedData != null) {
65-
val data = KeyStoreHelper.decryptData(encryptedData)
66-
this.aliasTokenCache[alias] = data
67-
return data
75+
return runBlocking {
76+
val encryptedData = context.dataStore.data.first()[stringPreferencesKey(alias)]
77+
if (encryptedData != null) {
78+
val data = KeyStoreHelper.decryptData(encryptedData)
79+
aliasTokenCache[alias] = data
80+
return@runBlocking data
81+
}
82+
null
6883
}
69-
70-
return null
7184
}
7285

7386
internal fun deleteValue(alias: String) {
74-
sharedPreferences.edit()
75-
.remove(alias)
76-
.apply()
77-
this.aliasTokenCache.remove(alias)
87+
runBlocking {
88+
context.dataStore.edit { preferences ->
89+
preferences.remove(stringPreferencesKey(alias))
90+
}
91+
aliasTokenCache.remove(alias)
92+
}
7893
}
7994

8095
internal fun sendJSEvent(eventName: String, data: WritableMap?) {
@@ -88,8 +103,23 @@ class ApiClientModuleImpl(reactApplicationContext: ReactApplicationContext) {
88103
context = reactContext
89104
}
90105

91-
private fun setSharedPreferences(reactContext: ReactApplicationContext) {
92-
sharedPreferences = reactContext.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE)
106+
private fun migrateSharedPreferences(reactContext: ReactApplicationContext) {
107+
val sharedPreferences = reactContext.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE)
108+
109+
if (sharedPreferences.all.isNotEmpty()) {
110+
runBlocking {
111+
reactContext.dataStore.edit { preferences ->
112+
sharedPreferences.all.forEach { entry ->
113+
val key = stringPreferencesKey(entry.key)
114+
when (val value = entry.value) {
115+
is String -> preferences[key] = value
116+
}
117+
}
118+
}
119+
120+
sharedPreferences.edit().clear().apply()
121+
}
122+
}
93123
}
94124

95125
private fun setCookieJar(reactContext: ReactApplicationContext) {
@@ -100,7 +130,7 @@ class ApiClientModuleImpl(reactApplicationContext: ReactApplicationContext) {
100130

101131
init {
102132
setCtx(reactApplicationContext)
103-
setSharedPreferences(reactApplicationContext)
133+
migrateSharedPreferences(reactApplicationContext)
104134
setCookieJar(reactApplicationContext)
105135
}
106136

0 commit comments

Comments
 (0)