diff --git a/packages/shared_preferences/shared_preferences_android/CHANGELOG.md b/packages/shared_preferences/shared_preferences_android/CHANGELOG.md index 958932eda0c..e8abda3d262 100644 --- a/packages/shared_preferences/shared_preferences_android/CHANGELOG.md +++ b/packages/shared_preferences/shared_preferences_android/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.4.0 + +* Adds `SharedPreferences` support within `SharedPreferencesAsyncAndroid` API. + ## 2.3.4 * Restrict types when decoding preferences. diff --git a/packages/shared_preferences/shared_preferences_android/README.md b/packages/shared_preferences/shared_preferences_android/README.md index d12b09c068a..8d8a84e9f13 100644 --- a/packages/shared_preferences/shared_preferences_android/README.md +++ b/packages/shared_preferences/shared_preferences_android/README.md @@ -11,5 +11,22 @@ so you do not need to add it to your `pubspec.yaml`. However, if you `import` this package to use any of its APIs directly, you should add it to your `pubspec.yaml` as usual. +## Options + +The [SharedPreferencesAsync] and [SharedPreferencesWithCache] APIs can use [DataStore Preferences](https://developer.android.com/topic/libraries/architecture/datastore) or [Android SharedPreferences](https://developer.android.com/reference/android/content/SharedPreferences) to store data. + +To use the `Android SharedPreferences` backend, use the `SharedPreferencesAsyncAndroidOptions` when using [SharedPreferencesAsync]. + + +```dart +const SharedPreferencesAsyncAndroidOptions options = + SharedPreferencesAsyncAndroidOptions( + backend: SharedPreferencesAndroidBackendLibrary.SharedPreferences, + originalSharedPreferencesOptions: AndroidSharedPreferencesStoreOptions( + fileName: 'the_name_of_a_file')); +``` + +The [SharedPreferences] API uses the native [Android SharedPreferences](https://developer.android.com/reference/android/content/SharedPreferences) tool to store data. + [1]: https://pub.dev/packages/shared_preferences [2]: https://flutter.dev/to/endorsed-federated-plugin diff --git a/packages/shared_preferences/shared_preferences_android/android/build.gradle b/packages/shared_preferences/shared_preferences_android/android/build.gradle index 28dc9ef31db..9d165eaf3e4 100644 --- a/packages/shared_preferences/shared_preferences_android/android/build.gradle +++ b/packages/shared_preferences/shared_preferences_android/android/build.gradle @@ -60,7 +60,8 @@ android { } dependencies { implementation 'androidx.datastore:datastore:1.0.0' - implementation 'androidx.datastore:datastore-preferences:1.0.0' + implementation 'androidx.datastore:datastore-preferences:1.0.0' + implementation 'androidx.preference:preference:1.2.1' testImplementation 'junit:junit:4.13.2' testImplementation 'androidx.test:core-ktx:1.5.0' testImplementation 'androidx.test.ext:junit-ktx:1.2.1' diff --git a/packages/shared_preferences/shared_preferences_android/android/gradle.properties b/packages/shared_preferences/shared_preferences_android/android/gradle.properties new file mode 100644 index 00000000000..598d13fee44 --- /dev/null +++ b/packages/shared_preferences/shared_preferences_android/android/gradle.properties @@ -0,0 +1,3 @@ +org.gradle.jvmargs=-Xmx4G +android.useAndroidX=true +android.enableJetifier=true diff --git a/packages/shared_preferences/shared_preferences_android/android/src/main/kotlin/io/flutter/plugins/sharedpreferences/MessagesAsync.g.kt b/packages/shared_preferences/shared_preferences_android/android/src/main/kotlin/io/flutter/plugins/sharedpreferences/MessagesAsync.g.kt index 159253f4280..6855bad260b 100644 --- a/packages/shared_preferences/shared_preferences_android/android/src/main/kotlin/io/flutter/plugins/sharedpreferences/MessagesAsync.g.kt +++ b/packages/shared_preferences/shared_preferences_android/android/src/main/kotlin/io/flutter/plugins/sharedpreferences/MessagesAsync.g.kt @@ -1,8 +1,9 @@ // Copyright 2013 The Flutter Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Autogenerated from Pigeon (v16.0.5), do not edit directly. +// Autogenerated from Pigeon (v22.6.1), do not edit directly. // See also: https://pub.dev/packages/pigeon +@file:Suppress("UNCHECKED_CAST", "ArrayInDataClass") package io.flutter.plugins.sharedpreferences @@ -19,10 +20,10 @@ private fun wrapResult(result: Any?): List { } private fun wrapError(exception: Throwable): List { - if (exception is SharedPreferencesError) { - return listOf(exception.code, exception.message, exception.details) + return if (exception is SharedPreferencesError) { + listOf(exception.code, exception.message, exception.details) } else { - return listOf( + listOf( exception.javaClass.simpleName, exception.toString(), "Cause: " + exception.cause + ", Stacktrace: " + Log.getStackTraceString(exception)) @@ -43,28 +44,27 @@ class SharedPreferencesError( ) : Throwable() /** Generated class from Pigeon that represents data sent in messages. */ -data class SharedPreferencesPigeonOptions(val fileKey: String? = null) { - +data class SharedPreferencesPigeonOptions(val fileName: String? = null, val useDataStore: Boolean) { companion object { - @Suppress("UNCHECKED_CAST") - fun fromList(list: List): SharedPreferencesPigeonOptions { - val fileKey = list[0] as String? - return SharedPreferencesPigeonOptions(fileKey) + fun fromList(pigeonVar_list: List): SharedPreferencesPigeonOptions { + val fileName = pigeonVar_list[0] as String? + val useDataStore = pigeonVar_list[1] as Boolean + return SharedPreferencesPigeonOptions(fileName, useDataStore) } } fun toList(): List { - return listOf( - fileKey, + return listOf( + fileName, + useDataStore, ) } } -@Suppress("UNCHECKED_CAST") -private object SharedPreferencesAsyncApiCodec : StandardMessageCodec() { +private open class MessagesAsyncPigeonCodec : StandardMessageCodec() { override fun readValueOfType(type: Byte, buffer: ByteBuffer): Any? { return when (type) { - 128.toByte() -> { + 129.toByte() -> { return (readValue(buffer) as? List)?.let { SharedPreferencesPigeonOptions.fromList(it) } @@ -76,7 +76,7 @@ private object SharedPreferencesAsyncApiCodec : StandardMessageCodec() { override fun writeValue(stream: ByteArrayOutputStream, value: Any?) { when (value) { is SharedPreferencesPigeonOptions -> { - stream.write(128) + stream.write(129) writeValue(stream, value.toList()) } else -> super.writeValue(stream, value) @@ -115,19 +115,25 @@ interface SharedPreferencesAsyncApi { companion object { /** The codec used by SharedPreferencesAsyncApi. */ - val codec: MessageCodec by lazy { SharedPreferencesAsyncApiCodec } + val codec: MessageCodec by lazy { MessagesAsyncPigeonCodec() } /** * Sets up an instance of `SharedPreferencesAsyncApi` to handle messages through the * `binaryMessenger`. */ - @Suppress("UNCHECKED_CAST") - fun setUp(binaryMessenger: BinaryMessenger, api: SharedPreferencesAsyncApi?) { + @JvmOverloads + fun setUp( + binaryMessenger: BinaryMessenger, + api: SharedPreferencesAsyncApi?, + messageChannelSuffix: String = "" + ) { + val separatedMessageChannelSuffix = + if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" run { val taskQueue = binaryMessenger.makeBackgroundTaskQueue() val channel = BasicMessageChannel( binaryMessenger, - "dev.flutter.pigeon.shared_preferences_android.SharedPreferencesAsyncApi.setBool", + "dev.flutter.pigeon.shared_preferences_android.SharedPreferencesAsyncApi.setBool$separatedMessageChannelSuffix", codec, taskQueue) if (api != null) { @@ -136,13 +142,13 @@ interface SharedPreferencesAsyncApi { val keyArg = args[0] as String val valueArg = args[1] as Boolean val optionsArg = args[2] as SharedPreferencesPigeonOptions - var wrapped: List - try { - api.setBool(keyArg, valueArg, optionsArg) - wrapped = listOf(null) - } catch (exception: Throwable) { - wrapped = wrapError(exception) - } + val wrapped: List = + try { + api.setBool(keyArg, valueArg, optionsArg) + listOf(null) + } catch (exception: Throwable) { + wrapError(exception) + } reply.reply(wrapped) } } else { @@ -154,7 +160,7 @@ interface SharedPreferencesAsyncApi { val channel = BasicMessageChannel( binaryMessenger, - "dev.flutter.pigeon.shared_preferences_android.SharedPreferencesAsyncApi.setString", + "dev.flutter.pigeon.shared_preferences_android.SharedPreferencesAsyncApi.setString$separatedMessageChannelSuffix", codec, taskQueue) if (api != null) { @@ -163,13 +169,13 @@ interface SharedPreferencesAsyncApi { val keyArg = args[0] as String val valueArg = args[1] as String val optionsArg = args[2] as SharedPreferencesPigeonOptions - var wrapped: List - try { - api.setString(keyArg, valueArg, optionsArg) - wrapped = listOf(null) - } catch (exception: Throwable) { - wrapped = wrapError(exception) - } + val wrapped: List = + try { + api.setString(keyArg, valueArg, optionsArg) + listOf(null) + } catch (exception: Throwable) { + wrapError(exception) + } reply.reply(wrapped) } } else { @@ -181,22 +187,22 @@ interface SharedPreferencesAsyncApi { val channel = BasicMessageChannel( binaryMessenger, - "dev.flutter.pigeon.shared_preferences_android.SharedPreferencesAsyncApi.setInt", + "dev.flutter.pigeon.shared_preferences_android.SharedPreferencesAsyncApi.setInt$separatedMessageChannelSuffix", codec, taskQueue) if (api != null) { channel.setMessageHandler { message, reply -> val args = message as List val keyArg = args[0] as String - val valueArg = args[1].let { if (it is Int) it.toLong() else it as Long } + val valueArg = args[1] as Long val optionsArg = args[2] as SharedPreferencesPigeonOptions - var wrapped: List - try { - api.setInt(keyArg, valueArg, optionsArg) - wrapped = listOf(null) - } catch (exception: Throwable) { - wrapped = wrapError(exception) - } + val wrapped: List = + try { + api.setInt(keyArg, valueArg, optionsArg) + listOf(null) + } catch (exception: Throwable) { + wrapError(exception) + } reply.reply(wrapped) } } else { @@ -208,7 +214,7 @@ interface SharedPreferencesAsyncApi { val channel = BasicMessageChannel( binaryMessenger, - "dev.flutter.pigeon.shared_preferences_android.SharedPreferencesAsyncApi.setDouble", + "dev.flutter.pigeon.shared_preferences_android.SharedPreferencesAsyncApi.setDouble$separatedMessageChannelSuffix", codec, taskQueue) if (api != null) { @@ -217,13 +223,13 @@ interface SharedPreferencesAsyncApi { val keyArg = args[0] as String val valueArg = args[1] as Double val optionsArg = args[2] as SharedPreferencesPigeonOptions - var wrapped: List - try { - api.setDouble(keyArg, valueArg, optionsArg) - wrapped = listOf(null) - } catch (exception: Throwable) { - wrapped = wrapError(exception) - } + val wrapped: List = + try { + api.setDouble(keyArg, valueArg, optionsArg) + listOf(null) + } catch (exception: Throwable) { + wrapError(exception) + } reply.reply(wrapped) } } else { @@ -235,7 +241,7 @@ interface SharedPreferencesAsyncApi { val channel = BasicMessageChannel( binaryMessenger, - "dev.flutter.pigeon.shared_preferences_android.SharedPreferencesAsyncApi.setStringList", + "dev.flutter.pigeon.shared_preferences_android.SharedPreferencesAsyncApi.setStringList$separatedMessageChannelSuffix", codec, taskQueue) if (api != null) { @@ -244,13 +250,13 @@ interface SharedPreferencesAsyncApi { val keyArg = args[0] as String val valueArg = args[1] as List val optionsArg = args[2] as SharedPreferencesPigeonOptions - var wrapped: List - try { - api.setStringList(keyArg, valueArg, optionsArg) - wrapped = listOf(null) - } catch (exception: Throwable) { - wrapped = wrapError(exception) - } + val wrapped: List = + try { + api.setStringList(keyArg, valueArg, optionsArg) + listOf(null) + } catch (exception: Throwable) { + wrapError(exception) + } reply.reply(wrapped) } } else { @@ -258,22 +264,24 @@ interface SharedPreferencesAsyncApi { } } run { + val taskQueue = binaryMessenger.makeBackgroundTaskQueue() val channel = BasicMessageChannel( binaryMessenger, - "dev.flutter.pigeon.shared_preferences_android.SharedPreferencesAsyncApi.getString", - codec) + "dev.flutter.pigeon.shared_preferences_android.SharedPreferencesAsyncApi.getString$separatedMessageChannelSuffix", + codec, + taskQueue) if (api != null) { channel.setMessageHandler { message, reply -> val args = message as List val keyArg = args[0] as String val optionsArg = args[1] as SharedPreferencesPigeonOptions - var wrapped: List - try { - wrapped = listOf(api.getString(keyArg, optionsArg)) - } catch (exception: Throwable) { - wrapped = wrapError(exception) - } + val wrapped: List = + try { + listOf(api.getString(keyArg, optionsArg)) + } catch (exception: Throwable) { + wrapError(exception) + } reply.reply(wrapped) } } else { @@ -281,22 +289,24 @@ interface SharedPreferencesAsyncApi { } } run { + val taskQueue = binaryMessenger.makeBackgroundTaskQueue() val channel = BasicMessageChannel( binaryMessenger, - "dev.flutter.pigeon.shared_preferences_android.SharedPreferencesAsyncApi.getBool", - codec) + "dev.flutter.pigeon.shared_preferences_android.SharedPreferencesAsyncApi.getBool$separatedMessageChannelSuffix", + codec, + taskQueue) if (api != null) { channel.setMessageHandler { message, reply -> val args = message as List val keyArg = args[0] as String val optionsArg = args[1] as SharedPreferencesPigeonOptions - var wrapped: List - try { - wrapped = listOf(api.getBool(keyArg, optionsArg)) - } catch (exception: Throwable) { - wrapped = wrapError(exception) - } + val wrapped: List = + try { + listOf(api.getBool(keyArg, optionsArg)) + } catch (exception: Throwable) { + wrapError(exception) + } reply.reply(wrapped) } } else { @@ -304,22 +314,24 @@ interface SharedPreferencesAsyncApi { } } run { + val taskQueue = binaryMessenger.makeBackgroundTaskQueue() val channel = BasicMessageChannel( binaryMessenger, - "dev.flutter.pigeon.shared_preferences_android.SharedPreferencesAsyncApi.getDouble", - codec) + "dev.flutter.pigeon.shared_preferences_android.SharedPreferencesAsyncApi.getDouble$separatedMessageChannelSuffix", + codec, + taskQueue) if (api != null) { channel.setMessageHandler { message, reply -> val args = message as List val keyArg = args[0] as String val optionsArg = args[1] as SharedPreferencesPigeonOptions - var wrapped: List - try { - wrapped = listOf(api.getDouble(keyArg, optionsArg)) - } catch (exception: Throwable) { - wrapped = wrapError(exception) - } + val wrapped: List = + try { + listOf(api.getDouble(keyArg, optionsArg)) + } catch (exception: Throwable) { + wrapError(exception) + } reply.reply(wrapped) } } else { @@ -327,22 +339,24 @@ interface SharedPreferencesAsyncApi { } } run { + val taskQueue = binaryMessenger.makeBackgroundTaskQueue() val channel = BasicMessageChannel( binaryMessenger, - "dev.flutter.pigeon.shared_preferences_android.SharedPreferencesAsyncApi.getInt", - codec) + "dev.flutter.pigeon.shared_preferences_android.SharedPreferencesAsyncApi.getInt$separatedMessageChannelSuffix", + codec, + taskQueue) if (api != null) { channel.setMessageHandler { message, reply -> val args = message as List val keyArg = args[0] as String val optionsArg = args[1] as SharedPreferencesPigeonOptions - var wrapped: List - try { - wrapped = listOf(api.getInt(keyArg, optionsArg)) - } catch (exception: Throwable) { - wrapped = wrapError(exception) - } + val wrapped: List = + try { + listOf(api.getInt(keyArg, optionsArg)) + } catch (exception: Throwable) { + wrapError(exception) + } reply.reply(wrapped) } } else { @@ -350,22 +364,24 @@ interface SharedPreferencesAsyncApi { } } run { + val taskQueue = binaryMessenger.makeBackgroundTaskQueue() val channel = BasicMessageChannel( binaryMessenger, - "dev.flutter.pigeon.shared_preferences_android.SharedPreferencesAsyncApi.getStringList", - codec) + "dev.flutter.pigeon.shared_preferences_android.SharedPreferencesAsyncApi.getStringList$separatedMessageChannelSuffix", + codec, + taskQueue) if (api != null) { channel.setMessageHandler { message, reply -> val args = message as List val keyArg = args[0] as String val optionsArg = args[1] as SharedPreferencesPigeonOptions - var wrapped: List - try { - wrapped = listOf(api.getStringList(keyArg, optionsArg)) - } catch (exception: Throwable) { - wrapped = wrapError(exception) - } + val wrapped: List = + try { + listOf(api.getStringList(keyArg, optionsArg)) + } catch (exception: Throwable) { + wrapError(exception) + } reply.reply(wrapped) } } else { @@ -377,7 +393,7 @@ interface SharedPreferencesAsyncApi { val channel = BasicMessageChannel( binaryMessenger, - "dev.flutter.pigeon.shared_preferences_android.SharedPreferencesAsyncApi.clear", + "dev.flutter.pigeon.shared_preferences_android.SharedPreferencesAsyncApi.clear$separatedMessageChannelSuffix", codec, taskQueue) if (api != null) { @@ -385,13 +401,13 @@ interface SharedPreferencesAsyncApi { val args = message as List val allowListArg = args[0] as List? val optionsArg = args[1] as SharedPreferencesPigeonOptions - var wrapped: List - try { - api.clear(allowListArg, optionsArg) - wrapped = listOf(null) - } catch (exception: Throwable) { - wrapped = wrapError(exception) - } + val wrapped: List = + try { + api.clear(allowListArg, optionsArg) + listOf(null) + } catch (exception: Throwable) { + wrapError(exception) + } reply.reply(wrapped) } } else { @@ -403,7 +419,7 @@ interface SharedPreferencesAsyncApi { val channel = BasicMessageChannel( binaryMessenger, - "dev.flutter.pigeon.shared_preferences_android.SharedPreferencesAsyncApi.getAll", + "dev.flutter.pigeon.shared_preferences_android.SharedPreferencesAsyncApi.getAll$separatedMessageChannelSuffix", codec, taskQueue) if (api != null) { @@ -411,12 +427,12 @@ interface SharedPreferencesAsyncApi { val args = message as List val allowListArg = args[0] as List? val optionsArg = args[1] as SharedPreferencesPigeonOptions - var wrapped: List - try { - wrapped = listOf(api.getAll(allowListArg, optionsArg)) - } catch (exception: Throwable) { - wrapped = wrapError(exception) - } + val wrapped: List = + try { + listOf(api.getAll(allowListArg, optionsArg)) + } catch (exception: Throwable) { + wrapError(exception) + } reply.reply(wrapped) } } else { @@ -428,7 +444,7 @@ interface SharedPreferencesAsyncApi { val channel = BasicMessageChannel( binaryMessenger, - "dev.flutter.pigeon.shared_preferences_android.SharedPreferencesAsyncApi.getKeys", + "dev.flutter.pigeon.shared_preferences_android.SharedPreferencesAsyncApi.getKeys$separatedMessageChannelSuffix", codec, taskQueue) if (api != null) { @@ -436,12 +452,12 @@ interface SharedPreferencesAsyncApi { val args = message as List val allowListArg = args[0] as List? val optionsArg = args[1] as SharedPreferencesPigeonOptions - var wrapped: List - try { - wrapped = listOf(api.getKeys(allowListArg, optionsArg)) - } catch (exception: Throwable) { - wrapped = wrapError(exception) - } + val wrapped: List = + try { + listOf(api.getKeys(allowListArg, optionsArg)) + } catch (exception: Throwable) { + wrapError(exception) + } reply.reply(wrapped) } } else { diff --git a/packages/shared_preferences/shared_preferences_android/android/src/main/kotlin/io/flutter/plugins/sharedpreferences/SharedPreferencesPlugin.kt b/packages/shared_preferences/shared_preferences_android/android/src/main/kotlin/io/flutter/plugins/sharedpreferences/SharedPreferencesPlugin.kt index 84c38630b89..e0ca35b258c 100644 --- a/packages/shared_preferences/shared_preferences_android/android/src/main/kotlin/io/flutter/plugins/sharedpreferences/SharedPreferencesPlugin.kt +++ b/packages/shared_preferences/shared_preferences_android/android/src/main/kotlin/io/flutter/plugins/sharedpreferences/SharedPreferencesPlugin.kt @@ -5,6 +5,7 @@ package io.flutter.plugins.sharedpreferences import android.content.Context +import android.content.SharedPreferences import android.util.Base64 import android.util.Log import androidx.annotation.VisibleForTesting @@ -16,6 +17,7 @@ import androidx.datastore.preferences.core.edit import androidx.datastore.preferences.core.longPreferencesKey import androidx.datastore.preferences.core.stringPreferencesKey import androidx.datastore.preferences.preferencesDataStore +import androidx.preference.PreferenceManager import io.flutter.embedding.engine.plugins.FlutterPlugin import io.flutter.plugin.common.BinaryMessenger import java.io.ByteArrayInputStream @@ -29,6 +31,7 @@ import kotlinx.coroutines.runBlocking const val TAG = "SharedPreferencesPlugin" const val SHARED_PREFERENCES_NAME = "FlutterSharedPreferences" const val LIST_PREFIX = "VGhpcyBpcyB0aGUgcHJlZml4IGZvciBhIGxpc3Qu" +const val DOUBLE_PREFIX = "VGhpcyBpcyB0aGUgcHJlZml4IGZvciBEb3VibGUu" private val Context.sharedPreferencesDataStore: DataStore by preferencesDataStore(SHARED_PREFERENCES_NAME) @@ -36,6 +39,7 @@ private val Context.sharedPreferencesDataStore: DataStore by /// SharedPreferencesPlugin class SharedPreferencesPlugin() : FlutterPlugin, SharedPreferencesAsyncApi { private lateinit var context: Context + private var backend: SharedPreferencesBackend? = null private var listEncoder = ListEncoder() as SharedPreferencesListEncoder @@ -47,7 +51,8 @@ class SharedPreferencesPlugin() : FlutterPlugin, SharedPreferencesAsyncApi { private fun setUp(messenger: BinaryMessenger, context: Context) { this.context = context try { - SharedPreferencesAsyncApi.setUp(messenger, this) + SharedPreferencesAsyncApi.setUp(messenger, this, "data_store") + backend = SharedPreferencesBackend(messenger, context, listEncoder) } catch (ex: Exception) { Log.e(TAG, "Received exception while setting up SharedPreferencesPlugin", ex) } @@ -59,7 +64,9 @@ class SharedPreferencesPlugin() : FlutterPlugin, SharedPreferencesAsyncApi { } override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) { - SharedPreferencesAsyncApi.setUp(binding.binaryMessenger, null) + SharedPreferencesAsyncApi.setUp(binding.binaryMessenger, null, "data_store") + backend?.tearDown() + backend = null } /** Adds property to data store of type bool. */ @@ -135,7 +142,6 @@ class SharedPreferencesPlugin() : FlutterPlugin, SharedPreferencesAsyncApi { val preferencesKey = longPreferencesKey(key) val preferenceFlow: Flow = context.sharedPreferencesDataStore.data.map { preferences -> preferences[preferencesKey] } - value = preferenceFlow.firstOrNull() } return value @@ -144,6 +150,7 @@ class SharedPreferencesPlugin() : FlutterPlugin, SharedPreferencesAsyncApi { /** Gets bool at [key] from data store. */ override fun getBool(key: String, options: SharedPreferencesPigeonOptions): Boolean? { val value: Boolean? + runBlocking { val preferencesKey = booleanPreferencesKey(key) val preferenceFlow: Flow = @@ -160,7 +167,7 @@ class SharedPreferencesPlugin() : FlutterPlugin, SharedPreferencesAsyncApi { val preferencesKey = stringPreferencesKey(key) val preferenceFlow: Flow = context.sharedPreferencesDataStore.data.map { preferences -> - transformPref(preferences[preferencesKey] as Any?) as Double? + transformPref(preferences[preferencesKey] as Any?, listEncoder) as Double? } value = preferenceFlow.firstOrNull() @@ -183,7 +190,8 @@ class SharedPreferencesPlugin() : FlutterPlugin, SharedPreferencesAsyncApi { /** Gets StringList at [key] from data store. */ override fun getStringList(key: String, options: SharedPreferencesPigeonOptions): List? { - return (transformPref(getString(key, options) as Any?) as List<*>?)?.filterIsInstance() + val value: List<*>? = transformPref(getString(key, options) as Any?, listEncoder) as List<*>? + return value?.filterIsInstance() } /** Gets all properties from data store. */ @@ -200,10 +208,10 @@ class SharedPreferencesPlugin() : FlutterPlugin, SharedPreferencesAsyncApi { val filteredMap = mutableMapOf() val keys = readAllKeys() - keys?.forEach() { key -> + keys?.forEach { key -> val value = getValueByKey(key) if (preferencesFilter(key.toString(), value, allowSet)) { - val transformedValue = transformPref(value) + val transformedValue = transformPref(value, listEncoder) if (transformedValue != null) { filteredMap[key.toString()] = transformedValue } @@ -221,45 +229,199 @@ class SharedPreferencesPlugin() : FlutterPlugin, SharedPreferencesAsyncApi { val value = context.sharedPreferencesDataStore.data.map { it[key] } return value.firstOrNull() } +} + +class SharedPreferencesBackend( + private var messenger: BinaryMessenger, + private var context: Context, + private var listEncoder: SharedPreferencesListEncoder = ListEncoder() +) : SharedPreferencesAsyncApi { + + init { + try { + SharedPreferencesAsyncApi.setUp(messenger, this, "shared_preferences") + } catch (ex: Exception) { + Log.e(TAG, "Received exception while setting up SharedPreferencesBackend", ex) + } + } + + fun tearDown() { + SharedPreferencesAsyncApi.setUp(messenger, null, "shared_preferences") + } - /** - * Returns false for any preferences that are not included in [allowList]. - * - * If no [allowList] is provided, instead returns false for any preferences that are not supported - * by shared_preferences. - */ - private fun preferencesFilter(key: String, value: Any?, allowList: Set?): Boolean { - if (allowList == null) { - return value is Boolean || value is Long || value is String || value is Double + private fun createSharedPreferences(options: SharedPreferencesPigeonOptions): SharedPreferences { + return if (options.fileName == null) { + PreferenceManager.getDefaultSharedPreferences(context) + } else { + context.getSharedPreferences(options.fileName, Context.MODE_PRIVATE) } + } + + /** Adds property to data store of type bool. */ + override fun setBool(key: String, value: Boolean, options: SharedPreferencesPigeonOptions) { + return createSharedPreferences(options).edit().putBoolean(key, value).apply() + } + + /** Adds property to data store of type String. */ + override fun setString(key: String, value: String, options: SharedPreferencesPigeonOptions) { + return createSharedPreferences(options).edit().putString(key, value).apply() + } + + /** Adds property to data store of type int. Converted to Long by pigeon, and saved as such. */ + override fun setInt(key: String, value: Long, options: SharedPreferencesPigeonOptions) { + return createSharedPreferences(options).edit().putLong(key, value).apply() + } + + /** Adds property to data store of type double. */ + override fun setDouble(key: String, value: Double, options: SharedPreferencesPigeonOptions) { + return createSharedPreferences(options).edit().putString(key, DOUBLE_PREFIX + value).apply() + } - return allowList.contains(key) + /** Adds property to data store of type List. */ + override fun setStringList( + key: String, + value: List, + options: SharedPreferencesPigeonOptions + ) { + val valueString = LIST_PREFIX + listEncoder.encode(value) + return createSharedPreferences(options).edit().putString(key, valueString).apply() } - /** Transforms preferences that are stored as Strings back to original type. */ - private fun transformPref(value: Any?): Any? { - if (value is String) { - if (value.startsWith(LIST_PREFIX)) { - return listEncoder.decode(value.substring(LIST_PREFIX.length)) + /** Removes all properties from data store. */ + override fun clear(allowList: List?, options: SharedPreferencesPigeonOptions) { + val preferences = createSharedPreferences(options) + val clearEditor: SharedPreferences.Editor = preferences.edit() + val allPrefs: Map = preferences.all + val filteredPrefs = ArrayList() + for (key in allPrefs.keys) { + if (preferencesFilter(key, allPrefs[key], allowList = allowList?.toSet())) { + filteredPrefs.add(key) } } - return value + for (key in filteredPrefs) { + clearEditor.remove(key) + } + return clearEditor.apply() } - /** Class that provides tools for encoding and decoding List to String and back. */ - class ListEncoder : SharedPreferencesListEncoder { - override fun encode(list: List): String { - val byteStream = ByteArrayOutputStream() - val stream = ObjectOutputStream(byteStream) - stream.writeObject(list) - stream.flush() - return Base64.encodeToString(byteStream.toByteArray(), 0) + /** Gets all properties from data store. */ + override fun getAll( + allowList: List?, + options: SharedPreferencesPigeonOptions + ): Map { + val preferences = createSharedPreferences(options) + val allPrefs: Map = preferences.all + val filteredPrefs = HashMap() + for (entry in allPrefs.entries) { + if (preferencesFilter(entry.key, entry.value, allowList = allowList?.toSet())) { + entry.value?.let { filteredPrefs.put(entry.key, transformPref(it, listEncoder) as Any) } + } + } + return filteredPrefs + } + + /** Gets int (as long) at [key] from data store. */ + override fun getInt(key: String, options: SharedPreferencesPigeonOptions): Long? { + val preferences = createSharedPreferences(options) + return if (preferences.contains(key)) { + preferences.getLong(key, 0) + } else { + null + } + } + + /** Gets bool at [key] from data store. */ + override fun getBool(key: String, options: SharedPreferencesPigeonOptions): Boolean? { + val preferences = createSharedPreferences(options) + return if (preferences.contains(key)) { + preferences.getBoolean(key, true) + } else { + null } + } + /** Gets double at [key] from data store. */ + override fun getDouble(key: String, options: SharedPreferencesPigeonOptions): Double? { + val preferences = createSharedPreferences(options) + return if (preferences.contains(key)) { + transformPref(preferences.getString(key, ""), listEncoder) as Double + } else { + null + } + } - override fun decode(listString: String): List { - val byteArray = Base64.decode(listString, 0) - val stream = StringListObjectInputStream(ByteArrayInputStream(byteArray)) - return (stream.readObject() as List<*>).filterIsInstance() + /** Gets String at [key] from data store. */ + override fun getString(key: String, options: SharedPreferencesPigeonOptions): String? { + val preferences = createSharedPreferences(options) + return if (preferences.contains(key)) { + preferences.getString(key, "") + } else { + null } } + + /** Gets StringList at [key] from data store. */ + override fun getStringList(key: String, options: SharedPreferencesPigeonOptions): List? { + val preferences = createSharedPreferences(options) + return if (preferences.contains(key)) { + (transformPref(preferences.getString(key, ""), listEncoder) as List<*>?)?.filterIsInstance< + String>() + } else { + null + } + } + + /** Gets all properties from data store. */ + override fun getKeys( + allowList: List?, + options: SharedPreferencesPigeonOptions + ): List { + val preferences = createSharedPreferences(options) + return preferences.all + .filter { preferencesFilter(it.key, it.value, allowList?.toSet()) } + .keys + .toList() + } +} + +/** + * Returns false for any preferences that are not included in [allowList]. + * + * If no [allowList] is provided, instead returns false for any preferences that are not supported + * by shared_preferences. + */ +internal fun preferencesFilter(key: String, value: Any?, allowList: Set?): Boolean { + if (allowList == null) { + return value is Boolean || value is Long || value is String || value is Double + } + + return allowList.contains(key) +} + +/** Transforms preferences that are stored as Strings back to original type. */ +internal fun transformPref(value: Any?, listEncoder: SharedPreferencesListEncoder): Any? { + if (value is String) { + if (value.startsWith(LIST_PREFIX)) { + return listEncoder.decode(value.substring(LIST_PREFIX.length)) + } else if (value.startsWith(DOUBLE_PREFIX)) { + return value.substring(DOUBLE_PREFIX.length).toDouble() + } + } + return value +} + +/** Class that provides tools for encoding and decoding List to String and back. */ +class ListEncoder : SharedPreferencesListEncoder { + override fun encode(list: List): String { + val byteStream = ByteArrayOutputStream() + val stream = ObjectOutputStream(byteStream) + stream.writeObject(list) + stream.flush() + return Base64.encodeToString(byteStream.toByteArray(), 0) + } + + override fun decode(listString: String): List { + val byteArray = Base64.decode(listString, 0) + val stream = StringListObjectInputStream(ByteArrayInputStream(byteArray)) + return (stream.readObject() as List<*>).filterIsInstance() + } } diff --git a/packages/shared_preferences/shared_preferences_android/android/src/test/kotlin/io/flutter/plugins/sharedpreferences/SharedPreferencesTest.kt b/packages/shared_preferences/shared_preferences_android/android/src/test/kotlin/io/flutter/plugins/sharedpreferences/SharedPreferencesTest.kt index ad5d6420cce..1803138bc12 100644 --- a/packages/shared_preferences/shared_preferences_android/android/src/test/kotlin/io/flutter/plugins/sharedpreferences/SharedPreferencesTest.kt +++ b/packages/shared_preferences/shared_preferences_android/android/src/test/kotlin/io/flutter/plugins/sharedpreferences/SharedPreferencesTest.kt @@ -5,7 +5,9 @@ package io.flutter.plugins.sharedpreferences import android.content.Context +import android.content.SharedPreferences import android.util.Base64 +import androidx.preference.PreferenceManager import androidx.test.core.app.ApplicationProvider import androidx.test.ext.junit.runners.AndroidJUnit4 import io.flutter.embedding.engine.plugins.FlutterPlugin @@ -41,98 +43,104 @@ internal class SharedPreferencesTest { private val testList = listOf("foo", "bar") - private val emptyOptions = SharedPreferencesPigeonOptions() - - private fun pluginSetup(): SharedPreferencesPlugin { - val testContext: Context = ApplicationProvider.getApplicationContext() + private val dataStoreOptions = SharedPreferencesPigeonOptions(useDataStore = true) + private val sharedPreferencesOptions = SharedPreferencesPigeonOptions(useDataStore = false) + private val testContext: Context = ApplicationProvider.getApplicationContext() + private fun pluginSetup(options: SharedPreferencesPigeonOptions): SharedPreferencesAsyncApi { val plugin = SharedPreferencesPlugin() val binaryMessenger = mockk() val flutterPluginBinding = mockk() every { flutterPluginBinding.binaryMessenger } returns binaryMessenger every { flutterPluginBinding.applicationContext } returns testContext plugin.onAttachedToEngine(flutterPluginBinding) - plugin.clear(null, emptyOptions) - return plugin + val backend = + SharedPreferencesBackend( + flutterPluginBinding.binaryMessenger, flutterPluginBinding.applicationContext) + return if (options.useDataStore) { + plugin + } else { + backend + } } @Test - fun testSetAndGetBool() { - val plugin = pluginSetup() - plugin.setBool(boolKey, testBool, emptyOptions) - Assert.assertEquals(plugin.getBool(boolKey, emptyOptions), testBool) + fun testSetAndGetBoolWithDataStore() { + val plugin = pluginSetup(dataStoreOptions) + plugin.setBool(boolKey, testBool, dataStoreOptions) + Assert.assertEquals(plugin.getBool(boolKey, dataStoreOptions), testBool) } @Test - fun testSetAndGetString() { - val plugin = pluginSetup() - plugin.setString(stringKey, testString, emptyOptions) - Assert.assertEquals(plugin.getString(stringKey, emptyOptions), testString) + fun testSetAndGetStringWithDataStore() { + val plugin = pluginSetup(dataStoreOptions) + plugin.setString(stringKey, testString, dataStoreOptions) + Assert.assertEquals(plugin.getString(stringKey, dataStoreOptions), testString) } @Test - fun testSetAndGetInt() { - val plugin = pluginSetup() - plugin.setInt(intKey, testInt, emptyOptions) - Assert.assertEquals(plugin.getInt(intKey, emptyOptions), testInt) + fun testSetAndGetIntWithDataStore() { + val plugin = pluginSetup(dataStoreOptions) + plugin.setInt(intKey, testInt, dataStoreOptions) + Assert.assertEquals(plugin.getInt(intKey, dataStoreOptions), testInt) } @Test - fun testSetAndGetDouble() { - val plugin = pluginSetup() - plugin.setDouble(doubleKey, testDouble, emptyOptions) - Assert.assertEquals(plugin.getDouble(doubleKey, emptyOptions), testDouble) + fun testSetAndGetDoubleWithDataStore() { + val plugin = pluginSetup(dataStoreOptions) + plugin.setDouble(doubleKey, testDouble, dataStoreOptions) + Assert.assertEquals(plugin.getDouble(doubleKey, dataStoreOptions), testDouble) } @Test - fun testSetAndGetStringList() { - val plugin = pluginSetup() - plugin.setStringList(listKey, testList, emptyOptions) - Assert.assertEquals(plugin.getStringList(listKey, emptyOptions), testList) + fun testSetAndGetStringListWithDataStore() { + val plugin = pluginSetup(dataStoreOptions) + plugin.setStringList(listKey, testList, dataStoreOptions) + Assert.assertEquals(plugin.getStringList(listKey, dataStoreOptions), testList) } @Test - fun testGetKeys() { - val plugin = pluginSetup() - plugin.setBool(boolKey, testBool, emptyOptions) - plugin.setString(stringKey, testString, emptyOptions) - plugin.setInt(intKey, testInt, emptyOptions) - plugin.setDouble(doubleKey, testDouble, emptyOptions) - plugin.setStringList(listKey, testList, emptyOptions) - val keyList = plugin.getKeys(listOf(boolKey, stringKey), emptyOptions) + fun testGetKeysWithDataStore() { + val plugin = pluginSetup(dataStoreOptions) + plugin.setBool(boolKey, testBool, dataStoreOptions) + plugin.setString(stringKey, testString, dataStoreOptions) + plugin.setInt(intKey, testInt, dataStoreOptions) + plugin.setDouble(doubleKey, testDouble, dataStoreOptions) + plugin.setStringList(listKey, testList, dataStoreOptions) + val keyList = plugin.getKeys(listOf(boolKey, stringKey), dataStoreOptions) Assert.assertEquals(keyList.size, 2) Assert.assertTrue(keyList.contains(stringKey)) Assert.assertTrue(keyList.contains(boolKey)) } @Test - fun testClear() { - val plugin = pluginSetup() - plugin.setBool(boolKey, testBool, emptyOptions) - plugin.setString(stringKey, testString, emptyOptions) - plugin.setInt(intKey, testInt, emptyOptions) - plugin.setDouble(doubleKey, testDouble, emptyOptions) - plugin.setStringList(listKey, testList, emptyOptions) - - plugin.clear(null, emptyOptions) - - Assert.assertNull(plugin.getBool(boolKey, emptyOptions)) - Assert.assertNull(plugin.getBool(stringKey, emptyOptions)) - Assert.assertNull(plugin.getBool(intKey, emptyOptions)) - Assert.assertNull(plugin.getBool(doubleKey, emptyOptions)) - Assert.assertNull(plugin.getBool(listKey, emptyOptions)) + fun testClearWithDataStore() { + val plugin = pluginSetup(dataStoreOptions) + plugin.setBool(boolKey, testBool, dataStoreOptions) + plugin.setString(stringKey, testString, dataStoreOptions) + plugin.setInt(intKey, testInt, dataStoreOptions) + plugin.setDouble(doubleKey, testDouble, dataStoreOptions) + plugin.setStringList(listKey, testList, dataStoreOptions) + + plugin.clear(null, dataStoreOptions) + + Assert.assertNull(plugin.getBool(boolKey, dataStoreOptions)) + Assert.assertNull(plugin.getBool(stringKey, dataStoreOptions)) + Assert.assertNull(plugin.getBool(intKey, dataStoreOptions)) + Assert.assertNull(plugin.getBool(doubleKey, dataStoreOptions)) + Assert.assertNull(plugin.getBool(listKey, dataStoreOptions)) } @Test - fun testGetAll() { - val plugin = pluginSetup() - plugin.setBool(boolKey, testBool, emptyOptions) - plugin.setString(stringKey, testString, emptyOptions) - plugin.setInt(intKey, testInt, emptyOptions) - plugin.setDouble(doubleKey, testDouble, emptyOptions) - plugin.setStringList(listKey, testList, emptyOptions) + fun testGetAllWithDataStore() { + val plugin = pluginSetup(dataStoreOptions) + plugin.setBool(boolKey, testBool, dataStoreOptions) + plugin.setString(stringKey, testString, dataStoreOptions) + plugin.setInt(intKey, testInt, dataStoreOptions) + plugin.setDouble(doubleKey, testDouble, dataStoreOptions) + plugin.setStringList(listKey, testList, dataStoreOptions) - val all = plugin.getAll(null, emptyOptions) + val all = plugin.getAll(null, dataStoreOptions) Assert.assertEquals(all[boolKey], testBool) Assert.assertEquals(all[stringKey], testString) @@ -142,33 +150,154 @@ internal class SharedPreferencesTest { } @Test - fun testClearWithAllowList() { - val plugin = pluginSetup() - plugin.setBool(boolKey, testBool, emptyOptions) - plugin.setString(stringKey, testString, emptyOptions) - plugin.setInt(intKey, testInt, emptyOptions) - plugin.setDouble(doubleKey, testDouble, emptyOptions) - plugin.setStringList(listKey, testList, emptyOptions) + fun testClearWithAllowListWithDataStore() { + val plugin = pluginSetup(dataStoreOptions) + plugin.setBool(boolKey, testBool, dataStoreOptions) + plugin.setString(stringKey, testString, dataStoreOptions) + plugin.setInt(intKey, testInt, dataStoreOptions) + plugin.setDouble(doubleKey, testDouble, dataStoreOptions) + plugin.setStringList(listKey, testList, dataStoreOptions) + + plugin.clear(listOf(boolKey, stringKey), dataStoreOptions) + + Assert.assertNull(plugin.getBool(boolKey, dataStoreOptions)) + Assert.assertNull(plugin.getString(stringKey, dataStoreOptions)) + Assert.assertNotNull(plugin.getInt(intKey, dataStoreOptions)) + Assert.assertNotNull(plugin.getDouble(doubleKey, dataStoreOptions)) + Assert.assertNotNull(plugin.getStringList(listKey, dataStoreOptions)) + } + + @Test + fun testGetAllWithAllowListWithDataStore() { + val plugin = pluginSetup(dataStoreOptions) + plugin.setBool(boolKey, testBool, dataStoreOptions) + plugin.setString(stringKey, testString, dataStoreOptions) + plugin.setInt(intKey, testInt, dataStoreOptions) + plugin.setDouble(doubleKey, testDouble, dataStoreOptions) + plugin.setStringList(listKey, testList, dataStoreOptions) + + val all = plugin.getAll(listOf(boolKey, stringKey), dataStoreOptions) + + Assert.assertEquals(all[boolKey], testBool) + Assert.assertEquals(all[stringKey], testString) + Assert.assertNull(all[intKey]) + Assert.assertNull(all[doubleKey]) + Assert.assertNull(all[listKey]) + } + + @Test + fun testSetAndGetBoolWithSharedPreferences() { + val plugin = pluginSetup(sharedPreferencesOptions) + plugin.setBool(boolKey, testBool, sharedPreferencesOptions) + Assert.assertEquals(plugin.getBool(boolKey, sharedPreferencesOptions), testBool) + } - plugin.clear(listOf(boolKey, stringKey), emptyOptions) + @Test + fun testSetAndGetStringWithSharedPreferences() { + val plugin = pluginSetup(sharedPreferencesOptions) + plugin.setString(stringKey, testString, sharedPreferencesOptions) + Assert.assertEquals(plugin.getString(stringKey, sharedPreferencesOptions), testString) + } - Assert.assertNull(plugin.getBool(boolKey, emptyOptions)) - Assert.assertNull(plugin.getString(stringKey, emptyOptions)) - Assert.assertNotNull(plugin.getInt(intKey, emptyOptions)) - Assert.assertNotNull(plugin.getDouble(doubleKey, emptyOptions)) - Assert.assertNotNull(plugin.getStringList(listKey, emptyOptions)) + @Test + fun testSetAndGetIntWithSharedPreferences() { + val plugin = pluginSetup(sharedPreferencesOptions) + plugin.setInt(intKey, testInt, sharedPreferencesOptions) + Assert.assertEquals(plugin.getInt(intKey, sharedPreferencesOptions), testInt) } @Test - fun testGetAllWithAllowList() { - val plugin = pluginSetup() - plugin.setBool(boolKey, testBool, emptyOptions) - plugin.setString(stringKey, testString, emptyOptions) - plugin.setInt(intKey, testInt, emptyOptions) - plugin.setDouble(doubleKey, testDouble, emptyOptions) - plugin.setStringList(listKey, testList, emptyOptions) + fun testSetAndGetDoubleWithSharedPreferences() { + val plugin = pluginSetup(sharedPreferencesOptions) + plugin.setDouble(doubleKey, testDouble, sharedPreferencesOptions) + Assert.assertEquals(plugin.getDouble(doubleKey, sharedPreferencesOptions), testDouble) + } - val all = plugin.getAll(listOf(boolKey, stringKey), emptyOptions) + @Test + fun testSetAndGetStringListWithSharedPreferences() { + val plugin = pluginSetup(sharedPreferencesOptions) + plugin.setStringList(listKey, testList, sharedPreferencesOptions) + Assert.assertEquals(plugin.getStringList(listKey, sharedPreferencesOptions), testList) + } + + @Test + fun testGetKeysWithSharedPreferences() { + val plugin = pluginSetup(sharedPreferencesOptions) + plugin.setBool(boolKey, testBool, sharedPreferencesOptions) + plugin.setString(stringKey, testString, sharedPreferencesOptions) + plugin.setInt(intKey, testInt, sharedPreferencesOptions) + plugin.setDouble(doubleKey, testDouble, sharedPreferencesOptions) + plugin.setStringList(listKey, testList, sharedPreferencesOptions) + val keyList = plugin.getKeys(listOf(boolKey, stringKey), sharedPreferencesOptions) + Assert.assertEquals(keyList.size, 2) + Assert.assertTrue(keyList.contains(stringKey)) + Assert.assertTrue(keyList.contains(boolKey)) + } + + @Test + fun testClearWithSharedPreferences() { + val plugin = pluginSetup(sharedPreferencesOptions) + plugin.setBool(boolKey, testBool, sharedPreferencesOptions) + plugin.setString(stringKey, testString, sharedPreferencesOptions) + plugin.setInt(intKey, testInt, sharedPreferencesOptions) + plugin.setDouble(doubleKey, testDouble, sharedPreferencesOptions) + plugin.setStringList(listKey, testList, sharedPreferencesOptions) + + plugin.clear(null, sharedPreferencesOptions) + + Assert.assertNull(plugin.getBool(boolKey, sharedPreferencesOptions)) + Assert.assertNull(plugin.getBool(stringKey, sharedPreferencesOptions)) + Assert.assertNull(plugin.getBool(intKey, sharedPreferencesOptions)) + Assert.assertNull(plugin.getBool(doubleKey, sharedPreferencesOptions)) + Assert.assertNull(plugin.getBool(listKey, sharedPreferencesOptions)) + } + + @Test + fun testGetAllWithSharedPreferences() { + val plugin = pluginSetup(sharedPreferencesOptions) + plugin.setBool(boolKey, testBool, sharedPreferencesOptions) + plugin.setString(stringKey, testString, sharedPreferencesOptions) + plugin.setInt(intKey, testInt, sharedPreferencesOptions) + plugin.setDouble(doubleKey, testDouble, sharedPreferencesOptions) + plugin.setStringList(listKey, testList, sharedPreferencesOptions) + + val all = plugin.getAll(null, sharedPreferencesOptions) + + Assert.assertEquals(all[boolKey], testBool) + Assert.assertEquals(all[stringKey], testString) + Assert.assertEquals(all[intKey], testInt) + Assert.assertEquals(all[doubleKey], testDouble) + Assert.assertEquals(all[listKey], testList) + } + + @Test + fun testClearWithAllowListWithSharedPreferences() { + val plugin = pluginSetup(sharedPreferencesOptions) + plugin.setBool(boolKey, testBool, sharedPreferencesOptions) + plugin.setString(stringKey, testString, sharedPreferencesOptions) + plugin.setInt(intKey, testInt, sharedPreferencesOptions) + plugin.setDouble(doubleKey, testDouble, sharedPreferencesOptions) + plugin.setStringList(listKey, testList, sharedPreferencesOptions) + + plugin.clear(listOf(boolKey, stringKey), sharedPreferencesOptions) + + Assert.assertNull(plugin.getBool(boolKey, sharedPreferencesOptions)) + Assert.assertNull(plugin.getString(stringKey, sharedPreferencesOptions)) + Assert.assertNotNull(plugin.getInt(intKey, sharedPreferencesOptions)) + Assert.assertNotNull(plugin.getDouble(doubleKey, sharedPreferencesOptions)) + Assert.assertNotNull(plugin.getStringList(listKey, sharedPreferencesOptions)) + } + + @Test + fun testGetAllWithAllowListWithSharedPreferences() { + val plugin = pluginSetup(sharedPreferencesOptions) + plugin.setBool(boolKey, testBool, sharedPreferencesOptions) + plugin.setString(stringKey, testString, sharedPreferencesOptions) + plugin.setInt(intKey, testInt, sharedPreferencesOptions) + plugin.setDouble(doubleKey, testDouble, sharedPreferencesOptions) + plugin.setStringList(listKey, testList, sharedPreferencesOptions) + + val all = plugin.getAll(listOf(boolKey, stringKey), sharedPreferencesOptions) Assert.assertEquals(all[boolKey], testBool) Assert.assertEquals(all[stringKey], testString) @@ -177,6 +306,26 @@ internal class SharedPreferencesTest { Assert.assertNull(all[listKey]) } + @Test + fun testSharedPreferencesWithMultipleFiles() { + val plugin = pluginSetup(sharedPreferencesOptions) + val optionsWithNewFile = + SharedPreferencesPigeonOptions(useDataStore = false, fileName = "test_file") + plugin.setInt(intKey, 1, sharedPreferencesOptions) + plugin.setInt(intKey, 2, optionsWithNewFile) + Assert.assertEquals(plugin.getInt(intKey, sharedPreferencesOptions), 1L) + Assert.assertEquals(plugin.getInt(intKey, optionsWithNewFile), 2L) + } + + @Test + fun testSharedPreferencesDefaultFile() { + val defaultPreferences: SharedPreferences = + PreferenceManager.getDefaultSharedPreferences(testContext) + defaultPreferences.edit().putString(stringKey, testString).commit() + val plugin = pluginSetup(sharedPreferencesOptions) + Assert.assertEquals(plugin.getString(stringKey, sharedPreferencesOptions), testString) + } + @Test fun testUnexpectedClassDecodeThrows() { // Only String should be allowed in an encoded list. @@ -188,12 +337,12 @@ internal class SharedPreferencesTest { stream.flush() val badPref = LIST_PREFIX + Base64.encodeToString(byteStream.toByteArray(), 0) - val plugin = pluginSetup() + val plugin = pluginSetup(dataStoreOptions) val badListKey = "badList" // Inject the bad pref as a string, as that is how string lists are stored internally. - plugin.setString(badListKey, badPref, emptyOptions) + plugin.setString(badListKey, badPref, dataStoreOptions) assertThrows(ClassNotFoundException::class.java) { - plugin.getStringList(badListKey, emptyOptions) + plugin.getStringList(badListKey, dataStoreOptions) } } } diff --git a/packages/shared_preferences/shared_preferences_android/example/android/.gitignore b/packages/shared_preferences/shared_preferences_android/example/android/.gitignore index 8e599af9f21..55afd919c65 100644 --- a/packages/shared_preferences/shared_preferences_android/example/android/.gitignore +++ b/packages/shared_preferences/shared_preferences_android/example/android/.gitignore @@ -9,3 +9,5 @@ GeneratedPluginRegistrant.java # Remember to never publicly share your keystore. # See https://flutter.dev/to/reference-keystore key.properties +**/*.keystore +**/*.jks diff --git a/packages/shared_preferences/shared_preferences_android/example/android/app/build.gradle b/packages/shared_preferences/shared_preferences_android/example/android/app/build.gradle index b2379b24950..f59008b9173 100644 --- a/packages/shared_preferences/shared_preferences_android/example/android/app/build.gradle +++ b/packages/shared_preferences/shared_preferences_android/example/android/app/build.gradle @@ -1,3 +1,16 @@ +buildscript { + ext.kotlin_version = '1.7.10' + repositories { + google() + mavenCentral() + } + + dependencies { + classpath 'com.android.tools.build:gradle:8.5.1' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + plugins { id "com.android.application" id "org.jetbrains.kotlin.android" @@ -23,15 +36,25 @@ if (flutterVersionName == null) { } android { - namespace 'io.flutter.plugins.sharedpreferencesexample' + namespace "dev.flutter.plugins.shared_preferences_example" compileSdk flutter.compileSdkVersion + ndkVersion flutter.ndkVersion + + compileOptions { + sourceCompatibility JavaVersion.VERSION_11 + targetCompatibility JavaVersion.VERSION_11 + } + + kotlinOptions { + jvmTarget = '11' + } sourceSets { main.java.srcDirs += 'src/main/kotlin' } defaultConfig { - applicationId "io.flutter.plugins.sharedpreferencesexample" + applicationId "dev.flutter.plugins.shared_preferences_example" minSdkVersion flutter.minSdkVersion targetSdkVersion 34 versionCode flutterVersionCode.toInteger() @@ -54,4 +77,11 @@ flutter { dependencies { implementation "androidx.datastore:datastore-preferences:1.0.0" + implementation 'androidx.preference:preference:1.2.1' + testImplementation 'junit:junit:4.13.2' + androidTestImplementation 'androidx.test.espresso:espresso-intents:3.2.0' + androidTestImplementation 'androidx.test:runner:1.2.0' + androidTestImplementation 'androidx.test:rules:1.2.0' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' + api 'androidx.test:core:1.4.0' } diff --git a/packages/shared_preferences/shared_preferences_android/example/android/app/src/androidTest/java/io/flutter/plugins/sharedpreferencesexample/MainActivityTest.java b/packages/shared_preferences/shared_preferences_android/example/android/app/src/androidTest/java/dev/flutter/plugins/shared_preferences_example/MainActivityTest.java similarity index 69% rename from packages/shared_preferences/shared_preferences_android/example/android/app/src/androidTest/java/io/flutter/plugins/sharedpreferencesexample/MainActivityTest.java rename to packages/shared_preferences/shared_preferences_android/example/android/app/src/androidTest/java/dev/flutter/plugins/shared_preferences_example/MainActivityTest.java index 304ee4c3332..20e13ab4115 100644 --- a/packages/shared_preferences/shared_preferences_android/example/android/app/src/androidTest/java/io/flutter/plugins/sharedpreferencesexample/MainActivityTest.java +++ b/packages/shared_preferences/shared_preferences_android/example/android/app/src/androidTest/java/dev/flutter/plugins/shared_preferences_example/MainActivityTest.java @@ -2,11 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -package io.flutter.plugins.sharedpreferences; +package dev.flutter.plugins.shared_preferences_example; import androidx.test.rule.ActivityTestRule; import dev.flutter.plugins.integration_test.FlutterTestRunner; -import io.flutter.embedding.android.FlutterActivity; import io.flutter.plugins.DartIntegrationTest; import org.junit.Rule; import org.junit.runner.RunWith; @@ -14,6 +13,5 @@ @DartIntegrationTest @RunWith(FlutterTestRunner.class) public class MainActivityTest { - @Rule - public ActivityTestRule rule = new ActivityTestRule<>(FlutterActivity.class); + @Rule public ActivityTestRule rule = new ActivityTestRule<>(MainActivity.class); } diff --git a/packages/shared_preferences/shared_preferences_android/example/android/app/src/debug/AndroidManifest.xml b/packages/shared_preferences/shared_preferences_android/example/android/app/src/debug/AndroidManifest.xml index d60d6f69a86..399f6981d5d 100644 --- a/packages/shared_preferences/shared_preferences_android/example/android/app/src/debug/AndroidManifest.xml +++ b/packages/shared_preferences/shared_preferences_android/example/android/app/src/debug/AndroidManifest.xml @@ -1,6 +1,6 @@ - - diff --git a/packages/shared_preferences/shared_preferences_android/example/android/app/src/main/AndroidManifest.xml b/packages/shared_preferences/shared_preferences_android/example/android/app/src/main/AndroidManifest.xml index 4288e93f875..1300cc59764 100644 --- a/packages/shared_preferences/shared_preferences_android/example/android/app/src/main/AndroidManifest.xml +++ b/packages/shared_preferences/shared_preferences_android/example/android/app/src/main/AndroidManifest.xml @@ -1,10 +1,10 @@ - - + - diff --git a/packages/shared_preferences/shared_preferences_android/example/android/gradle/wrapper/gradle-wrapper.properties b/packages/shared_preferences/shared_preferences_android/example/android/gradle/wrapper/gradle-wrapper.properties index b9150adbf12..3c85cfe057a 100644 --- a/packages/shared_preferences/shared_preferences_android/example/android/gradle/wrapper/gradle-wrapper.properties +++ b/packages/shared_preferences/shared_preferences_android/example/android/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,5 @@ -#Wed Jan 17 19:21:34 PST 2024 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-all.zip diff --git a/packages/shared_preferences/shared_preferences_android/example/android/settings.gradle b/packages/shared_preferences/shared_preferences_android/example/android/settings.gradle index d056e4db366..74d52ff12f4 100644 --- a/packages/shared_preferences/shared_preferences_android/example/android/settings.gradle +++ b/packages/shared_preferences/shared_preferences_android/example/android/settings.gradle @@ -19,7 +19,7 @@ pluginManagement { // See https://github.com/flutter/flutter/blob/master/docs/ecosystem/Plugins-and-Packages-repository-structure.md#gradle-structure for more info. plugins { id "dev.flutter.flutter-plugin-loader" version "1.0.0" - id "com.android.application" version "8.5.1" apply false + id "com.android.application" version "8.5.2" apply false id "org.jetbrains.kotlin.android" version "1.9.0" apply false id "com.google.cloud.artifactregistry.gradle-plugin" version "2.2.1" } diff --git a/packages/shared_preferences/shared_preferences_android/example/integration_test/shared_preferences_test.dart b/packages/shared_preferences/shared_preferences_android/example/integration_test/shared_preferences_test.dart index 48f451d20a1..0335b00968b 100644 --- a/packages/shared_preferences/shared_preferences_android/example/integration_test/shared_preferences_test.dart +++ b/packages/shared_preferences/shared_preferences_android/example/integration_test/shared_preferences_test.dart @@ -495,208 +495,299 @@ void main() { }); }); - group('shared_preferences_async', () { - const SharedPreferencesAsyncAndroidOptions emptyOptions = - SharedPreferencesAsyncAndroidOptions(); - - const String stringKey = 'testString'; - const String boolKey = 'testBool'; - const String intKey = 'testInt'; - const String doubleKey = 'testDouble'; - const String listKey = 'testList'; - - const String testString = 'hello world'; - const bool testBool = true; - const int testInt = 42; - const double testDouble = 3.14159; - const List testList = ['foo', 'bar']; - - Future getPreferences() async { - final SharedPreferencesAsyncPlatform preferences = - SharedPreferencesAsyncPlatform.instance!; - await preferences.clear( - const ClearPreferencesParameters(filter: PreferencesFilters()), - emptyOptions); - return preferences; - } - - testWidgets('set and get String', (WidgetTester _) async { - final SharedPreferencesAsyncPlatform preferences = await getPreferences(); - - await preferences.setString(stringKey, testString, emptyOptions); - expect(await preferences.getString(stringKey, emptyOptions), testString); - }); + const String stringKey = 'testString'; + const String boolKey = 'testBool'; + const String intKey = 'testInt'; + const String doubleKey = 'testDouble'; + const String listKey = 'testList'; + + const String testString = 'hello world'; + const bool testBool = true; + const int testInt = 42; + const double testDouble = 3.14159; + const List testList = ['foo', 'bar']; + + SharedPreferencesAsyncAndroidOptions getOptions({ + required bool useDataStore, + String? fileName, + }) { + return SharedPreferencesAsyncAndroidOptions( + backend: useDataStore + ? SharedPreferencesAndroidBackendLibrary.DataStore + : SharedPreferencesAndroidBackendLibrary.SharedPreferences, + originalSharedPreferencesOptions: fileName == null + ? null + : AndroidSharedPreferencesStoreOptions(fileName: fileName), + ); + } + + Future clearPreferences( + SharedPreferencesAsyncPlatform preferences, + SharedPreferencesAsyncAndroidOptions options, + ) async { + await preferences.clear( + const ClearPreferencesParameters(filter: PreferencesFilters()), + options); + } + + SharedPreferencesAsyncPlatform getPreferences() { + final SharedPreferencesAsyncPlatform preferences = + SharedPreferencesAsyncPlatform.instance!; + return preferences; + } + + void runAsyncTests(bool useDataStore) { + group('shared_preferences_async', () { + final String backend = useDataStore ? 'DataStore' : 'SharedPreferences'; + + testWidgets('set and get String with $backend', (WidgetTester _) async { + final SharedPreferencesAsyncAndroidOptions options = + getOptions(useDataStore: useDataStore, fileName: 'notDefault'); + final SharedPreferencesAsyncPlatform preferences = getPreferences(); + await clearPreferences(preferences, options); + + await preferences.setString(stringKey, testString, options); + expect(await preferences.getString(stringKey, options), testString); + }); - testWidgets('set and get bool', (WidgetTester _) async { - final SharedPreferencesAsyncPlatform preferences = await getPreferences(); + testWidgets('set and get bool with $backend', (WidgetTester _) async { + final SharedPreferencesAsyncAndroidOptions options = + getOptions(useDataStore: useDataStore, fileName: 'notDefault'); + final SharedPreferencesAsyncPlatform preferences = getPreferences(); + await clearPreferences(preferences, options); - await preferences.setBool(boolKey, testBool, emptyOptions); - expect(await preferences.getBool(boolKey, emptyOptions), testBool); - }); + await preferences.setBool(boolKey, testBool, options); + expect(await preferences.getBool(boolKey, options), testBool); + }); - testWidgets('set and get int', (WidgetTester _) async { - final SharedPreferencesAsyncPlatform preferences = await getPreferences(); + testWidgets('set and get int with $backend', (WidgetTester _) async { + final SharedPreferencesAsyncAndroidOptions options = + getOptions(useDataStore: useDataStore, fileName: 'notDefault'); + final SharedPreferencesAsyncPlatform preferences = getPreferences(); + await clearPreferences(preferences, options); - await preferences.setInt(intKey, testInt, emptyOptions); - expect(await preferences.getInt(intKey, emptyOptions), testInt); - }); + await preferences.setInt(intKey, testInt, options); + expect(await preferences.getInt(intKey, options), testInt); + }); - testWidgets('set and get double', (WidgetTester _) async { - final SharedPreferencesAsyncPlatform preferences = await getPreferences(); + testWidgets('set and get double with $backend', (WidgetTester _) async { + final SharedPreferencesAsyncAndroidOptions options = + getOptions(useDataStore: useDataStore, fileName: 'notDefault'); + final SharedPreferencesAsyncPlatform preferences = getPreferences(); + await clearPreferences(preferences, options); - await preferences.setDouble(doubleKey, testDouble, emptyOptions); - expect(await preferences.getDouble(doubleKey, emptyOptions), testDouble); - }); + await preferences.setDouble(doubleKey, testDouble, options); + expect(await preferences.getDouble(doubleKey, options), testDouble); + }); - testWidgets('set and get StringList', (WidgetTester _) async { - final SharedPreferencesAsyncPlatform preferences = await getPreferences(); + testWidgets('set and get StringList with $backend', + (WidgetTester _) async { + final SharedPreferencesAsyncAndroidOptions options = + getOptions(useDataStore: useDataStore, fileName: 'notDefault'); + final SharedPreferencesAsyncPlatform preferences = getPreferences(); + await clearPreferences(preferences, options); - await preferences.setStringList(listKey, testList, emptyOptions); - expect(await preferences.getStringList(listKey, emptyOptions), testList); - }); + await preferences.setStringList(listKey, testList, options); + expect(await preferences.getStringList(listKey, options), testList); + }); - testWidgets('getStringList returns mutable list', (WidgetTester _) async { - final SharedPreferencesAsyncPlatform preferences = await getPreferences(); + testWidgets('getStringList returns mutable list with $backend', + (WidgetTester _) async { + final SharedPreferencesAsyncAndroidOptions options = + getOptions(useDataStore: useDataStore, fileName: 'notDefault'); + final SharedPreferencesAsyncPlatform preferences = getPreferences(); + await clearPreferences(preferences, options); + + await preferences.setStringList(listKey, testList, options); + final List? list = + await preferences.getStringList(listKey, options); + list?.add('value'); + expect(list?.length, testList.length + 1); + }); - await preferences.setStringList(listKey, testList, emptyOptions); - final List? list = - await preferences.getStringList(listKey, emptyOptions); - list?.add('value'); - expect(list?.length, testList.length + 1); - }); + testWidgets('getPreferences with $backend', (WidgetTester _) async { + final SharedPreferencesAsyncAndroidOptions options = + getOptions(useDataStore: useDataStore, fileName: 'notDefault'); + final SharedPreferencesAsyncPlatform preferences = getPreferences(); + await clearPreferences(preferences, options); + await Future.wait(>[ + preferences.setString(stringKey, testString, options), + preferences.setBool(boolKey, testBool, options), + preferences.setInt(intKey, testInt, options), + preferences.setDouble(doubleKey, testDouble, options), + preferences.setStringList(listKey, testList, options) + ]); - testWidgets('getPreferences', (WidgetTester _) async { - final SharedPreferencesAsyncPlatform preferences = await getPreferences(); - await Future.wait(>[ - preferences.setString(stringKey, testString, emptyOptions), - preferences.setBool(boolKey, testBool, emptyOptions), - preferences.setInt(intKey, testInt, emptyOptions), - preferences.setDouble(doubleKey, testDouble, emptyOptions), - preferences.setStringList(listKey, testList, emptyOptions) - ]); + final Map gotAll = await preferences.getPreferences( + const GetPreferencesParameters(filter: PreferencesFilters()), + options, + ); - final Map gotAll = await preferences.getPreferences( - const GetPreferencesParameters(filter: PreferencesFilters()), - emptyOptions, - ); + expect(gotAll.length, 5); + expect(gotAll[stringKey], testString); + expect(gotAll[boolKey], testBool); + expect(gotAll[intKey], testInt); + expect(gotAll[doubleKey], testDouble); + expect(gotAll[listKey], testList); + }); - expect(gotAll.length, 5); - expect(gotAll[stringKey], testString); - expect(gotAll[boolKey], testBool); - expect(gotAll[intKey], testInt); - expect(gotAll[doubleKey], testDouble); - expect(gotAll[listKey], testList); - }); + testWidgets('getPreferences with filter with $backend', + (WidgetTester _) async { + final SharedPreferencesAsyncAndroidOptions options = + getOptions(useDataStore: useDataStore, fileName: 'notDefault'); + final SharedPreferencesAsyncPlatform preferences = getPreferences(); + await clearPreferences(preferences, options); + await Future.wait(>[ + preferences.setString(stringKey, testString, options), + preferences.setBool(boolKey, testBool, options), + preferences.setInt(intKey, testInt, options), + preferences.setDouble(doubleKey, testDouble, options), + preferences.setStringList(listKey, testList, options) + ]); - testWidgets('getPreferences with filter', (WidgetTester _) async { - final SharedPreferencesAsyncPlatform preferences = await getPreferences(); - await Future.wait(>[ - preferences.setString(stringKey, testString, emptyOptions), - preferences.setBool(boolKey, testBool, emptyOptions), - preferences.setInt(intKey, testInt, emptyOptions), - preferences.setDouble(doubleKey, testDouble, emptyOptions), - preferences.setStringList(listKey, testList, emptyOptions) - ]); + final Map gotAll = await preferences.getPreferences( + const GetPreferencesParameters( + filter: PreferencesFilters(allowList: {stringKey, boolKey}), + ), + options, + ); - final Map gotAll = await preferences.getPreferences( - const GetPreferencesParameters( - filter: PreferencesFilters(allowList: {stringKey, boolKey}), - ), - emptyOptions, - ); + expect(gotAll.length, 2); + expect(gotAll[stringKey], testString); + expect(gotAll[boolKey], testBool); + }); - expect(gotAll.length, 2); - expect(gotAll[stringKey], testString); - expect(gotAll[boolKey], testBool); - }); + testWidgets('getKeys with $backend', (WidgetTester _) async { + final SharedPreferencesAsyncAndroidOptions options = + getOptions(useDataStore: useDataStore, fileName: 'notDefault'); + final SharedPreferencesAsyncPlatform preferences = getPreferences(); + await clearPreferences(preferences, options); + await Future.wait(>[ + preferences.setString(stringKey, testString, options), + preferences.setBool(boolKey, testBool, options), + preferences.setInt(intKey, testInt, options), + preferences.setDouble(doubleKey, testDouble, options), + preferences.setStringList(listKey, testList, options) + ]); - testWidgets('getKeys', (WidgetTester _) async { - final SharedPreferencesAsyncPlatform preferences = await getPreferences(); - await Future.wait(>[ - preferences.setString(stringKey, testString, emptyOptions), - preferences.setBool(boolKey, testBool, emptyOptions), - preferences.setInt(intKey, testInt, emptyOptions), - preferences.setDouble(doubleKey, testDouble, emptyOptions), - preferences.setStringList(listKey, testList, emptyOptions) - ]); + final Set keys = await preferences.getKeys( + const GetPreferencesParameters(filter: PreferencesFilters()), + options, + ); - final Set keys = await preferences.getKeys( - const GetPreferencesParameters(filter: PreferencesFilters()), - emptyOptions, - ); + expect(keys.length, 5); + expect(keys, contains(stringKey)); + expect(keys, contains(boolKey)); + expect(keys, contains(intKey)); + expect(keys, contains(doubleKey)); + expect(keys, contains(listKey)); + }); - expect(keys.length, 5); - expect(keys, contains(stringKey)); - expect(keys, contains(boolKey)); - expect(keys, contains(intKey)); - expect(keys, contains(doubleKey)); - expect(keys, contains(listKey)); - }); + testWidgets('getKeys with filter with $backend', (WidgetTester _) async { + final SharedPreferencesAsyncAndroidOptions options = + getOptions(useDataStore: useDataStore, fileName: 'notDefault'); + final SharedPreferencesAsyncPlatform preferences = getPreferences(); + await clearPreferences(preferences, options); + await Future.wait(>[ + preferences.setString(stringKey, testString, options), + preferences.setBool(boolKey, testBool, options), + preferences.setInt(intKey, testInt, options), + preferences.setDouble(doubleKey, testDouble, options), + preferences.setStringList(listKey, testList, options) + ]); - testWidgets('getKeys with filter', (WidgetTester _) async { - final SharedPreferencesAsyncPlatform preferences = await getPreferences(); - await Future.wait(>[ - preferences.setString(stringKey, testString, emptyOptions), - preferences.setBool(boolKey, testBool, emptyOptions), - preferences.setInt(intKey, testInt, emptyOptions), - preferences.setDouble(doubleKey, testDouble, emptyOptions), - preferences.setStringList(listKey, testList, emptyOptions) - ]); + final Set keys = await preferences.getKeys( + const GetPreferencesParameters( + filter: PreferencesFilters(allowList: {stringKey, boolKey}), + ), + options, + ); - final Set keys = await preferences.getKeys( - const GetPreferencesParameters( - filter: PreferencesFilters(allowList: {stringKey, boolKey}), - ), - emptyOptions, - ); + expect(keys.length, 2); + expect(keys, contains(stringKey)); + expect(keys, contains(boolKey)); + }); - expect(keys.length, 2); - expect(keys, contains(stringKey)); - expect(keys, contains(boolKey)); - }); + testWidgets('clear with $backend', (WidgetTester _) async { + final SharedPreferencesAsyncAndroidOptions options = + getOptions(useDataStore: useDataStore, fileName: 'notDefault'); + final SharedPreferencesAsyncPlatform preferences = getPreferences(); + await clearPreferences(preferences, options); + await Future.wait(>[ + preferences.setString(stringKey, testString, options), + preferences.setBool(boolKey, testBool, options), + preferences.setInt(intKey, testInt, options), + preferences.setDouble(doubleKey, testDouble, options), + preferences.setStringList(listKey, testList, options) + ]); - testWidgets('clear', (WidgetTester _) async { - final SharedPreferencesAsyncPlatform preferences = await getPreferences(); - await Future.wait(>[ - preferences.setString(stringKey, testString, emptyOptions), - preferences.setBool(boolKey, testBool, emptyOptions), - preferences.setInt(intKey, testInt, emptyOptions), - preferences.setDouble(doubleKey, testDouble, emptyOptions), - preferences.setStringList(listKey, testList, emptyOptions) - ]); + await preferences.clear( + const ClearPreferencesParameters(filter: PreferencesFilters()), + options, + ); - await preferences.clear( - const ClearPreferencesParameters(filter: PreferencesFilters()), - emptyOptions, - ); + expect(await preferences.getString(stringKey, options), null); + expect(await preferences.getBool(boolKey, options), null); + expect(await preferences.getInt(intKey, options), null); + expect(await preferences.getDouble(doubleKey, options), null); + expect(await preferences.getStringList(listKey, options), null); + }); - expect(await preferences.getString(stringKey, emptyOptions), null); - expect(await preferences.getBool(boolKey, emptyOptions), null); - expect(await preferences.getInt(intKey, emptyOptions), null); - expect(await preferences.getDouble(doubleKey, emptyOptions), null); - expect(await preferences.getStringList(listKey, emptyOptions), null); + testWidgets('clear with filter with $backend', (WidgetTester _) async { + final SharedPreferencesAsyncAndroidOptions options = + getOptions(useDataStore: useDataStore, fileName: 'notDefault'); + final SharedPreferencesAsyncPlatform preferences = getPreferences(); + await clearPreferences(preferences, options); + await Future.wait(>[ + preferences.setString(stringKey, testString, options), + preferences.setBool(boolKey, testBool, options), + preferences.setInt(intKey, testInt, options), + preferences.setDouble(doubleKey, testDouble, options), + preferences.setStringList(listKey, testList, options) + ]); + await preferences.clear( + const ClearPreferencesParameters( + filter: PreferencesFilters(allowList: {stringKey, boolKey}), + ), + options, + ); + expect(await preferences.getString(stringKey, options), null); + expect(await preferences.getBool(boolKey, options), null); + expect(await preferences.getInt(intKey, options), testInt); + expect(await preferences.getDouble(doubleKey, options), testDouble); + expect(await preferences.getStringList(listKey, options), testList); + }); }); + } + + runAsyncTests(true); + runAsyncTests(false); + + testWidgets('Shared Preferences works with multiple files', + (WidgetTester _) async { + final SharedPreferencesAsyncAndroidOptions options1 = + getOptions(useDataStore: false, fileName: 'file1'); + final SharedPreferencesAsyncAndroidOptions options2 = + getOptions(useDataStore: false, fileName: 'file2'); + final SharedPreferencesAsyncPlatform preferences = getPreferences(); + await clearPreferences(preferences, options1); + await clearPreferences(preferences, options2); + + await preferences.setInt(intKey, 1, options1); + await preferences.setInt(intKey, 2, options2); + expect(await preferences.getInt(intKey, options1), 1); + expect(await preferences.getInt(intKey, options2), 2); + }); - testWidgets('clear with filter', (WidgetTester _) async { - final SharedPreferencesAsyncPlatform preferences = await getPreferences(); - await Future.wait(>[ - preferences.setString(stringKey, testString, emptyOptions), - preferences.setBool(boolKey, testBool, emptyOptions), - preferences.setInt(intKey, testInt, emptyOptions), - preferences.setDouble(doubleKey, testDouble, emptyOptions), - preferences.setStringList(listKey, testList, emptyOptions) - ]); - await preferences.clear( - const ClearPreferencesParameters( - filter: PreferencesFilters(allowList: {stringKey, boolKey}), - ), - emptyOptions, - ); - expect(await preferences.getString(stringKey, emptyOptions), null); - expect(await preferences.getBool(boolKey, emptyOptions), null); - expect(await preferences.getInt(intKey, emptyOptions), testInt); - expect(await preferences.getDouble(doubleKey, emptyOptions), testDouble); - expect(await preferences.getStringList(listKey, emptyOptions), testList); - }); + testWidgets('Shared Preferences can read default sharedPreferences', + (WidgetTester _) async { + final SharedPreferencesAsyncAndroidOptions options = + getOptions(useDataStore: false); + final SharedPreferencesAsyncPlatform preferences = getPreferences(); + + expect( + await preferences.getString( + 'thisStringIsWrittenInTheExampleAppJavaCode', options), + 'testString'); }); } diff --git a/packages/shared_preferences/shared_preferences_android/example/lib/main.dart b/packages/shared_preferences/shared_preferences_android/example/lib/main.dart index 5bf8d060920..e4a0e2121f2 100644 --- a/packages/shared_preferences/shared_preferences_android/example/lib/main.dart +++ b/packages/shared_preferences/shared_preferences_android/example/lib/main.dart @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// ignore_for_file: public_member_api_docs +// ignore_for_file: public_member_api_docs, unreachable_from_main import 'package:flutter/material.dart'; import 'package:shared_preferences_android/shared_preferences_android.dart'; @@ -12,6 +12,14 @@ void main() { runApp(const MyApp()); } +// #docregion Android_Options +const SharedPreferencesAsyncAndroidOptions options = + SharedPreferencesAsyncAndroidOptions( + backend: SharedPreferencesAndroidBackendLibrary.SharedPreferences, + originalSharedPreferencesOptions: AndroidSharedPreferencesStoreOptions( + fileName: 'the_name_of_a_file')); +// #enddocregion Android_Options + class MyApp extends StatelessWidget { const MyApp({super.key}); diff --git a/packages/shared_preferences/shared_preferences_android/lib/src/messages_async.g.dart b/packages/shared_preferences/shared_preferences_android/lib/src/messages_async.g.dart index d355cfd916d..c21b49cca96 100644 --- a/packages/shared_preferences/shared_preferences_android/lib/src/messages_async.g.dart +++ b/packages/shared_preferences/shared_preferences_android/lib/src/messages_async.g.dart @@ -1,7 +1,7 @@ // Copyright 2013 The Flutter Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Autogenerated from Pigeon (v16.0.5), do not edit directly. +// Autogenerated from Pigeon (v22.6.1), do not edit directly. // See also: https://pub.dev/packages/pigeon // ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import, no_leading_underscores_for_local_identifiers @@ -20,31 +20,39 @@ PlatformException _createConnectionError(String channelName) { class SharedPreferencesPigeonOptions { SharedPreferencesPigeonOptions({ - this.fileKey, + this.fileName, + this.useDataStore = true, }); - String? fileKey; + String? fileName; + + bool useDataStore; Object encode() { return [ - fileKey, + fileName, + useDataStore, ]; } static SharedPreferencesPigeonOptions decode(Object result) { result as List; return SharedPreferencesPigeonOptions( - fileKey: result[0] as String?, + fileName: result[0] as String?, + useDataStore: result[1]! as bool, ); } } -class _SharedPreferencesAsyncApiCodec extends StandardMessageCodec { - const _SharedPreferencesAsyncApiCodec(); +class _PigeonCodec extends StandardMessageCodec { + const _PigeonCodec(); @override void writeValue(WriteBuffer buffer, Object? value) { - if (value is SharedPreferencesPigeonOptions) { - buffer.putUint8(128); + if (value is int) { + buffer.putUint8(4); + buffer.putInt64(value); + } else if (value is SharedPreferencesPigeonOptions) { + buffer.putUint8(129); writeValue(buffer, value.encode()); } else { super.writeValue(buffer, value); @@ -54,7 +62,7 @@ class _SharedPreferencesAsyncApiCodec extends StandardMessageCodec { @override Object? readValueOfType(int type, ReadBuffer buffer) { switch (type) { - case 128: + case 129: return SharedPreferencesPigeonOptions.decode(readValue(buffer)!); default: return super.readValueOfType(type, buffer); @@ -66,33 +74,37 @@ class SharedPreferencesAsyncApi { /// Constructor for [SharedPreferencesAsyncApi]. The [binaryMessenger] named argument is /// available for dependency injection. If it is left null, the default /// BinaryMessenger will be used which routes to the host platform. - SharedPreferencesAsyncApi({BinaryMessenger? binaryMessenger}) - : __pigeon_binaryMessenger = binaryMessenger; - final BinaryMessenger? __pigeon_binaryMessenger; + SharedPreferencesAsyncApi( + {BinaryMessenger? binaryMessenger, String messageChannelSuffix = ''}) + : pigeonVar_binaryMessenger = binaryMessenger, + pigeonVar_messageChannelSuffix = + messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; + final BinaryMessenger? pigeonVar_binaryMessenger; + + static const MessageCodec pigeonChannelCodec = _PigeonCodec(); - static const MessageCodec pigeonChannelCodec = - _SharedPreferencesAsyncApiCodec(); + final String pigeonVar_messageChannelSuffix; /// Adds property to shared preferences data set of type bool. Future setBool( String key, bool value, SharedPreferencesPigeonOptions options) async { - const String __pigeon_channelName = - 'dev.flutter.pigeon.shared_preferences_android.SharedPreferencesAsyncApi.setBool'; - final BasicMessageChannel __pigeon_channel = + final String pigeonVar_channelName = + 'dev.flutter.pigeon.shared_preferences_android.SharedPreferencesAsyncApi.setBool$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( - __pigeon_channelName, + pigeonVar_channelName, pigeonChannelCodec, - binaryMessenger: __pigeon_binaryMessenger, + binaryMessenger: pigeonVar_binaryMessenger, ); - final List? __pigeon_replyList = await __pigeon_channel + final List? pigeonVar_replyList = await pigeonVar_channel .send([key, value, options]) as List?; - if (__pigeon_replyList == null) { - throw _createConnectionError(__pigeon_channelName); - } else if (__pigeon_replyList.length > 1) { + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { throw PlatformException( - code: __pigeon_replyList[0]! as String, - message: __pigeon_replyList[1] as String?, - details: __pigeon_replyList[2], + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], ); } else { return; @@ -102,23 +114,23 @@ class SharedPreferencesAsyncApi { /// Adds property to shared preferences data set of type String. Future setString( String key, String value, SharedPreferencesPigeonOptions options) async { - const String __pigeon_channelName = - 'dev.flutter.pigeon.shared_preferences_android.SharedPreferencesAsyncApi.setString'; - final BasicMessageChannel __pigeon_channel = + final String pigeonVar_channelName = + 'dev.flutter.pigeon.shared_preferences_android.SharedPreferencesAsyncApi.setString$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( - __pigeon_channelName, + pigeonVar_channelName, pigeonChannelCodec, - binaryMessenger: __pigeon_binaryMessenger, + binaryMessenger: pigeonVar_binaryMessenger, ); - final List? __pigeon_replyList = await __pigeon_channel + final List? pigeonVar_replyList = await pigeonVar_channel .send([key, value, options]) as List?; - if (__pigeon_replyList == null) { - throw _createConnectionError(__pigeon_channelName); - } else if (__pigeon_replyList.length > 1) { + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { throw PlatformException( - code: __pigeon_replyList[0]! as String, - message: __pigeon_replyList[1] as String?, - details: __pigeon_replyList[2], + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], ); } else { return; @@ -128,23 +140,23 @@ class SharedPreferencesAsyncApi { /// Adds property to shared preferences data set of type int. Future setInt( String key, int value, SharedPreferencesPigeonOptions options) async { - const String __pigeon_channelName = - 'dev.flutter.pigeon.shared_preferences_android.SharedPreferencesAsyncApi.setInt'; - final BasicMessageChannel __pigeon_channel = + final String pigeonVar_channelName = + 'dev.flutter.pigeon.shared_preferences_android.SharedPreferencesAsyncApi.setInt$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( - __pigeon_channelName, + pigeonVar_channelName, pigeonChannelCodec, - binaryMessenger: __pigeon_binaryMessenger, + binaryMessenger: pigeonVar_binaryMessenger, ); - final List? __pigeon_replyList = await __pigeon_channel + final List? pigeonVar_replyList = await pigeonVar_channel .send([key, value, options]) as List?; - if (__pigeon_replyList == null) { - throw _createConnectionError(__pigeon_channelName); - } else if (__pigeon_replyList.length > 1) { + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { throw PlatformException( - code: __pigeon_replyList[0]! as String, - message: __pigeon_replyList[1] as String?, - details: __pigeon_replyList[2], + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], ); } else { return; @@ -154,23 +166,23 @@ class SharedPreferencesAsyncApi { /// Adds property to shared preferences data set of type double. Future setDouble( String key, double value, SharedPreferencesPigeonOptions options) async { - const String __pigeon_channelName = - 'dev.flutter.pigeon.shared_preferences_android.SharedPreferencesAsyncApi.setDouble'; - final BasicMessageChannel __pigeon_channel = + final String pigeonVar_channelName = + 'dev.flutter.pigeon.shared_preferences_android.SharedPreferencesAsyncApi.setDouble$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( - __pigeon_channelName, + pigeonVar_channelName, pigeonChannelCodec, - binaryMessenger: __pigeon_binaryMessenger, + binaryMessenger: pigeonVar_binaryMessenger, ); - final List? __pigeon_replyList = await __pigeon_channel + final List? pigeonVar_replyList = await pigeonVar_channel .send([key, value, options]) as List?; - if (__pigeon_replyList == null) { - throw _createConnectionError(__pigeon_channelName); - } else if (__pigeon_replyList.length > 1) { + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { throw PlatformException( - code: __pigeon_replyList[0]! as String, - message: __pigeon_replyList[1] as String?, - details: __pigeon_replyList[2], + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], ); } else { return; @@ -178,25 +190,25 @@ class SharedPreferencesAsyncApi { } /// Adds property to shared preferences data set of type List. - Future setStringList(String key, List value, + Future setStringList(String key, List value, SharedPreferencesPigeonOptions options) async { - const String __pigeon_channelName = - 'dev.flutter.pigeon.shared_preferences_android.SharedPreferencesAsyncApi.setStringList'; - final BasicMessageChannel __pigeon_channel = + final String pigeonVar_channelName = + 'dev.flutter.pigeon.shared_preferences_android.SharedPreferencesAsyncApi.setStringList$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( - __pigeon_channelName, + pigeonVar_channelName, pigeonChannelCodec, - binaryMessenger: __pigeon_binaryMessenger, + binaryMessenger: pigeonVar_binaryMessenger, ); - final List? __pigeon_replyList = await __pigeon_channel + final List? pigeonVar_replyList = await pigeonVar_channel .send([key, value, options]) as List?; - if (__pigeon_replyList == null) { - throw _createConnectionError(__pigeon_channelName); - } else if (__pigeon_replyList.length > 1) { + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { throw PlatformException( - code: __pigeon_replyList[0]! as String, - message: __pigeon_replyList[1] as String?, - details: __pigeon_replyList[2], + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], ); } else { return; @@ -206,153 +218,153 @@ class SharedPreferencesAsyncApi { /// Gets individual String value stored with [key], if any. Future getString( String key, SharedPreferencesPigeonOptions options) async { - const String __pigeon_channelName = - 'dev.flutter.pigeon.shared_preferences_android.SharedPreferencesAsyncApi.getString'; - final BasicMessageChannel __pigeon_channel = + final String pigeonVar_channelName = + 'dev.flutter.pigeon.shared_preferences_android.SharedPreferencesAsyncApi.getString$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( - __pigeon_channelName, + pigeonVar_channelName, pigeonChannelCodec, - binaryMessenger: __pigeon_binaryMessenger, + binaryMessenger: pigeonVar_binaryMessenger, ); - final List? __pigeon_replyList = - await __pigeon_channel.send([key, options]) as List?; - if (__pigeon_replyList == null) { - throw _createConnectionError(__pigeon_channelName); - } else if (__pigeon_replyList.length > 1) { + final List? pigeonVar_replyList = + await pigeonVar_channel.send([key, options]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { throw PlatformException( - code: __pigeon_replyList[0]! as String, - message: __pigeon_replyList[1] as String?, - details: __pigeon_replyList[2], + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], ); } else { - return (__pigeon_replyList[0] as String?); + return (pigeonVar_replyList[0] as String?); } } /// Gets individual void value stored with [key], if any. Future getBool( String key, SharedPreferencesPigeonOptions options) async { - const String __pigeon_channelName = - 'dev.flutter.pigeon.shared_preferences_android.SharedPreferencesAsyncApi.getBool'; - final BasicMessageChannel __pigeon_channel = + final String pigeonVar_channelName = + 'dev.flutter.pigeon.shared_preferences_android.SharedPreferencesAsyncApi.getBool$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( - __pigeon_channelName, + pigeonVar_channelName, pigeonChannelCodec, - binaryMessenger: __pigeon_binaryMessenger, + binaryMessenger: pigeonVar_binaryMessenger, ); - final List? __pigeon_replyList = - await __pigeon_channel.send([key, options]) as List?; - if (__pigeon_replyList == null) { - throw _createConnectionError(__pigeon_channelName); - } else if (__pigeon_replyList.length > 1) { + final List? pigeonVar_replyList = + await pigeonVar_channel.send([key, options]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { throw PlatformException( - code: __pigeon_replyList[0]! as String, - message: __pigeon_replyList[1] as String?, - details: __pigeon_replyList[2], + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], ); } else { - return (__pigeon_replyList[0] as bool?); + return (pigeonVar_replyList[0] as bool?); } } /// Gets individual double value stored with [key], if any. Future getDouble( String key, SharedPreferencesPigeonOptions options) async { - const String __pigeon_channelName = - 'dev.flutter.pigeon.shared_preferences_android.SharedPreferencesAsyncApi.getDouble'; - final BasicMessageChannel __pigeon_channel = + final String pigeonVar_channelName = + 'dev.flutter.pigeon.shared_preferences_android.SharedPreferencesAsyncApi.getDouble$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( - __pigeon_channelName, + pigeonVar_channelName, pigeonChannelCodec, - binaryMessenger: __pigeon_binaryMessenger, + binaryMessenger: pigeonVar_binaryMessenger, ); - final List? __pigeon_replyList = - await __pigeon_channel.send([key, options]) as List?; - if (__pigeon_replyList == null) { - throw _createConnectionError(__pigeon_channelName); - } else if (__pigeon_replyList.length > 1) { + final List? pigeonVar_replyList = + await pigeonVar_channel.send([key, options]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { throw PlatformException( - code: __pigeon_replyList[0]! as String, - message: __pigeon_replyList[1] as String?, - details: __pigeon_replyList[2], + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], ); } else { - return (__pigeon_replyList[0] as double?); + return (pigeonVar_replyList[0] as double?); } } /// Gets individual int value stored with [key], if any. Future getInt( String key, SharedPreferencesPigeonOptions options) async { - const String __pigeon_channelName = - 'dev.flutter.pigeon.shared_preferences_android.SharedPreferencesAsyncApi.getInt'; - final BasicMessageChannel __pigeon_channel = + final String pigeonVar_channelName = + 'dev.flutter.pigeon.shared_preferences_android.SharedPreferencesAsyncApi.getInt$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( - __pigeon_channelName, + pigeonVar_channelName, pigeonChannelCodec, - binaryMessenger: __pigeon_binaryMessenger, + binaryMessenger: pigeonVar_binaryMessenger, ); - final List? __pigeon_replyList = - await __pigeon_channel.send([key, options]) as List?; - if (__pigeon_replyList == null) { - throw _createConnectionError(__pigeon_channelName); - } else if (__pigeon_replyList.length > 1) { + final List? pigeonVar_replyList = + await pigeonVar_channel.send([key, options]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { throw PlatformException( - code: __pigeon_replyList[0]! as String, - message: __pigeon_replyList[1] as String?, - details: __pigeon_replyList[2], + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], ); } else { - return (__pigeon_replyList[0] as int?); + return (pigeonVar_replyList[0] as int?); } } /// Gets individual List value stored with [key], if any. - Future?> getStringList( + Future?> getStringList( String key, SharedPreferencesPigeonOptions options) async { - const String __pigeon_channelName = - 'dev.flutter.pigeon.shared_preferences_android.SharedPreferencesAsyncApi.getStringList'; - final BasicMessageChannel __pigeon_channel = + final String pigeonVar_channelName = + 'dev.flutter.pigeon.shared_preferences_android.SharedPreferencesAsyncApi.getStringList$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( - __pigeon_channelName, + pigeonVar_channelName, pigeonChannelCodec, - binaryMessenger: __pigeon_binaryMessenger, + binaryMessenger: pigeonVar_binaryMessenger, ); - final List? __pigeon_replyList = - await __pigeon_channel.send([key, options]) as List?; - if (__pigeon_replyList == null) { - throw _createConnectionError(__pigeon_channelName); - } else if (__pigeon_replyList.length > 1) { + final List? pigeonVar_replyList = + await pigeonVar_channel.send([key, options]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { throw PlatformException( - code: __pigeon_replyList[0]! as String, - message: __pigeon_replyList[1] as String?, - details: __pigeon_replyList[2], + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], ); } else { - return (__pigeon_replyList[0] as List?)?.cast(); + return (pigeonVar_replyList[0] as List?)?.cast(); } } /// Removes all properties from shared preferences data set with matching prefix. Future clear( - List? allowList, SharedPreferencesPigeonOptions options) async { - const String __pigeon_channelName = - 'dev.flutter.pigeon.shared_preferences_android.SharedPreferencesAsyncApi.clear'; - final BasicMessageChannel __pigeon_channel = + List? allowList, SharedPreferencesPigeonOptions options) async { + final String pigeonVar_channelName = + 'dev.flutter.pigeon.shared_preferences_android.SharedPreferencesAsyncApi.clear$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( - __pigeon_channelName, + pigeonVar_channelName, pigeonChannelCodec, - binaryMessenger: __pigeon_binaryMessenger, + binaryMessenger: pigeonVar_binaryMessenger, ); - final List? __pigeon_replyList = await __pigeon_channel + final List? pigeonVar_replyList = await pigeonVar_channel .send([allowList, options]) as List?; - if (__pigeon_replyList == null) { - throw _createConnectionError(__pigeon_channelName); - } else if (__pigeon_replyList.length > 1) { + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { throw PlatformException( - code: __pigeon_replyList[0]! as String, - message: __pigeon_replyList[1] as String?, - details: __pigeon_replyList[2], + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], ); } else { return; @@ -360,65 +372,65 @@ class SharedPreferencesAsyncApi { } /// Gets all properties from shared preferences data set with matching prefix. - Future> getAll( - List? allowList, SharedPreferencesPigeonOptions options) async { - const String __pigeon_channelName = - 'dev.flutter.pigeon.shared_preferences_android.SharedPreferencesAsyncApi.getAll'; - final BasicMessageChannel __pigeon_channel = + Future> getAll( + List? allowList, SharedPreferencesPigeonOptions options) async { + final String pigeonVar_channelName = + 'dev.flutter.pigeon.shared_preferences_android.SharedPreferencesAsyncApi.getAll$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( - __pigeon_channelName, + pigeonVar_channelName, pigeonChannelCodec, - binaryMessenger: __pigeon_binaryMessenger, + binaryMessenger: pigeonVar_binaryMessenger, ); - final List? __pigeon_replyList = await __pigeon_channel + final List? pigeonVar_replyList = await pigeonVar_channel .send([allowList, options]) as List?; - if (__pigeon_replyList == null) { - throw _createConnectionError(__pigeon_channelName); - } else if (__pigeon_replyList.length > 1) { + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { throw PlatformException( - code: __pigeon_replyList[0]! as String, - message: __pigeon_replyList[1] as String?, - details: __pigeon_replyList[2], + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], ); - } else if (__pigeon_replyList[0] == null) { + } else if (pigeonVar_replyList[0] == null) { throw PlatformException( code: 'null-error', message: 'Host platform returned null value for non-null return value.', ); } else { - return (__pigeon_replyList[0] as Map?)! - .cast(); + return (pigeonVar_replyList[0] as Map?)! + .cast(); } } /// Gets all properties from shared preferences data set with matching prefix. - Future> getKeys( - List? allowList, SharedPreferencesPigeonOptions options) async { - const String __pigeon_channelName = - 'dev.flutter.pigeon.shared_preferences_android.SharedPreferencesAsyncApi.getKeys'; - final BasicMessageChannel __pigeon_channel = + Future> getKeys( + List? allowList, SharedPreferencesPigeonOptions options) async { + final String pigeonVar_channelName = + 'dev.flutter.pigeon.shared_preferences_android.SharedPreferencesAsyncApi.getKeys$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( - __pigeon_channelName, + pigeonVar_channelName, pigeonChannelCodec, - binaryMessenger: __pigeon_binaryMessenger, + binaryMessenger: pigeonVar_binaryMessenger, ); - final List? __pigeon_replyList = await __pigeon_channel + final List? pigeonVar_replyList = await pigeonVar_channel .send([allowList, options]) as List?; - if (__pigeon_replyList == null) { - throw _createConnectionError(__pigeon_channelName); - } else if (__pigeon_replyList.length > 1) { + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { throw PlatformException( - code: __pigeon_replyList[0]! as String, - message: __pigeon_replyList[1] as String?, - details: __pigeon_replyList[2], + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], ); - } else if (__pigeon_replyList[0] == null) { + } else if (pigeonVar_replyList[0] == null) { throw PlatformException( code: 'null-error', message: 'Host platform returned null value for non-null return value.', ); } else { - return (__pigeon_replyList[0] as List?)!.cast(); + return (pigeonVar_replyList[0] as List?)!.cast(); } } } diff --git a/packages/shared_preferences/shared_preferences_android/lib/src/shared_preferences_async_android.dart b/packages/shared_preferences/shared_preferences_android/lib/src/shared_preferences_async_android.dart index 7b3f1cb7b35..2b6dcd5bcaa 100644 --- a/packages/shared_preferences/shared_preferences_android/lib/src/shared_preferences_async_android.dart +++ b/packages/shared_preferences/shared_preferences_android/lib/src/shared_preferences_async_android.dart @@ -18,10 +18,16 @@ base class SharedPreferencesAsyncAndroid extends SharedPreferencesAsyncPlatform { /// Creates a new plugin implementation instance. SharedPreferencesAsyncAndroid({ - @visibleForTesting SharedPreferencesAsyncApi? api, - }) : _api = api ?? SharedPreferencesAsyncApi(); + @visibleForTesting SharedPreferencesAsyncApi? dataStoreApi, + @visibleForTesting SharedPreferencesAsyncApi? sharedPreferencesApi, + }) : _dataStoreApi = dataStoreApi ?? + SharedPreferencesAsyncApi(messageChannelSuffix: 'data_store'), + _sharedPreferencesApi = sharedPreferencesApi ?? + SharedPreferencesAsyncApi( + messageChannelSuffix: 'shared_preferences'); - final SharedPreferencesAsyncApi _api; + final SharedPreferencesAsyncApi _dataStoreApi; + final SharedPreferencesAsyncApi _sharedPreferencesApi; /// Registers this class as the default instance of [SharedPreferencesAsyncPlatform]. static void registerWith() { @@ -31,22 +37,34 @@ base class SharedPreferencesAsyncAndroid /// Returns a SharedPreferencesPigeonOptions for sending to platform. SharedPreferencesPigeonOptions _convertOptionsToPigeonOptions( SharedPreferencesOptions options) { + if (options is SharedPreferencesAsyncAndroidOptions) { + return SharedPreferencesPigeonOptions( + fileName: options.originalSharedPreferencesOptions?.fileName, + useDataStore: + options.backend == SharedPreferencesAndroidBackendLibrary.DataStore, + ); + } return SharedPreferencesPigeonOptions(); } + SharedPreferencesAsyncApi _getApiForBackend( + SharedPreferencesPigeonOptions options) { + return options.useDataStore ? _dataStoreApi : _sharedPreferencesApi; + } + @override Future> getKeys( GetPreferencesParameters parameters, SharedPreferencesOptions options, ) async { final PreferencesFilters filter = parameters.filter; - // TODO(tarrinneal): Remove cast once https://github.com/flutter/flutter/issues/97848 - // is fixed. In practice, the values will never be null, and the native implementation assumes that. - return (await _api.getKeys( + final SharedPreferencesPigeonOptions pigeonOptions = + _convertOptionsToPigeonOptions(options); + final SharedPreferencesAsyncApi api = _getApiForBackend(pigeonOptions); + return (await api.getKeys( filter.allowList?.toList(), - _convertOptionsToPigeonOptions(options), + pigeonOptions, )) - .cast() .toSet(); } @@ -60,8 +78,11 @@ base class SharedPreferencesAsyncAndroid throw ArgumentError( 'StorageError: This string cannot be stored as it clashes with special identifier prefixes'); } + final SharedPreferencesPigeonOptions pigeonOptions = + _convertOptionsToPigeonOptions(options); + final SharedPreferencesAsyncApi api = _getApiForBackend(pigeonOptions); - return _api.setString(key, value, _convertOptionsToPigeonOptions(options)); + return api.setString(key, value, pigeonOptions); } @override @@ -70,7 +91,10 @@ base class SharedPreferencesAsyncAndroid int value, SharedPreferencesOptions options, ) async { - return _api.setInt(key, value, _convertOptionsToPigeonOptions(options)); + final SharedPreferencesPigeonOptions pigeonOptions = + _convertOptionsToPigeonOptions(options); + final SharedPreferencesAsyncApi api = _getApiForBackend(pigeonOptions); + return api.setInt(key, value, pigeonOptions); } @override @@ -79,7 +103,10 @@ base class SharedPreferencesAsyncAndroid double value, SharedPreferencesOptions options, ) async { - return _api.setDouble(key, value, _convertOptionsToPigeonOptions(options)); + final SharedPreferencesPigeonOptions pigeonOptions = + _convertOptionsToPigeonOptions(options); + final SharedPreferencesAsyncApi api = _getApiForBackend(pigeonOptions); + return api.setDouble(key, value, pigeonOptions); } @override @@ -88,7 +115,10 @@ base class SharedPreferencesAsyncAndroid bool value, SharedPreferencesOptions options, ) async { - return _api.setBool(key, value, _convertOptionsToPigeonOptions(options)); + final SharedPreferencesPigeonOptions pigeonOptions = + _convertOptionsToPigeonOptions(options); + final SharedPreferencesAsyncApi api = _getApiForBackend(pigeonOptions); + return api.setBool(key, value, pigeonOptions); } @override @@ -97,8 +127,10 @@ base class SharedPreferencesAsyncAndroid List value, SharedPreferencesOptions options, ) async { - return _api.setStringList( - key, value, _convertOptionsToPigeonOptions(options)); + final SharedPreferencesPigeonOptions pigeonOptions = + _convertOptionsToPigeonOptions(options); + final SharedPreferencesAsyncApi api = _getApiForBackend(pigeonOptions); + return api.setStringList(key, value, pigeonOptions); } @override @@ -106,8 +138,11 @@ base class SharedPreferencesAsyncAndroid String key, SharedPreferencesOptions options, ) async { - return _convertKnownExceptions(() async => - _api.getString(key, _convertOptionsToPigeonOptions(options))); + final SharedPreferencesPigeonOptions pigeonOptions = + _convertOptionsToPigeonOptions(options); + final SharedPreferencesAsyncApi api = _getApiForBackend(pigeonOptions); + return _convertKnownExceptions( + () async => api.getString(key, pigeonOptions)); } @override @@ -115,8 +150,11 @@ base class SharedPreferencesAsyncAndroid String key, SharedPreferencesOptions options, ) async { + final SharedPreferencesPigeonOptions pigeonOptions = + _convertOptionsToPigeonOptions(options); + final SharedPreferencesAsyncApi api = _getApiForBackend(pigeonOptions); return _convertKnownExceptions( - () async => _api.getBool(key, _convertOptionsToPigeonOptions(options))); + () async => api.getBool(key, pigeonOptions)); } @override @@ -124,8 +162,11 @@ base class SharedPreferencesAsyncAndroid String key, SharedPreferencesOptions options, ) async { - return _convertKnownExceptions(() async => - _api.getDouble(key, _convertOptionsToPigeonOptions(options))); + final SharedPreferencesPigeonOptions pigeonOptions = + _convertOptionsToPigeonOptions(options); + final SharedPreferencesAsyncApi api = _getApiForBackend(pigeonOptions); + return _convertKnownExceptions( + () async => api.getDouble(key, pigeonOptions)); } @override @@ -133,8 +174,11 @@ base class SharedPreferencesAsyncAndroid String key, SharedPreferencesOptions options, ) async { + final SharedPreferencesPigeonOptions pigeonOptions = + _convertOptionsToPigeonOptions(options); + final SharedPreferencesAsyncApi api = _getApiForBackend(pigeonOptions); return _convertKnownExceptions( - () async => _api.getInt(key, _convertOptionsToPigeonOptions(options))); + () async => api.getInt(key, pigeonOptions)); } @override @@ -142,12 +186,13 @@ base class SharedPreferencesAsyncAndroid String key, SharedPreferencesOptions options, ) async { + final SharedPreferencesPigeonOptions pigeonOptions = + _convertOptionsToPigeonOptions(options); + final SharedPreferencesAsyncApi api = _getApiForBackend(pigeonOptions); // TODO(tarrinneal): Remove cast once https://github.com/flutter/flutter/issues/97848 // is fixed. In practice, the values will never be null, and the native implementation assumes that. return _convertKnownExceptions>(() async => - (await _api.getStringList(key, _convertOptionsToPigeonOptions(options))) - ?.cast() - .toList()); + (await api.getStringList(key, pigeonOptions))?.cast().toList()); } Future _convertKnownExceptions(Future Function() method) async { @@ -169,9 +214,12 @@ base class SharedPreferencesAsyncAndroid SharedPreferencesOptions options, ) async { final PreferencesFilters filter = parameters.filter; - return _api.clear( + final SharedPreferencesPigeonOptions pigeonOptions = + _convertOptionsToPigeonOptions(options); + final SharedPreferencesAsyncApi api = _getApiForBackend(pigeonOptions); + return api.clear( filter.allowList?.toList(), - _convertOptionsToPigeonOptions(options), + pigeonOptions, ); } @@ -181,16 +229,53 @@ base class SharedPreferencesAsyncAndroid SharedPreferencesOptions options, ) async { final PreferencesFilters filter = parameters.filter; - final Map data = await _api.getAll( + final SharedPreferencesPigeonOptions pigeonOptions = + _convertOptionsToPigeonOptions(options); + final SharedPreferencesAsyncApi api = _getApiForBackend(pigeonOptions); + final Map data = await api.getAll( filter.allowList?.toList(), - _convertOptionsToPigeonOptions(options), + pigeonOptions, ); return data.cast(); } } +/// Used to identify which Android library should be used on the backend of this call. +enum SharedPreferencesAndroidBackendLibrary { + /// Represents the newer DataStore Preferences library. + DataStore, + + /// Represents the older SharedPreferences library. + SharedPreferences, +} + /// Options for the Android specific SharedPreferences plugin. class SharedPreferencesAsyncAndroidOptions extends SharedPreferencesOptions { /// Constructor for SharedPreferencesAsyncAndroidOptions. - const SharedPreferencesAsyncAndroidOptions(); + const SharedPreferencesAsyncAndroidOptions({ + this.backend = SharedPreferencesAndroidBackendLibrary.DataStore, + this.originalSharedPreferencesOptions, + }); + + /// Which backend should be used for this method call. + final SharedPreferencesAndroidBackendLibrary backend; + + /// These options define how the `SharedPreferences` backend should behave. + /// + /// Any options in this field will be ignored unless the backend that is selected + /// is `SharedPreferences`. + final AndroidSharedPreferencesStoreOptions? originalSharedPreferencesOptions; +} + +/// Options necessary for defining the use of the original `SharedPreferences` +/// library. +/// +/// These options are only ever used with the original `SharedPreferences` and +/// have no purpose when using the default DataStore Preferences. +class AndroidSharedPreferencesStoreOptions { + /// Constructor for AndroidSharedPreferencesStoreOptions. + const AndroidSharedPreferencesStoreOptions({this.fileName}); + + /// The name of the file in which the preferences are stored. + final String? fileName; } diff --git a/packages/shared_preferences/shared_preferences_android/pigeons/messages_async.dart b/packages/shared_preferences/shared_preferences_android/pigeons/messages_async.dart index 5334cc042f5..9334123482b 100644 --- a/packages/shared_preferences/shared_preferences_android/pigeons/messages_async.dart +++ b/packages/shared_preferences/shared_preferences_android/pigeons/messages_async.dart @@ -17,9 +17,11 @@ import 'package:pigeon/pigeon.dart'; )) class SharedPreferencesPigeonOptions { SharedPreferencesPigeonOptions({ - this.fileKey, + this.fileName, + this.useDataStore = true, }); - String? fileKey; + String? fileName; + bool useDataStore; } @HostApi(dartHostTestHandler: 'TestSharedPreferencesAsyncApi') diff --git a/packages/shared_preferences/shared_preferences_android/pubspec.yaml b/packages/shared_preferences/shared_preferences_android/pubspec.yaml index c161df41512..594d763c6f8 100644 --- a/packages/shared_preferences/shared_preferences_android/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences_android/pubspec.yaml @@ -2,7 +2,7 @@ name: shared_preferences_android description: Android implementation of the shared_preferences plugin repository: https://github.com/flutter/packages/tree/main/packages/shared_preferences/shared_preferences_android issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+shared_preferences%22 -version: 2.3.4 +version: 2.4.0 environment: sdk: ^3.5.0 @@ -25,7 +25,7 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter - pigeon: ^16.0.4 + pigeon: ^22.6.0 topics: - persistence diff --git a/packages/shared_preferences/shared_preferences_android/test/shared_preferences_async_test.dart b/packages/shared_preferences/shared_preferences_android/test/shared_preferences_async_test.dart index 45ee340a7cf..fd2907e164b 100755 --- a/packages/shared_preferences/shared_preferences_android/test/shared_preferences_async_test.dart +++ b/packages/shared_preferences/shared_preferences_android/test/shared_preferences_async_test.dart @@ -2,6 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// ignore_for_file: non_constant_identifier_names + +import 'package:flutter/src/services/binary_messenger.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:shared_preferences_android/shared_preferences_android.dart'; import 'package:shared_preferences_android/src/messages_async.g.dart'; @@ -22,185 +25,216 @@ void main() { const double testDouble = 3.14159; const List testList = ['foo', 'bar']; - const SharedPreferencesAsyncAndroidOptions emptyOptions = - SharedPreferencesAsyncAndroidOptions(); - - SharedPreferencesAsyncAndroid getPreferences() { + SharedPreferencesAsyncAndroid getPreferences(bool useDataStore) { final _FakeSharedPreferencesApi api = _FakeSharedPreferencesApi(); final SharedPreferencesAsyncAndroid preferences = - SharedPreferencesAsyncAndroid(api: api); + SharedPreferencesAsyncAndroid( + dataStoreApi: api, + sharedPreferencesApi: api, + ); return preferences; } - test('set and get String', () async { - final SharedPreferencesAsyncAndroid preferences = getPreferences(); - - await preferences.setString(stringKey, testString, emptyOptions); - expect(await preferences.getString(stringKey, emptyOptions), testString); - }); - - test('set and get bool', () async { - final SharedPreferencesAsyncAndroid preferences = getPreferences(); - - await preferences.setBool(boolKey, testBool, emptyOptions); - expect(await preferences.getBool(boolKey, emptyOptions), testBool); - }); - - test('set and get int', () async { - final SharedPreferencesAsyncAndroid preferences = getPreferences(); - - await preferences.setInt(intKey, testInt, emptyOptions); - expect(await preferences.getInt(intKey, emptyOptions), testInt); - }); - - test('set and get double', () async { - final SharedPreferencesAsyncAndroid preferences = getPreferences(); - - await preferences.setDouble(doubleKey, testDouble, emptyOptions); - expect(await preferences.getDouble(doubleKey, emptyOptions), testDouble); - }); - - test('set and get StringList', () async { - final SharedPreferencesAsyncAndroid preferences = getPreferences(); + void runTests(bool useDataStore) { + final String backend = useDataStore ? 'DataStore' : 'SharedPreferences'; - await preferences.setStringList(listKey, testList, emptyOptions); - expect(await preferences.getStringList(listKey, emptyOptions), testList); - }); - - test('getPreferences', () async { - final SharedPreferencesAsyncAndroid preferences = getPreferences(); - await Future.wait(>[ - preferences.setString(stringKey, testString, emptyOptions), - preferences.setBool(boolKey, testBool, emptyOptions), - preferences.setInt(intKey, testInt, emptyOptions), - preferences.setDouble(doubleKey, testDouble, emptyOptions), - preferences.setStringList(listKey, testList, emptyOptions) - ]); + final SharedPreferencesAsyncAndroidOptions emptyOptions = + SharedPreferencesAsyncAndroidOptions( + backend: useDataStore + ? SharedPreferencesAndroidBackendLibrary.DataStore + : SharedPreferencesAndroidBackendLibrary.SharedPreferences, + ); - final Map gotAll = await preferences.getPreferences( + test('set and get String with $backend', () async { + final SharedPreferencesAsyncAndroid preferences = + getPreferences(useDataStore); + + await preferences.setString(stringKey, testString, emptyOptions); + expect(await preferences.getString(stringKey, emptyOptions), testString); + }); + + test('set and get bool with $backend', () async { + final SharedPreferencesAsyncAndroid preferences = + getPreferences(useDataStore); + + await preferences.setBool(boolKey, testBool, emptyOptions); + expect(await preferences.getBool(boolKey, emptyOptions), testBool); + }); + + test('set and get int with $backend', () async { + final SharedPreferencesAsyncAndroid preferences = + getPreferences(useDataStore); + + await preferences.setInt(intKey, testInt, emptyOptions); + expect(await preferences.getInt(intKey, emptyOptions), testInt); + }); + + test('set and get double with $backend', () async { + final SharedPreferencesAsyncAndroid preferences = + getPreferences(useDataStore); + + await preferences.setDouble(doubleKey, testDouble, emptyOptions); + expect(await preferences.getDouble(doubleKey, emptyOptions), testDouble); + }); + + test('set and get StringList with $backend', () async { + final SharedPreferencesAsyncAndroid preferences = + getPreferences(useDataStore); + + await preferences.setStringList(listKey, testList, emptyOptions); + expect(await preferences.getStringList(listKey, emptyOptions), testList); + }); + + test('getPreferences with $backend', () async { + final SharedPreferencesAsyncAndroid preferences = + getPreferences(useDataStore); + await Future.wait(>[ + preferences.setString(stringKey, testString, emptyOptions), + preferences.setBool(boolKey, testBool, emptyOptions), + preferences.setInt(intKey, testInt, emptyOptions), + preferences.setDouble(doubleKey, testDouble, emptyOptions), + preferences.setStringList(listKey, testList, emptyOptions) + ]); + + final Map gotAll = await preferences.getPreferences( + const GetPreferencesParameters(filter: PreferencesFilters()), + emptyOptions); + + expect(gotAll.length, 5); + expect(gotAll[stringKey], testString); + expect(gotAll[boolKey], testBool); + expect(gotAll[intKey], testInt); + expect(gotAll[doubleKey], testDouble); + expect(gotAll[listKey], testList); + }); + + test('getPreferences with filter with $backend', () async { + final SharedPreferencesAsyncAndroid preferences = + getPreferences(useDataStore); + await Future.wait(>[ + preferences.setString(stringKey, testString, emptyOptions), + preferences.setBool(boolKey, testBool, emptyOptions), + preferences.setInt(intKey, testInt, emptyOptions), + preferences.setDouble(doubleKey, testDouble, emptyOptions), + preferences.setStringList(listKey, testList, emptyOptions) + ]); + + final Map gotAll = await preferences.getPreferences( + const GetPreferencesParameters( + filter: + PreferencesFilters(allowList: {stringKey, boolKey})), + emptyOptions); + + expect(gotAll.length, 2); + expect(gotAll[stringKey], testString); + expect(gotAll[boolKey], testBool); + }); + + test('getKeys with $backend', () async { + final SharedPreferencesAsyncAndroid preferences = + getPreferences(useDataStore); + await Future.wait(>[ + preferences.setString(stringKey, testString, emptyOptions), + preferences.setBool(boolKey, testBool, emptyOptions), + preferences.setInt(intKey, testInt, emptyOptions), + preferences.setDouble(doubleKey, testDouble, emptyOptions), + preferences.setStringList(listKey, testList, emptyOptions) + ]); + + final Set keys = await preferences.getKeys( const GetPreferencesParameters(filter: PreferencesFilters()), - emptyOptions); - - expect(gotAll.length, 5); - expect(gotAll[stringKey], testString); - expect(gotAll[boolKey], testBool); - expect(gotAll[intKey], testInt); - expect(gotAll[doubleKey], testDouble); - expect(gotAll[listKey], testList); - }); - - test('getPreferences with filter', () async { - final SharedPreferencesAsyncAndroid preferences = getPreferences(); - await Future.wait(>[ - preferences.setString(stringKey, testString, emptyOptions), - preferences.setBool(boolKey, testBool, emptyOptions), - preferences.setInt(intKey, testInt, emptyOptions), - preferences.setDouble(doubleKey, testDouble, emptyOptions), - preferences.setStringList(listKey, testList, emptyOptions) - ]); - - final Map gotAll = await preferences.getPreferences( + emptyOptions, + ); + + expect(keys.length, 5); + expect(keys, contains(stringKey)); + expect(keys, contains(boolKey)); + expect(keys, contains(intKey)); + expect(keys, contains(doubleKey)); + expect(keys, contains(listKey)); + }); + + test('getKeys with filter with $backend', () async { + final SharedPreferencesAsyncAndroid preferences = + getPreferences(useDataStore); + await Future.wait(>[ + preferences.setString(stringKey, testString, emptyOptions), + preferences.setBool(boolKey, testBool, emptyOptions), + preferences.setInt(intKey, testInt, emptyOptions), + preferences.setDouble(doubleKey, testDouble, emptyOptions), + preferences.setStringList(listKey, testList, emptyOptions) + ]); + + final Set keys = await preferences.getKeys( const GetPreferencesParameters( - filter: - PreferencesFilters(allowList: {stringKey, boolKey})), - emptyOptions); - - expect(gotAll.length, 2); - expect(gotAll[stringKey], testString); - expect(gotAll[boolKey], testBool); - }); - - test('getKeys', () async { - final SharedPreferencesAsyncAndroid preferences = getPreferences(); - await Future.wait(>[ - preferences.setString(stringKey, testString, emptyOptions), - preferences.setBool(boolKey, testBool, emptyOptions), - preferences.setInt(intKey, testInt, emptyOptions), - preferences.setDouble(doubleKey, testDouble, emptyOptions), - preferences.setStringList(listKey, testList, emptyOptions) - ]); - - final Set keys = await preferences.getKeys( - const GetPreferencesParameters(filter: PreferencesFilters()), - emptyOptions, - ); - - expect(keys.length, 5); - expect(keys, contains(stringKey)); - expect(keys, contains(boolKey)); - expect(keys, contains(intKey)); - expect(keys, contains(doubleKey)); - expect(keys, contains(listKey)); - }); - - test('getKeys with filter', () async { - final SharedPreferencesAsyncAndroid preferences = getPreferences(); - await Future.wait(>[ - preferences.setString(stringKey, testString, emptyOptions), - preferences.setBool(boolKey, testBool, emptyOptions), - preferences.setInt(intKey, testInt, emptyOptions), - preferences.setDouble(doubleKey, testDouble, emptyOptions), - preferences.setStringList(listKey, testList, emptyOptions) - ]); - - final Set keys = await preferences.getKeys( - const GetPreferencesParameters( - filter: PreferencesFilters(allowList: {stringKey, boolKey}), - ), - emptyOptions, - ); + filter: PreferencesFilters(allowList: {stringKey, boolKey}), + ), + emptyOptions, + ); + + expect(keys.length, 2); + expect(keys, contains(stringKey)); + expect(keys, contains(boolKey)); + }); + + test('clear with $backend', () async { + final SharedPreferencesAsyncAndroid preferences = + getPreferences(useDataStore); + await Future.wait(>[ + preferences.setString(stringKey, testString, emptyOptions), + preferences.setBool(boolKey, testBool, emptyOptions), + preferences.setInt(intKey, testInt, emptyOptions), + preferences.setDouble(doubleKey, testDouble, emptyOptions), + preferences.setStringList(listKey, testList, emptyOptions) + ]); + await preferences.clear( + const ClearPreferencesParameters(filter: PreferencesFilters()), + emptyOptions); + expect(await preferences.getString(stringKey, emptyOptions), null); + expect(await preferences.getBool(boolKey, emptyOptions), null); + expect(await preferences.getInt(intKey, emptyOptions), null); + expect(await preferences.getDouble(doubleKey, emptyOptions), null); + expect(await preferences.getStringList(listKey, emptyOptions), null); + }); + + test('clear with filter with $backend', () async { + final SharedPreferencesAsyncAndroid preferences = + getPreferences(useDataStore); + await Future.wait(>[ + preferences.setString(stringKey, testString, emptyOptions), + preferences.setBool(boolKey, testBool, emptyOptions), + preferences.setInt(intKey, testInt, emptyOptions), + preferences.setDouble(doubleKey, testDouble, emptyOptions), + preferences.setStringList(listKey, testList, emptyOptions) + ]); + await preferences.clear( + const ClearPreferencesParameters( + filter: PreferencesFilters(allowList: {stringKey, boolKey}), + ), + emptyOptions, + ); + expect(await preferences.getString(stringKey, emptyOptions), null); + expect(await preferences.getBool(boolKey, emptyOptions), null); + expect(await preferences.getInt(intKey, emptyOptions), testInt); + expect(await preferences.getDouble(doubleKey, emptyOptions), testDouble); + expect(await preferences.getStringList(listKey, emptyOptions), testList); + }); + } - expect(keys.length, 2); - expect(keys, contains(stringKey)); - expect(keys, contains(boolKey)); - }); - - test('clear', () async { - final SharedPreferencesAsyncAndroid preferences = getPreferences(); - await Future.wait(>[ - preferences.setString(stringKey, testString, emptyOptions), - preferences.setBool(boolKey, testBool, emptyOptions), - preferences.setInt(intKey, testInt, emptyOptions), - preferences.setDouble(doubleKey, testDouble, emptyOptions), - preferences.setStringList(listKey, testList, emptyOptions) - ]); - await preferences.clear( - const ClearPreferencesParameters(filter: PreferencesFilters()), - emptyOptions); - expect(await preferences.getString(stringKey, emptyOptions), null); - expect(await preferences.getBool(boolKey, emptyOptions), null); - expect(await preferences.getInt(intKey, emptyOptions), null); - expect(await preferences.getDouble(doubleKey, emptyOptions), null); - expect(await preferences.getStringList(listKey, emptyOptions), null); - }); - - test('clear with filter', () async { - final SharedPreferencesAsyncAndroid preferences = getPreferences(); - await Future.wait(>[ - preferences.setString(stringKey, testString, emptyOptions), - preferences.setBool(boolKey, testBool, emptyOptions), - preferences.setInt(intKey, testInt, emptyOptions), - preferences.setDouble(doubleKey, testDouble, emptyOptions), - preferences.setStringList(listKey, testList, emptyOptions) - ]); - await preferences.clear( - const ClearPreferencesParameters( - filter: PreferencesFilters(allowList: {stringKey, boolKey}), - ), - emptyOptions, - ); - expect(await preferences.getString(stringKey, emptyOptions), null); - expect(await preferences.getBool(boolKey, emptyOptions), null); - expect(await preferences.getInt(intKey, emptyOptions), testInt); - expect(await preferences.getDouble(doubleKey, emptyOptions), testDouble); - expect(await preferences.getStringList(listKey, emptyOptions), testList); - }); + runTests(true); + runTests(false); } class _FakeSharedPreferencesApi implements SharedPreferencesAsyncApi { final Map items = {}; + @override + BinaryMessenger? get pigeonVar_binaryMessenger => throw UnimplementedError(); + + @override + String get pigeonVar_messageChannelSuffix => throw UnimplementedError(); + @override Future clear( List? allowList, SharedPreferencesPigeonOptions options) async { @@ -214,7 +248,7 @@ class _FakeSharedPreferencesApi implements SharedPreferencesAsyncApi { } @override - Future> getAll( + Future> getAll( List? allowList, SharedPreferencesPigeonOptions options) async { final Map filteredItems = {...items}; if (allowList != null) { @@ -242,7 +276,7 @@ class _FakeSharedPreferencesApi implements SharedPreferencesAsyncApi { } @override - Future> getKeys( + Future> getKeys( List? allowList, SharedPreferencesPigeonOptions options) async { final List filteredItems = items.keys.toList(); if (allowList != null) { @@ -258,7 +292,7 @@ class _FakeSharedPreferencesApi implements SharedPreferencesAsyncApi { } @override - Future?> getStringList( + Future?> getStringList( String key, SharedPreferencesPigeonOptions options) async { return items[key] as List?; } diff --git a/packages/shared_preferences/shared_preferences_foundation/CHANGELOG.md b/packages/shared_preferences/shared_preferences_foundation/CHANGELOG.md index 6d2bdd8ab8a..6af9743b2e0 100644 --- a/packages/shared_preferences/shared_preferences_foundation/CHANGELOG.md +++ b/packages/shared_preferences/shared_preferences_foundation/CHANGELOG.md @@ -1,5 +1,6 @@ -## NEXT +## 2.5.4 +* Updates Pigeon to fix lint error. * Updates minimum supported SDK version to Flutter 3.22/Dart 3.4. ## 2.5.3 diff --git a/packages/shared_preferences/shared_preferences_foundation/darwin/shared_preferences_foundation/Sources/shared_preferences_foundation/messages.g.swift b/packages/shared_preferences/shared_preferences_foundation/darwin/shared_preferences_foundation/Sources/shared_preferences_foundation/messages.g.swift index 275de0921d5..665ea2e5ed6 100644 --- a/packages/shared_preferences/shared_preferences_foundation/darwin/shared_preferences_foundation/Sources/shared_preferences_foundation/messages.g.swift +++ b/packages/shared_preferences/shared_preferences_foundation/darwin/shared_preferences_foundation/Sources/shared_preferences_foundation/messages.g.swift @@ -86,7 +86,7 @@ struct SharedPreferencesPigeonOptions { } } -private class messagesPigeonCodecReader: FlutterStandardReader { +private class MessagesPigeonCodecReader: FlutterStandardReader { override func readValue(ofType type: UInt8) -> Any? { switch type { case 129: @@ -97,7 +97,7 @@ private class messagesPigeonCodecReader: FlutterStandardReader { } } -private class messagesPigeonCodecWriter: FlutterStandardWriter { +private class MessagesPigeonCodecWriter: FlutterStandardWriter { override func writeValue(_ value: Any) { if let value = value as? SharedPreferencesPigeonOptions { super.writeByte(129) @@ -108,18 +108,18 @@ private class messagesPigeonCodecWriter: FlutterStandardWriter { } } -private class messagesPigeonCodecReaderWriter: FlutterStandardReaderWriter { +private class MessagesPigeonCodecReaderWriter: FlutterStandardReaderWriter { override func reader(with data: Data) -> FlutterStandardReader { - return messagesPigeonCodecReader(data: data) + return MessagesPigeonCodecReader(data: data) } override func writer(with data: NSMutableData) -> FlutterStandardWriter { - return messagesPigeonCodecWriter(data: data) + return MessagesPigeonCodecWriter(data: data) } } -class messagesPigeonCodec: FlutterStandardMessageCodec, @unchecked Sendable { - static let shared = messagesPigeonCodec(readerWriter: messagesPigeonCodecReaderWriter()) +class MessagesPigeonCodec: FlutterStandardMessageCodec, @unchecked Sendable { + static let shared = MessagesPigeonCodec(readerWriter: MessagesPigeonCodecReaderWriter()) } /// Generated protocol from Pigeon that represents a handler of messages from Flutter. @@ -134,7 +134,7 @@ protocol LegacyUserDefaultsApi { /// Generated setup class from Pigeon to handle messages through the `binaryMessenger`. class LegacyUserDefaultsApiSetup { - static var codec: FlutterStandardMessageCodec { messagesPigeonCodec.shared } + static var codec: FlutterStandardMessageCodec { MessagesPigeonCodec.shared } /// Sets up an instance of `LegacyUserDefaultsApi` to handle messages through the `binaryMessenger`. static func setUp( binaryMessenger: FlutterBinaryMessenger, api: LegacyUserDefaultsApi?, @@ -272,7 +272,7 @@ protocol UserDefaultsApi { /// Generated setup class from Pigeon to handle messages through the `binaryMessenger`. class UserDefaultsApiSetup { - static var codec: FlutterStandardMessageCodec { messagesPigeonCodec.shared } + static var codec: FlutterStandardMessageCodec { MessagesPigeonCodec.shared } /// Sets up an instance of `UserDefaultsApi` to handle messages through the `binaryMessenger`. static func setUp( binaryMessenger: FlutterBinaryMessenger, api: UserDefaultsApi?, diff --git a/packages/shared_preferences/shared_preferences_foundation/pubspec.yaml b/packages/shared_preferences/shared_preferences_foundation/pubspec.yaml index 300fc87fe3b..915f1c5707a 100644 --- a/packages/shared_preferences/shared_preferences_foundation/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences_foundation/pubspec.yaml @@ -2,7 +2,7 @@ name: shared_preferences_foundation description: iOS and macOS implementation of the shared_preferences plugin. repository: https://github.com/flutter/packages/tree/main/packages/shared_preferences/shared_preferences_foundation issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+shared_preferences%22 -version: 2.5.3 +version: 2.5.4 environment: sdk: ^3.4.0