Skip to main content

shared_preferences

PackageKindProvides the roleNeedsChoose with
smf_shared_preferencesinfrastructurePreferencesnothing-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.

warning

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 AppPreferences interface, which has a read and a write for a String, a bool, an int, a double and a List<String>, such as getBool(key) and setBool(key, value), and remove(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 that initPreferences() 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