🔖

Flutter+Firestore+Riverpodで1回だけ強制アップデートチェック

4 min read

今回はFlutter+Firestore+Riverpodにて、
アプリ起動時などに1回だけ強制アップデートのチェックを行う実装をしたいと思います。

環境

Firestore

誰でもread出来るようにルールを設定

  • path
    /config/update
  • フィールド 強制アップデートバージョンを設定
    android_version: '1.0.0'
    ios_version: '1.0.0'

flutter doctor -v

>flutter doctor -v
Flutter version 2.8.0
Dart version 2.15.0

pubspec.yaml

dependencies:
  flutter:
    sdk: flutter
  #状態管理
  riverpod: ^1.0.0 #https://pub.dev/packages/riverpod
  #Firebase
  firebase_core: ^1.10.0 #https://pub.dev/packages/firebase_core
  cloud_firestore: ^3.1.0 #https://pub.dev/packages/cloud_firestore
  #現在の端末からバージョンを取得
  package_info_plus: ^1.3.0 #https://pub.dev/packages/package_info_plus
  #バージョンの解析、比較
  version: ^2.0.0 #https://pub.dev/packages/version

実装

Model


import 'dart:io';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:riverpod/riverpod.dart';
import 'package:version/version.dart';

// riverpod
final versionCheckProvider =
    FutureProvider<bool>((ref) => FirestoreService().versionCheck());

class FirestoreService {
  Future<bool> versionCheck() async {
    final firestorePath =
        FirebaseFirestore.instance.collection('config').doc('update');
    final configDoc = await firestorePath.get();

// docの有無を確認
    if (configDoc.exists) {
      final data = configDoc.data();
      //現在の端末のアプリバージョンを取得
      final packageInfo = await PackageInfo.fromPlatform();
      final currentVersion = Version.parse(packageInfo.version);
      //強制アップデートバージョンを取得
      final Version latestVersion;
      //プラットフォームごとの処理を設定
      if (Platform.isIOS) {
        latestVersion = Version.parse(data!['ios_version'] ?? '1.0.0');
      } else if (Platform.isAndroid) {
        latestVersion = Version.parse(data!['android_version'] ?? '1.0.0');
      }
      //必要に応じて別のプラットフォームを追加
      else {
        latestVersion = Version.parse('1.0.0');
      }

      //強制アップデートバージョンが端末のアプリバージョンを上回ると true
      //バージョンが同等か下回ればfalse
      final result = latestVersion > currentVersion ? true : false;
      return result;
    } 
    //Firestore上にdocが見つからなかった場合
    else {
      //docがなかったら通過させる
      return false;
    }
  }
}

View



class LoginCheck extends ConsumerWidget {
  const LoginCheck({Key? key}) : super(key: key);

  
  Widget build(BuildContext context, ref) {
  // FutureProvider
    final versionCheck = ref.watch(versionCheckProvider);

    return Scaffold(
      appBar: AppBar(),
      body: versionCheck.when(
        loading: () => const CircularProgressIndicator(
          semanticsLabel: 'Loading',
        ),
        error: (error, stack) => Text('Error: $error'),
        data: (doc) {
	//強制アップデートの処理
          if (doc == true) {
            Future.delayed(Duration.zero, () {
	    //アップデート要求ダイアログを起動
              updateDialog(context);
            });
            return const SizedBox();
          } 
	  //強制アップデートなしの処理
	  else {
	  //他の画面へ遷移させる
	  //例:HomeScreenへ遷移させる場合
             Future.delayed(
        Duration.zero,
        () => Navigator.pushReplacementNamed(context, HomeScreen()),
      );
            return const SizedBox();
          }
        },
      ),
    );
  }
}

void updateDialog(BuildContext context) {
  showDialog(
    context: context,
    barrierDismissible: false,
    builder: (BuildContext context) {
      return AlertDialog(
        title: const Text(
          'ストアページへの遷移処理',
          textScaleFactor: 1,
        ),
        actions: <Widget>[
          ElevatedButton(
            child: const Text(
              'btn',
            ),
            onPressed: () {
	    //  ストアページへの遷移処理などを記載
	    },
          ),
        ],
      );
    },
  );
}


Discussion

ログインするとコメントできます