shared_preferences

shared_preferences は、アプリの設定やちょっとしたデータを保存するパッケージです!
比喩で言うと: スマホのメモ帳のようなもの。簡単なデータをサッと保存して、後で取り出せます! 📝

🤔 何ができるの?
保存できるデータ:
✅ bool – true/false (例: ダークモード ON/OFF)
✅ int – 整数 (例: カウンター、年齢)
✅ double – 小数 (例: 音量、評価)
✅ String – 文字列 (例: ユーザー名、言語設定)
✅ List – 文字列のリスト (例: お気に入りリスト)

使う場面の例:

用途:

  • ログイン状態 bool isLoggedIn
  • ダークモード bool isDarkMode
  • 言語設定 String language (ja, en)
  • ユーザー名 String userName
  • 初回起動フラグ bool isFirstLaunch
  • 最終アクセス日 String lastAccess

保存できないもの(注意!):
❌ 大量のデータ – データベースを使う
❌ 複雑なオブジェクト – JSON に変換が必要
❌ 画像・動画 – ファイルとして保存
❌ 機密情報 – パスワード、クレカ番号(暗号化が必要)

インストール方法

pubspec.yaml に追加

dependencies:
  flutter:
    sdk: flutter
  
  shared_preferences: ^2.2.0

パッケージを取得

flutter pub get

import する

import 'package:shared_preferences/shared_preferences.dart';

基本的な使い方

STEP
インスタンスを取得
final prefs = await SharedPreferences.getInstance();
STEP
データを保存する
// bool を保存
await prefs.setBool('isDarkMode', true);

// int を保存
await prefs.setInt('age', 35);

// double を保存
await prefs.setDouble('volume', 0.8);

// String を保存
await prefs.setString('userName', '花子');

// List<String> を保存
await prefs.setStringList('favorites', ['りんご', 'バナナ', 'みかん']);
STEP
データを取得する
// bool を取得
bool? isDarkMode = prefs.getBool('isDarkMode');

// int を取得
int? age = prefs.getInt('age');

// double を取得
double? volume = prefs.getDouble('volume');

// String を取得
String? userName = prefs.getString('userName');

// List<String> を取得
List<String>? favorites = prefs.getStringList('favorites');

注意: 取得結果は null かもしれない ので ? が付きます!

STEP
デフォルト値を使う(推奨!)
// null の場合は false を返す
bool isDarkMode = prefs.getBool('isDarkMode') ?? false;

// null の場合は 0 を返す
int age = prefs.getInt('age') ?? 0;

// null の場合は 'ゲスト' を返す
String userName = prefs.getString('userName') ?? 'ゲスト';

// null の場合は空リストを返す
List<String> favorites = prefs.getStringList('favorites') ?? [];

?? 演算子使います

実践例1: ダークモード切り替え

import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';

class SettingsPage extends StatefulWidget {
  @override
  _SettingsPageState createState() => _SettingsPageState();
}

class _SettingsPageState extends State<SettingsPage> {
  bool isDarkMode = false;
  
  @override
  void initState() {
    super.initState();
    _loadSettings();  // 起動時に読み込む
  }
  
  // 設定を読み込む
  Future<void> _loadSettings() async {
    final prefs = await SharedPreferences.getInstance();
    setState(() {
      isDarkMode = prefs.getBool('isDarkMode') ?? false;
    });
  }
  
  // 設定を保存する
  Future<void> _saveSettings(bool value) async {
    final prefs = await SharedPreferences.getInstance();
    await prefs.setBool('isDarkMode', value);
    setState(() {
      isDarkMode = value;
    });
  }
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('設定')),
      body: SwitchListTile(
        title: Text('ダークモード'),
        value: isDarkMode,
        onChanged: (value) {
          _saveSettings(value);  // 切り替えたら保存
        },
      ),
    );
  }
}

ポイント:

initState で読み込み
スイッチを切り替えたら即保存
アプリを再起動しても設定が残る! ✅

実践例2: 初回起動チェック

アプリを初めて起動したときだけ、チュートリアルを表示:

import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: FutureBuilder<bool>(
        future: _checkFirstLaunch(),
        builder: (context, snapshot) {
          if (snapshot.connectionState == ConnectionState.waiting) {
            return CircularProgressIndicator();  // 読み込み中
          }
          
          // 初回起動なら チュートリアル
          if (snapshot.data == true) {
            return TutorialPage();
          }
          
          // 2回目以降なら ホーム画面
          return HomePage();
        },
      ),
    );
  }
  
  Future<bool> _checkFirstLaunch() async {
    final prefs = await SharedPreferences.getInstance();
    bool isFirstLaunch = prefs.getBool('isFirstLaunch') ?? true;
    
    if (isFirstLaunch) {
      // 初回フラグを false に更新
      await prefs.setBool('isFirstLaunch', false);
      return true;  // 初回起動
    }
    
    return false;  // 2回目以降
  }
}

ポイント:

使い道:

チュートリアル表示
利用規約の同意チェック
アプリ紹介画面

実践例3: ユーザー情報を保存

class UserPreferences {
  static const String _keyUserName = 'userName';
  static const String _keyEmail = 'email';
  static const String _keyIsLoggedIn = 'isLoggedIn';
  
  // ユーザー情報を保存
  static Future<void> saveUser({
    required String userName,
    required String email,
  }) async {
    final prefs = await SharedPreferences.getInstance();
    await prefs.setString(_keyUserName, userName);
    await prefs.setString(_keyEmail, email);
    await prefs.setBool(_keyIsLoggedIn, true);
  }
  
  // ユーザー情報を取得
  static Future<Map<String, dynamic>> getUser() async {
    final prefs = await SharedPreferences.getInstance();
    return {
      'userName': prefs.getString(_keyUserName) ?? '',
      'email': prefs.getString(_keyEmail) ?? '',
      'isLoggedIn': prefs.getBool(_keyIsLoggedIn) ?? false,
    };
  }
  
  // ログアウト(情報を削除)
  static Future<void> logout() async {
    final prefs = await SharedPreferences.getInstance();
    await prefs.remove(_keyUserName);
    await prefs.remove(_keyEmail);
    await prefs.setBool(_keyIsLoggedIn, false);
  }
  
  // 全データを削除
  static Future<void> clearAll() async {
    final prefs = await SharedPreferences.getInstance();
    await prefs.clear();
  }
}

// 使い方
void main() async {
  // 保存
  await UserPreferences.saveUser(
    userName: '花子',
    email: 'hisayo@example.com',
  );
  
  // 取得
  final user = await UserPreferences.getUser();
  print(user['userName']);  // 花子
  
  // ログアウト
  await UserPreferences.logout();
}

ポイント:

クラスにまとめて管理
キー名を定数化(タイプミス防止)
再利用しやすい

実践例4: お気に入りリスト

class FavoriteManager {
  static const String _keyFavorites = 'favorites';
  
  // お気に入りを追加
  static Future<void> addFavorite(String item) async {
    final prefs = await SharedPreferences.getInstance();
    List<String> favorites = prefs.getStringList(_keyFavorites) ?? [];
    
    if (!favorites.contains(item)) {
      favorites.add(item);
      await prefs.setStringList(_keyFavorites, favorites);
    }
  }
  
  // お気に入りを削除
  static Future<void> removeFavorite(String item) async {
    final prefs = await SharedPreferences.getInstance();
    List<String> favorites = prefs.getStringList(_keyFavorites) ?? [];
    
    favorites.remove(item);
    await prefs.setStringList(_keyFavorites, favorites);
  }
  
  // お気に入りリストを取得
  static Future<List<String>> getFavorites() async {
    final prefs = await SharedPreferences.getInstance();
    return prefs.getStringList(_keyFavorites) ?? [];
  }
  
  // お気に入りかチェック
  static Future<bool> isFavorite(String item) async {
    final prefs = await SharedPreferences.getInstance();
    List<String> favorites = prefs.getStringList(_keyFavorites) ?? [];
    return favorites.contains(item);
  }
}

// 使い方
void main() async {
  // 追加
  await FavoriteManager.addFavorite('りんご');
  await FavoriteManager.addFavorite('バナナ');
  
  // リスト取得
  List<String> favorites = await FavoriteManager.getFavorites();
  print(favorites);  // [りんご, バナナ]
  
  // チェック
  bool isFav = await FavoriteManager.isFavorite('りんご');
  print(isFav);  // true
  
  // 削除
  await FavoriteManager.removeFavorite('りんご');
}

便利なメソッド

データの存在確認:

final prefs = await SharedPreferences.getInstance();

// キーが存在するか確認
bool hasKey = prefs.containsKey('userName');

if (hasKey) {
  String userName = prefs.getString('userName')!;
} else {
  print('ユーザー名が保存されていません');
}

特定のキーを削除:

await prefs.remove('userName');  // userName だけ削除

全データを削除:

await prefs.clear();  // 全部削除

注意: アプリをアンインストールしても、データは削除されません! テスト時は clear() で削除。

全キーを取得:

Set<String> keys = prefs.getKeys();
print(keys);  // {userName, isDarkMode, age, ...}

❶ 必ず async/await を使う

// ❌ 間違い
final prefs = SharedPreferences.getInstance();  // エラー!

// ✅ 正しい
final prefs = await SharedPreferences.getInstance();

❷ キー名は定数化する

// ❌ 良くない
prefs.setString('userName', 'ヒサヨ');
String name = prefs.getString('userNmae');  // タイポ!

// ✅ 良い
class PrefsKeys {
  static const String userName = 'userName';
}

prefs.setString(PrefsKeys.userName, 'ヒサヨ');
String name = prefs.getString(PrefsKeys.userName)!;

❸ デフォルト値を必ず設定

// ❌ null が返る可能性
int? age = prefs.getInt('age');
print(age + 1);  // null なのでエラー!

// ✅ デフォルト値を使う
int age = prefs.getInt('age') ?? 0;
print(age + 1);  // 安全

❹ 大きなデータは保存しない

// ❌ 大量のデータ
List<String> bigData = List.generate(10000, (i) => 'データ$i');
await prefs.setStringList('bigData', bigData);  // 遅い!

// ✅ データベースを使う
// sqflite, hive, isar など

❺ 複雑なオブジェクトはJSONに変換

import 'dart:convert';

class User {
  String name;
  int age;
  
  User({required this.name, required this.age});
  
  // JSON に変換
  Map<String, dynamic> toJson() => {
    'name': name,
    'age': age,
  };
  
  // JSON から復元
  factory User.fromJson(Map<String, dynamic> json) => User(
    name: json['name'],
    age: json['age'],
  );
}

// 保存
User user = User(name: 'ヒサヨ', age: 35);
String userJson = json.encode(user.toJson());
await prefs.setString('user', userJson);

// 取得
String? userJson = prefs.getString('user');
if (userJson != null) {
  Map<String, dynamic> userMap = json.decode(userJson);
  User user = User.fromJson(userMap);
  print(user.name);  // ヒサヨ
}

いつ使う?

データshared_preferencesデータベース
ログイン状態
ダークモード
ユーザー名
設定値
初回起動フラグ
お気に入りリスト(少量)
会員リスト(大量)
会計記録(複雑)
画像・ファイル

ルール: 簡単で少量のデータ → shared_preferences、
複雑で大量のデータ → データベース

それでも迷ったら、人気な方を選べば間違いなし! 😊

一言まとめ:
shared_preferences は設定値やちょっとしたデータを保存するパッケージ!
setBool, setInt, setString で保存、
getBool, getInt, getString で取得。
async/await とデフォルト値 ?? を忘れずに! 📝✨