【Flutter/Dart】shared_preferencesでローカルにデータを保存する方法と仕組み

この記事からわかること
- Flutter/Dartのshared_preferencesの実装方法
- ローカルにデータを保存するには?
index
[open]
\ アプリをリリースしました /
環境
- Android Studio:Koala
- Xcode:16.0
- Flutter:3.29.2
- Dart:3.7.2
- shared_preferences:2.5.2
- Mac M1:Sequoia 15.4
Flutterアプリで端末(ローカル)にデータを永続的に保存する方法
FlutterでiOS/Androidアプリを開発する際に端末(ローカル)にデータを永続的に保存する方法はいくつか用意されています。
- shared_preferences
- sqflite
- Realm
- flutter_secure_storage
- テキストファイル
それぞれに一長一短がありますが今回はshared_preferences
を使用する方法をまとめていきます。
shared_preferences
shared_preferences
はローカルにデータを保存するための機能を提供しているパッケージです。独自の仕組みというよりiOS/Android固有の永続ストレージ機能をラップして共通して実装できるようになっているのがこのパッケージです。
iOSはUserDefaults、AndroidはSharedPreferencesの仕組みがラップされています。ラップしているだけなので仕組みはそれぞれの要件を確認する必要がありますが、データを永続化できることと大事なデータ(ログイン情報など)は格納しないという点は共通かと思います。
ログイン情報などのセキュリティ要件を高めて保存したいデータはflutter_secure_storage
を活用してください。こちらはiOSはKeyChain、AndroidはKeyStoreをラップしたパッケージになります。
サポートされているデータ型はint
、double
、bool
、String
、List<String>
です。
導入方法
パッケージを導入するにはプロジェクトルートでflutter pub add パッケージ名
コマンドを実行します。
$ flutter pub add shared_preferences
これでパッケージの導入が完了し、import
文を追加すれば使用できるようになります。
import 'package:shared_preferences/shared_preferences.dart';
実装方法
shared_preferences
を使用するにはまずSharedPreferences
インスタンスを取得する必要があります。シングルトンのインスタンスがgetInstance
メソッドで取得できるのこれを使用して取得します。ただasync
が付与されている非同期処理になるのでawait
を使用して呼び出す必要があるので注意してください。
final prefs = await SharedPreferences.getInstance();
データを保存する
データを保存したい場合はsetデータ型(キー,値)
メソッドを使用します。引数にデータを保存するためのキーと実際に保存したい値を指定します。こちらもasync
が付与されている非同期処理になるのでawait
を使用して呼び出す必要があります。
final prefs = await SharedPreferences.getInstance();
await prefs.setString(SharedPreferencesKeys.USERNAME.key, 'ame');
データ型によって呼び出すメソッドが変化します。
メソッド名 | データ型 |
---|---|
setInt(String key, int value) | int |
setDouble(String key, double value) | double |
setBool(String key, bool value) | bool |
setString(String key, String value) | String |
setStringList(String key, List<String> value) | List<String> |
データを取得する
データを取得したい場合はgetデータ型(キー)
メソッドを使用します。引数にデータを取得するためのキーを指定します。こちらは非同期ではないのでawait
を使用せずに呼び出すことが可能です。
final prefs = await SharedPreferences.getInstance();
String? username = prefs.getString(SharedPreferencesKeys.USERNAME.key);
print(username);
またデータが存在しなかった場合はnull
が返却されます。データ型によって呼び出すメソッドが変化します。
メソッド名 | データ型 |
---|---|
getInt(String key) | int? |
getDouble(String key) | double? |
getBool(String key) | bool? |
getString(String key) | String? |
getStringList(String key) | List<String>? |
データを削除する
一度保存したデータはアプリがアンインストールされない限り永続化されます。データを明示的に削除したい場合はremove(キー)
メソッドを使用します。また全てのデータを削除したい場合はclear
メソッドを使用します。
// 指定して削除
await prefs.remove(SharedPreferencesKeys.USERNAME.key);
// 全て削除
await prefs.clear();
メソッド名 | データ型 | 説明 |
---|---|---|
remove(String key) | Future<bool> | 指定したキーのデータを削除する |
clear() | Future<bool> | すべてのデータを削除する |
管理クラスに切り出してみる
ローカル保存・取得の機能を管理用クラスとして切り出してみました。_instance
からシングルトンインスタンスを参照できるようになっており、キーはSharedPreferencesKeys
で管理しています。
import 'package:shared_preferences/shared_preferences.dart';
enum SharedPreferencesKeys {
USERNAME('username');
final String key;
const SharedPreferencesKeys(this.key);
}
class SharedPreferencesService {
static final SharedPreferencesService _instance = SharedPreferencesService._internal();
factory SharedPreferencesService() => _instance;
SharedPreferences? _prefs;
SharedPreferencesService._internal();
Future<void> init() async {
_prefs = await SharedPreferences.getInstance();
}
Future<void> saveUsername(String username) async {
_prefs?.setString(SharedPreferencesKeys.USERNAME.key, username);
}
String? getUsername() {
return _prefs?.getString(SharedPreferencesKeys.USERNAME.key);
}
Future<void> remove(SharedPreferencesKeys key) async {
final prefs = _prefs;
if (prefs == null) return;
await prefs.remove(key.key);
}
Future<void> clearData() async {
final prefs = _prefs;
if (prefs == null) return;
await prefs.clear();
}
}
実際にViewから使用する場合は以下のように使用します。
import 'package:flutter/material.dart';
import 'shared_prefs_service.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await SharedPreferencesService().init();
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: const PageA(),
);
}
}
class PageA extends StatefulWidget {
const PageA({super.key});
@override
State<PageA> createState() => _PageAState();
}
class _PageAState extends State<PageA> {
String _username = "";
TextEditingController _controller = TextEditingController();
// ユーザー名を取得
Future<void> _getUsername() async {
String? username = SharedPreferencesService().getUsername();
setState(() {
_username = username ?? "まだ保存されていません";
});
}
// ユーザー名を保存
Future<void> _saveUsername() async {
String username = _controller.text; // 入力されたユーザー名を取得
if (username.isNotEmpty) {
await SharedPreferencesService().saveUsername(username);
_getUsername(); // 保存後に再取得
} else {
// 空のユーザー名が入力された場合はアラート
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text("ユーザー名を入力してください")),
);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("SharedPreferences デモ")),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// 入力ボックス
Padding(
padding: const EdgeInsets.all(16.0),
child: TextField(
controller: _controller,
decoration: const InputDecoration(
labelText: "ユーザー名を入力",
border: OutlineInputBorder(),
),
),
),
const SizedBox(height: 20),
// 保存されているユーザー名表示
Text(
"保存されているユーザー名: $_username",
style: const TextStyle(fontSize: 18),
),
const SizedBox(height: 20),
// ユーザー名取得ボタン
ElevatedButton(
onPressed: _getUsername,
child: const Text("ユーザー名を取得"),
),
const SizedBox(height: 20),
// ユーザー名保存ボタン
ElevatedButton(
onPressed: _saveUsername,
child: const Text("ユーザー名を保存"),
),
],
),
),
);
}
}

まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。
ご覧いただきありがとうございました。