Chapter 21

[v0.14.0以下版] Providerとoverridesを使ってflavorをアプリ内で使用する

村松龍之介
村松龍之介
2023.02.12に更新

サンプルリポジトリのリンク

flavor.dart のコード全容はこちらのリンクから、GitHubリポジトリにて確認できます。
https://github.com/Riscait/flutter_playground/blob/main/lib/src/top_level_providers/flavor.dart


Flavorを使うと、開発環境・テスト環境・本番環境というようにアプリの環境を変化させることが可能です。

開発環境と本番環境で異なる文字列を表示させたかったり、安全のため異なるデータベースを使いたいことは多々あるので、各Storeで公開するアプリにとってはほぼ必須と言っても良い機能ではないでしょうか。

当書籍ではRiverpodに主眼をおいているため、Flavorの詳細やiOS, Androidでの設定は割愛いたします。

なぜProviderか

Flavorはアプリビルド時や起動時に指定するものであり、基本的にアプリ内で変えるものではありません。
なので、変化する状態を持たない、一番基本的な「Provider」を使用します。

Flavorを指定するオプションを追加

まず、FlutterアプリにFlavor(環境)を伝えるには、 dart-define オプションを使って指定します。
以下のように build or run の後に --dart-define=FLAVOR= と書き、任意の環境文字列で指定します。

$ flutter build --dart-define=FLAVOR=development
$ flutter run --dart-define=FLAVOR=development

Flavorの定義

Flavor自体は enum で表現しましょう。
ここでは、3種類のFlavorを定義しましたが、Flavorの数と名前は好みのものを設定ください。
(他の方の記事を読むと、 develop , qa , prod などの文字列を見かけますね)

flavor.dart
enum Flavor {
  development,
  staging,
  production,
}

// 拡張して、文字列を返すGetterを用意しておくと、何かと便利です。
extension FlavorExt on Flavor {
  String get key => describeEnum(this);
}

Providerの作成

続いて、Flavorを入れるためのProviderを宣言します。

flavor.dart
final flavorProvider = Provider<Flavor>((ref) => throw UnimplementedError());

後ほど必ず値を入れるため、初期値では throw UnimplementedError() のエラーを投げています。
初期値がFlavorではないため、 <Flavor>のように型の明示を忘れないようにしましょう。
明示しなければ、 Provider<Never> と推論されてしまいます。

main関数でFlavorを受け取り、ProviderScopeに渡す

では、 main関数でFlavorを受け取り、 flavorProvider の値を上書きしましょう。

main.dart
void main() {
  // `runApp` 関数完了前に何か処理を行いたいときに実行必須の関数です。
  WidgetsFlutterBinding.ensureInitialized();

  // ビルド時に指定したFlavorを取得
  final flavorString = const String.fromEnvironment('FLAVOR');
  // enumから `flavorString` と一致する Flavor を取得
  final flavor = Flavor.values.firstWhere((e) => e.key == flavorString);

  runApp(
    ProviderScope(
      overrides: [
        // flavorProviderの値に `flavor` を入れる
        flavorProvider.overrideWithValue(flavor),
      ],
      child: App(),
    ),
  );
}

String.fromEnvironment('FLAVOR') と書くことで、ビルド時に --dart-define=FLAVOR=xxx で指定したFlavorの文字列を取得できます。
あとは、その文字列からFlavorを特定し、 ProviderScopeの overridesで flavorProvider の値を上書きすれば完了です。

flavorProvider を読み込むことで、アプリのどこからでもFlavorが取得できるようになりました🎉

参考リンク

Creating flavors for Flutter - Flutter
https://flutter.dev/docs/deployment/flavors