4.2 Системы хранения данных: библиотеки для работы с парами ключ — значение

В предыдущем параграфе мы начали большую тему, посвящённую обзору библиотек для работы с данными разных типов — успели поговорить о файлах. В этом параграфе поговорим про работу с парами ключ — значения.

Простейшие хранилища формата ключ — значение (Key — Value) не являются подвидами каких-либо баз данных (SQL/NoSQL) и представляют собой легковесное и простое решение для специфических задач, таких как кэширование и хранение настроек.

Они не предназначены для обработки больших объёмов данных или сложных операций.

Мы рассмотрим три библиотеки:

  • shared_preferences;

  • flutter_secure_storage;

  • get_storage.

Библиотека shared_preferences

shared_preferences — это библиотека, позволяющая сохранять примитивные данные в формате ключ — значение (key — value) на устройстве пользователя и доступная на всех платформах, в том числе в вебе. Она предоставляет удобный способ хранения настроек приложения и иных простых данных — сохраняется/читается обыкновенный текстовый файл на iOS в формате .plist (NSUserDefaults) и на Android в формате .xml (SharedPreferences).

Вы уже могли видеть пример пользования данной библиотекой ранее. Сейчас разберём её возможности и методы подробнее.

Использование

Для начала работы с shared_preferences необходимо импортировать соответствующий пакет:

1import 'package:shared_preferences/shared_preferences.dart';

После этого с помощью метода getInstance() вы можете получить инстанс SharedPreferences. Он представляет собой синглтон:

1void main() async {
2  final sharedPrefs = await SharedPreferences.getInstance();
3  // Далее вы можете использовать sharedPrefs для чтения и записи данных
4}

Когда мы достаём инстанс, то все данные выгружаются в оперативную память. Поэтому вы можете синхронно доставать из неё данные — это будет быстрая операция. При этом запись данных — это асинхронная дисковая операция. Таким образом, одновременно происходит запись и в оперативную память, и в файл.

Функции записи возвращают булево значение. Оно сигнализирует, удалась запись или нет. Почти всегда возвращается true, но в теории может вернуться и false, хотя такое маловероятно. Например, это может произойти на iOS, когда интерфейс NSUserDefault записывает в кэш и синхронизируется не сразу. В таких случаях нужно быть готовыми к тому, что данные не запишутся, и сделать соответствующую запись в логах либо попробовать повторить попытку записи.

Вот как выглядит файл с настройками SharedPreferencesв системе Android. Найти его можно по следующему пути: /data/data/<application_ID>/shared_prefs/FlutterSharedPreferences.xml.

1<?xml version='1.0' encoding='utf-8' standalone='yes' ?> 
2<map> 
3 <string name="flutter.user_nickname">yandex_student</string>
4 <boolean name="flutter.is_night_theme" value="true" />
5 <long name="flutter.age" value="20" />
6</map>

Теперь поговорим о методах инстанса SharedPreferences.

Чтение данных

shared_preferences предоставляет методы для синхронного чтения различных типов данных:

  • get(String key) — синхронное чтение данных по ключу.

  • getBool(String key) — синхронное чтение булевых данных по ключу.

  • getInt(String key) — синхронное чтение целочисленных данных по ключу.

  • getDouble(String key) — синхронное чтение числовых данных с плавающей точкой по ключу.

  • getString(String key) — синхронное чтение строковых данных по ключу.

  • containsKey(String key) — проверяет наличие ключа.

  • getStringList(String key) — синхронное чтение списка строк по ключу.

Пример считывания строки:

1final username = sharedPrefs.getString('username');

Запись данных

Для записи данных в shared_preferences используйте асинхронные методы:

  • setBool(String key, bool value) — асинхронная запись булевых данных по ключу.

  • setInt(String key, int value) — асинхронная запись целочисленных данных по ключу.

  • setDouble(String key, double value) — асинхронная запись числовых данных с плавающей точкой по ключу.

  • setString(String key, String value) — асинхронная запись строковых данных по ключу.

  • setStringList(String key, List<String> value) — асинхронная запись списка строк по ключу.

Пример записи строки:

1await sharedPrefs.setString('username', 'john_doe');

Удаление данных

Вы также можете удалить данные, связанные с определённым ключом, с помощью метода remove(String key):

1await sharedPrefs.remove('username');

Где хранится файл с настройками shared_preferences

Это зависит от платформы:

  • Android — данные хранятся в файле XML в папке SharedPreferences.

  • iOS — данные хранятся с использованием класса NSUserDefault.

  • macOS — данные также хранятся с использованием NSUserDefault.

  • Linux — данные хранятся в папке .config в XDG_DATA_HOME.

  • Windows — данные хранятся в Roaming AppData директории.

  • Web — данные хранятся в кэше браузера.

Преимущества и недостатки shared_preferences

Преимущества

Недостатки

  • Удобно хранить настройки приложения в виде примитивных данных.

  • Синхронное чтение из кэша в памяти лишний раз не выполняет дисковую операцию и не ходит в платформенный код.

  • Простой и интуитивно понятный API.

  • Разные реализации для Android, iOS и других платформ, что требует обращения к платформенному коду.

  • Не гарантируется немедленная запись на диск после успешного выполнения метода (хотя теоретическая вероятность стремится к нулю).

  • Нельзя сохранять сложные объекты «из коробки».

  • Не самое оптимальное решение для сохранения большого количества данных.

Библиотека shared_preferences — это хороший инструмент для хранения простых данных во Flutter. Она предоставляет простой и удобный способ управления настройками приложения и другими данными на стороне клиента. Несмотря на некоторые ограничения, она остаётся одним из популярных выборов для хранения ключевых данных.

Библиотека flutter_secure_storage

flutter_secure_storage — это библиотека для безопасного хранения конфиденциальных данных в приложениях Flutter. Она поддерживает все платформы, что делает её отличным выбором для хранения и управления чувствительными данными.

Основные возможности

  • Поддержка Android и iOS. На Android библиотека использует систему управления ключами Keystore с RSA шифрованием или Android EncryptedSharedPreferences (расширение над SharedPreferences с поддержкой шифрования) в зависимости от настроек. На iOS данные хранятся в Keychain — криптоконтейнере для хранения чувствительной информации, включая ключи, учётные данные, сертификаты.

  • Простой API. Вы можете легко записывать, читать и удалять данные из flutter_secure_storage. Ниже приведён пример сохранения и чтения значения в защищённом хранилище.

1import 'package:flutter_secure_storage/flutter_secure_storage.dart';
2
3const storage = FlutterSecureStorage();
4await storage.write(key: 'key', value: 'value');
5final value = await storage.read(key: 'key');
6await storage.delete(key: 'key');

Для более продвинутого хранения данных и их обмена между разными приложениями одного разработчика на iOS существует технология App Group, которую также можно конфигурировать для использования с flutter_secure_storage.

AppGroups

AppGroups — это функциональность, специфичная для iOS, которая позволяет приложениям одного разработчика совместно использовать данные. Это особенно полезно, когда несколько ваших приложений нуждаются в доступе к общим данным — например, для авторизации пользователя.

Пример ниже позволяет разделять данные между приложениями группы group.example. Это означает, что другое приложение, настроенное на использование этой же группы, сможет получить доступ к хранимым данным по ключу key.

1import 'package:flutter_secure_storage/flutter_secure_storage.dart';
2
3final storage = FlutterSecureStorage();
4await storage.write(
5  key: 'key',
6  value: 'value',
7  iOptions: IOSOptions(groupId: 'group.example'),
8);

Для использования AppGroups вам необходим аккаунт разработчика и настройка разрешений в консоли разработчика Apple. Подробнее об этом можно почитать в разделе Configuring App Groups на официальном сайте разработчика Apple.

Преимущества и недостатки flutter_secure_storage

Преимущества

Недостатки

  • Простой и интуитивно понятный API.

  • Поддержка всех платформ, в том числе веб.

  • Подходит только для хранения простых типов данных.

Библиотека отлично подходит для приложений, требующих безопасного хранения таких данных, как токены аутентификации, пароли и другие чувствительные данные.

Библиотека get_storage

get_storage — это ещё одна библиотека для Flutter, предназначенная для хранения простых данных в памяти устройства. Она предоставляет простой и интуитивно понятный интерфейс для работы с хранилищем, позволяя сохранять и получать данные без лишних сложностей.

Основные возможности

Простой интерфейс. Библиотека get_storage предоставляет простые методы для записи и чтения данных.

1import 'package:get_storage/get_storage.dart';
2
3...
4
5main() {
6 await GetStorage.init();
7 ...
8}
9
10...
11
12final box = GetStorage();
13box.write('key1', 'value');
14box.write('key2', 3);
15final value = box.read('key1');

Запись и чтение. Этот плагин оптимизирован для быстрого доступа к данным, что делает его подходящим для хранения часто используемых значений.

Поддержка разных типов данных. Вы можете сохранять данные различных типов, таких как строки, числа, булевы значения и объекты, используя динамическую типизацию.

Пример использования

1import 'package:get_storage/get_storage.dart';
2
3final box = GetStorage();
4
5// Записываем значение
6box.write('username', 'JohnDoe');
7
8// Читаем значение
9final username = box.read('username');
10
11// Проверяем наличие ключа
12if (box.hasData('username')) {
13  // Делаем что-то, если ключ существует
14}

Преимущества и недостатки get_storage

Преимущества

Недостатки

  • Простой и интуитивно понятный API.

  • Поддержка всех платформ, в том числе веб.

  • Данные хранятся в оперативной памяти.
  • Нет встроенной поддержки миграций.
  • Отсутствие разнообразия функций, как у некоторых других библиотек для работы с локальными БД.
  • Нельзя сохранять сложные объекты.

get_storage может быть полезен для хранения настроек пользователя, временных данных и другой информации, которая не требует сложных манипуляций с базами данных.


До этого момента мы рассматривали хранение данных в обычных текстовых файлах, что подходит для простых структур данных и для малых объёмов этих самых данных. Когда требования к данным возрастают, следом появляется необходимость в использовании более удобных и надёжных инструментов для работыс данными.

Помочь нам в этом призваны базы данных. О них и поговорим в следующем параграфе.

Чтобы добавить в заметки выделенный текст, нажмите Ctrl + E
Предыдущий параграф4.1. Системы хранения данных: библиотеки для работы с файлами
Следующий параграф4.3. Системы хранения данных: библиотеки для работы с БД