くらげになりたい。

くらげのようにふわふわ生きたい日曜プログラマなブログ。趣味の備忘録です。

Flutter x Firebase Remote Configで強制アップデート

Firebaseコンソールで設定した値を、
Flutterアプリから取得できるRemote Config

Remote Configとpackage_info_plusをつかって、
強制アップデート機能を実装したときの備忘録(*´ω`*)

状態管理には、riverpodを利用してる

ざっくりとした流れ

流れとしてはこんな感じ

  • 起動時
    • package_info_plusでバージョンなどを取得
    • Remote Configで値の変更をliten開始
  • Remote Configの値変更時
    • 現在のバージョンと比較
    • アップデートが必要であれば、ダイアログなどを出す

起動時

PackageInfo周りはこんな感じ。

import 'package:package_info_plus/package_info_plus.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';

// キャッシュとして保存しておくProvider
@Riverpod(keepAlive: true)
PackageInfo packageInfo(PackageInfoRef ref) {
  throw UnimplementedError();
}

// 起動時の処理
FutureOr<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  // パッケージ情報の取得
  PackageInfo packageInfo = await PackageInfo.fromPlatform();
  
  // Firebaseの初期化
  await Firebase.initializeApp(options: options);
  
  // Firebase Remote Confingの設定
  await FirebaseRemoteConfig.instance.setConfigSettings(RemoteConfigSettings(
    fetchTimeout: const Duration(minutes: 1),
    minimumFetchInterval: const Duration(minutes: 5),
  ));
  
  // アプリの起動
  runApp(ProviderScope(
    overrides: [
      // 初期化したinstanceで上書き
      packageInfoProvider.overrideWithValue(packageInfo),
    ],
    child: const MyApp(),
  ));
}

PackageInfooverridesをつかって保持しておく

FirebaseRemoteConfigではタイムアウトと取得間隔を設定、
取得間隔(最小フェッチ間隔)のデフォルトは12時間。

Remote Configの値の変更をリアルタイムで取得/反映する

Remote Configの値を取得したり、変更を監視する部分はこんな感じ。

@Riverpod(keepAlive: true)
class ForceUpdate extends _$ForceUpdate {
  @override
  bool build() {
    final packageInfo = ref.watch(packageInfoProvider);
    final remoteConfig = FirebaseRemoteConfig.instance;

    // リアルタイムで変更を監視
    fbConfig.onConfigUpdated.listen((event) async {
      try {
        // 更新された値を反映する
        await remoteConfig.activate();
        
        // バージョンを比較して、結果を保存
        state = checkForceUpdate(packageInfo.version);
      } catch (error) {
        // エラーが発生したら、なにもしない
      }
    });

    // 初期化時に、現在の値を取得をリクエスト
    remoteConfig.fetch();
    // バージョンを比較して、結果を保存
    return checkForceUpdate(packageInfo.version);
  }
}

// 強制アップデートが必要かどうかのチェック
bool checkForceUpdate(String pkgVer) {
  try {
    // RemoteConfigの値を取得
    final remoteConfig = FirebaseRemoteConfig.instance;
    final updateVersionKey = "update_version";
    final confVer = remoteConfig.getString(updateVersionKey);
    if (confVer.isEmpty) return false;

    // packageInfo.versionと値を比較
    // 強制アップデートの必要があるかを返す
    final result = pkgVer.compareTo(confVer) < 0;
    return result;
  } catch (error) {
    // エラーが発生したら、falseを返す
    return false;
  }
}

Remote Configには、fetchactivateの2つの動作があり、

  • fetch ... サーバから最新の値を取得
  • activate ... fetchした値を利用できるようにする

という感じ。

onConfigUpdatedでは、fetchのみなので、
activate()で取得した値を反映後に、
remoteConfig.getString(updateVersionKey)で値を取得している

強制アップデートの必要かの確認

あとは、対象の画面でチェックして、
ダイアログを表示しておけばOK(*´ω`*)

class FooPage extends HookConsumerWidget {
  const FooPage({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    useEffect(() {
        WidgetsBinding.instance.addPostFrameCallback((_) {
          final needUpdate = ref.read(forceUpdateProvider);
          if (needUpdate) {
            // ダイアログを表示する
          }
        });
      return null;
    }, const []);
  }
}

以上!! Remote Config、便利だね(*´ω`*)

参考にしたサイトさま