shared_preferences
| Package | Kind | Provides the role | Needs | Choose with |
|---|---|---|---|---|
smf_shared_preferences | infrastructure | Preferences | nothing | -m shared_preferences |
shared_preferences lets the app remember its settings between its launches, such as the theme mode or a hint that the user dismissed. It keeps them with the shared_preferences package.
Nothing in the preferences is encrypted, and a backup of the device carries them. Never store a token, a password, an API key or an encryption key there. A secret belongs in the secure storage of the platform, the Keychain on iOS and the Keystore on Android.
What it adds to the app
The module adds shared_preferences: ^2.5.5 to the dependencies, and lib/core/preferences/shared_app_preferences.dart with the preferences on SharedPreferencesWithCache. The package keeps the values in DataStore on Android and in UserDefaults on iOS, and reads them into memory when the app starts.
Whichever module provides it, the preferences role adds lib/core/preferences/app_preferences.dart with:
- the
AppPreferencesinterface, which has a read and a write for aString, abool, anint, adoubleand aList<String>, such asgetBool(key)andsetBool(key, value), andremove(key); initPreferences(), which opens the preferences and gives them to the code of the app that keeps settings there.bootstrap()awaits it in its platform phase, before the services of the app and before the first frame;createAppPreferences(), which returns the preferences thatinitPreferences()opened.
Preferences and settings shows how the code of the app remembers a setting with them.
Reads and writes
A read is synchronous and never throws. It returns null when its key has no value of the type it asks for. This module reads a number only as the type that it was saved as: getDouble returns null for a key with an int, and getInt returns null for a key with a double, even a whole number such as 18.0. So save and read a setting as one type.
A write completes once the value is saved. The preferences keep a copy of a list they are given, and a read returns a copy of it, so a later change of either list changes nothing that is saved.
A write puts its value into memory before it saves it. If the platform refuses the save, the write fails. The reads of this run return the value all the same. The next launch reads what was saved before the write, or nothing if the key had no value. Android refuses a text that starts with the prefix that the shared_preferences package marks a list with.
Getting the preferences
bootstrap() opens the preferences. The code of a module gets them right then, through a function that the module gives the preferences role. With a module of dependency injection, the role also registers the preferences in the container as a lazy singleton. A service then takes them as a dependency, and a feature takes them with resolve in its composition file.
If the preferences cannot be opened, initPreferences() fails, and bootstrap() with it.
In tests
A test that runs bootstrap() first puts the preferences of the package into memory, or opening them throws a StateError:
SharedPreferencesAsyncPlatform.instance =
InMemorySharedPreferencesAsync.empty();
Both names come from the package shared_preferences_platform_interface, which the test needs as a dev dependency, each from a library of its own:
import 'package:shared_preferences_platform_interface/in_memory_shared_preferences_async.dart';
import 'package:shared_preferences_platform_interface/shared_preferences_async_platform_interface.dart';
The guide for coding agents of the app tells agents to set this instance too, in its section on the preferences. Preferences and settings has a whole test.
Whichever module provides the preferences, a value of each type is read back as it was saved, a removed key has no value, and the next start reads what was saved. SMF's CI checks this in running apps with the role, and on devices with the real platform side of this module; see Contributing.
Choosing it
smf create asks which module provides the preferences of the app, and offers None as well. When a module you chose needs preferences, as material_theme and gen_l10n do, and shared_preferences is the only module that provides them, smf create adds it by itself. To choose it without the question:
smf create my_app -m shared_preferences