🌊

【Flutter】Firestoreを用いて強制アップデートを実装する

2022/01/14に公開

はじめに

「Flutter 強制アップデート」で調べるとFirebaseのRemoteConfig で実装する例をよく目にします。
RemoteConfigでの実装例はこちらの記事がとてもわかりやすかったです。
https://qiita.com/kasa_le/items/a7bae1b9aef6dfde2504

しかしこちらの実装を終えてみて、わざわざRemoteConfigを設定せずにFirestoreでよくね?と思ったのでFirestoreでの実装例を紹介させていただきます!

またこちらの個人開発アプリで実際に実装してみたので、アプリについて宣伝させていただきます! 
二郎好きの方はぜひ使ってみてください!
https://apps.apple.com/us/app/二郎生活-ラーメン簡単マップ検索-クチコミ投稿アプリ/id1604416308

完成例

強制アップデートダイアログ

全体像

強制アップデートはRemoteConfigでもFirestoreでもやることは同じで

1. 現在のアプリのバージョンを確認する
2. アップデートしたいバージョンをFirestore(or RemoteConfig)から取得する
3. 現在のアプリバージョンがアップデートしたいバージョンより低ければ強制アップデートのダイアログを表示させる

というシンプルなものになります。
この順番に実装例をご紹介します!

実装例

前提

Firebaseの設定を行なっていること
https://firebase.google.com/docs/flutter/setup?hl=ja&platform=ios

必要なパッケージ

pubspec.yaml
dependencies:
	cloud_firestore: ^2.3.0
	firebase_core: ^1.10.0
	package_info: ^2.0.2 //アプリのバージョンを取得
	url_launcher: ^6.0.17 //ストアを開く
	version: ^2.0.0 //なくても良い(1.0.3と1.0.4を簡単に比較できるようになる)

pubspec.yamlに記述し pub get

Firestoreにアップデートしたいバージョンを入れる

以下のようにconfigコレクションにios_force_app_versionを作成する。(Androidも実装する場合は別で値を作成する。今回は省略)
Firestore

現在のアプリバージョンを確認する

package_infoを用いて現在のアプリのバージョンを取得します。

 final info = await PackageInfo.fromPlatform();
 final currentVersion = Version.parse(info.version);

Firestoreからアップデートしたいバージョンを取得する。

さきほどFirestoreに入れたバージョンをアプリ側で取得する

final doc = await FirebaseFirestore.instance
        .collection('config')
        .doc('- ドキュメントIDを指定する -')
        .get();
final newVersion =  Version.parse(doc.data()!['ios_force_app_version'] as String);

現在のバージョンとFirestoreから取得したバージョンを比較してダイアログを出す

//現在のバージョンがアップデートしたいバージョンより低ければダイアログを出す。
if (currentVersion < newVersion) {
      showUpdateDialog(context);
    }
ダイアログ
 // FIXME ストアにアプリを登録したらurlが入れられる
  static const appStoreURL =
      'https://apps.apple.com/jp/app/id[アプリのApple ID]?mt=8';

  /// ダイアログを表示
  void showUpdateDialog(BuildContext context) {
    showDialog<void>(
      context: context,
      barrierDismissible: false,
      builder: (BuildContext context) {
        const title = 'バージョン更新のお知らせ';
        const message = '新しいバージョンのアプリが利用可能です。ストアより更新版を入手して、ご利用下さい。';
        const btnLabel = '今すぐ更新';
        return CupertinoAlertDialog(
          title: const Text(title),
          content: const Text(message),
          actions: <Widget>[
            TextButton(
              child: const Text(
                btnLabel,
                style: TextStyle(color: Colors.red),
              ),
              onPressed: () async {
                if (await canLaunch(appStoreURL)) {
                  await launch(
                    appStoreURL,
                    forceSafariVC: true,
                    forceWebView: true,
                  );
                } else {
                  throw Error();
                }
              },
            ),
          ],
        );
      },
    );
  }

全体のコード

//アプリ起動時に呼ぶ
 Future<void> versionCheck() async {
    //アプリのバージョンを取得
    final info = await PackageInfo.fromPlatform();
    final currentVersion = Version.parse(info.version);
    
    //Firestoreからアップデートしたいバージョンを取得
    final doc = await FirebaseFirestore.instance
        .collection('config')
        .doc('- ドキュメントIDを指定する -')
        .get();
    final newVersion =  Version.parse(doc.data()!['ios_force_app_version'] as String);
    
    //バージョンを比較し、現在のバージョンの方が低ければダイアログを出す
    if (currentVersion < newVersion) {
      showUpdateDialog(context);
    }
  }
  
  // FIXME ストアにアプリを登録したらurlが入れられる
  static const appStoreURL =
      'https://apps.apple.com/jp/app/id[アプリのApple ID]?mt=8';

  /// ダイアログを表示
  void showUpdateDialog(BuildContext context) {
    showDialog<void>(
      context: context,
      barrierDismissible: false,
      builder: (BuildContext context) {
        const title = 'バージョン更新のお知らせ';
        const message = '新しいバージョンのアプリが利用可能です。ストアより更新版を入手して、ご利用下さい。';
        const btnLabel = '今すぐ更新';
        return CupertinoAlertDialog(
          title: const Text(title),
          content: const Text(message),
          actions: <Widget>[
            TextButton(
              child: const Text(
                btnLabel,
                style: TextStyle(color: Colors.red),
              ),
              onPressed: () async {
                if (await canLaunch(appStoreURL)) {
                  await launch(
                    appStoreURL,
                    forceSafariVC: true,
                    forceWebView: true,
                  );
                } else {
                  throw Error();
                }
              },
            ),
          ],
        );
      },
    );
  }

最後に

個人的にはRemoteConfigよりもFirestoreの方がシンプルに実装できると感じました!
参考になれば幸いです。

参考資料など

https://qiita.com/kasa_le/items/a7bae1b9aef6dfde2504
https://pub.dev/packages/cloud_firestore
https://pub.dev/packages/firebase_core
https://pub.dev/packages/package_info
https://pub.dev/packages/version
https://pub.dev/packages/url_launcher

Flutter大学

Discussion