🦦

Flutterでflavorの設定構築

2022/02/08に公開

2022年6月追記
注意!FlutterFire CLIを利用している、予定でしらflavorでの
 pubspec.yamlの設定は異なります。
https://qiita.com/KazaKago/items/5dbe67032ecc7d459d74

筆者は記事を作成した時期のFlutterFire CLIがまだ日が浅かったので導入を見送っていましたが、
公式ドキュメントでは設定方法がございますので、おそらく推奨しております。
https://firebase.google.com/docs/flutter/setup?platform=ios

ios:テスト環境,本番環境
android:テスト環境、本番環境
合計、4つの環境が必要となりそれぞれfirebaseの設定も必要。

まとめますと、
1.flavoer(テスト,本番)
2.Run/DebugConfigurations(テスト,本番)
3.firebaseの設定(ios:テスト環境,本番環境,android:テスト環境、本番環境)
上記の設定が必要ではないでしょうか?

追記前のFlutterFire CLIを利用していない実装内容。

開発時に必要不可欠ではないでしょうか?
今回はFlavorパッケージを利用したのでご紹介致します。

今回は下記で設定を構築致します。

■テスト環境
・main-dev.dart
・devApiURL //テストApi
・devFireBase //テストFireBase
■本番環境
・main-production.dart
・productionApiURL//本番Api
・productionFireBase//本番FireBase

2022/2/8時点
pubspec.yaml

dependencies:
  flutter:
    sdk: flutter
  flutter_flavor: ^3.0.3
  flutter_flavorizr: ^2.1.0

flutter pub get

pubspec.yaml追加
※devはandroid firebaseの設定が混じってます。

flavorizr:
  app:
    android:
      flavorDimensions: "flavor-type"
    ios:
      flavorDimensions: "flavor-type"

  flavors:
    dev:
      app:
        name: "testRouteDev"
      android:
        applicationId: "com.example.testRoute.Dev" //※補足1
        firebase:
          config: "保管しているpath/google-services.json"
      ios:
        bundleId: "com.example.testRoute.Dev"
        #firebase:
          #config: "保管しているpath/GoogleService-Info.plist"
	///この時点ではfirebase,ios設定しておらずおそらくこれでいけるかな?
    production:
      app:
        name: "testRouteProduction"
      android:
        applicationId: "com.example.testRoute.production"
       //firebase未設定
      ios:
        bundleId: "com.example.testRoute.production"
      //firebase未設定  

生成
flutter pub run flutter_flavorizr

※補足1 firebase利用される方は一緒にしてください。自分はこれで動きました。

そしたら

dartファイルで生成されます。

page/my_home_page.dart //自分は必要ない

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

class MyHomePage extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(F.title),
      ),
      body: Center(
        child: Text(
          'Hello ${F.title}',
        ),
      ),
    );
  }
}

flavors.dart

enum Flavor {
  DEV,
  PRODUCTION,
}

extension FlavorName on Flavor {
  String get name => this.toString().split('.').last;
}

class F {
  static Flavor? appFlavor;

  static String get name => appFlavor?.name ?? '';

  static String get title {
    switch (appFlavor) {
      case Flavor.DEV:
           //ここでFlavorごとに分岐処理できるっぽい
        return 'testRouteTest';
      case Flavor.PRODUCTION:
           //ここでFlavor ごとに分岐処理できるっぽい
        return 'testRouteProduction';
      default:
        return 'title';
    }
  }

}

app.dart

class App extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return (
      child: MaterialApp(
        title: F.title,
        theme: ThemeData(
          primarySwatch: Colors.blue,
        ),
        home: MyHomePage(),
      ),
    );
  }
}

上記を変更
※auto_route使用しております。

class App extends StatelessWidget {

  final _appRouter = AppRouter();

  
  Widget build(BuildContext context) {
    return MaterialApp.router(
      routerDelegate: _appRouter.delegate(),
      routeInformationParser: _appRouter.defaultRouteParser(),
      title:  F.title,
      theme: ThemeData(
        primarySwatch: Colors.blue,

      ),
      //home: MyHomePage(),
    );
  }
  
}

main-dev.dart //スペルミスこっちが正しい

void main() {
//追記
  FlavorConfig(
      name: 'DEV',
      color: Colors.red, //自分は不要
      location: BannerLocation.bottomStart,
      variables:<String, dynamic>{
        'baseUrl': 'https://testapiurl〇〇.com',テスト用
      });
 //ここまで     
  F.appFlavor = Flavor.DEV;
  runApp(App());
}


main-production.dart

void main() {
//追記
  FlavorConfig(
      name: 'PRODUCTION',
      color: Colors.red,//自分は不要
      location: BannerLocation.bottomStart,
      variables:<String, dynamic>{
        'baseUrl': 'https://productionapiurl〇〇.com',//本番用
      });
 //ここまで  
  F.appFlavor = Flavor.PRODUCTION;
  runApp(App());
}

apiURL使用する場合

var baseUrl = FlavorConfig.instance.variables["baseUrl"];

Edit Configutations... から + -> Flutter でmain-production.dart追加します。
※main-devも同様。

これでRunやDebugできれば完了です。

参考サイト
先人の皆様ありがとうございます。

※Gradleエラー:ProductFlavor名を「test」で始めることはできません
https://stackoverflow.com/questions/54765759/gradle-error-productflavor-names-cannot-start-with-test/54765841
注意!testとは命名できない(android)

Flutter で環境を分ける方法
https://zenn.dev/attomicgm/articles/how_to_use_flutter_flavorizr

※iosでエラーが出る場合。
flutter_flavor + flutter_flavorizr を使って Flutter の Flavor を設定する
https://zenn.dev/kmd_htsh0226/articles/c229fe4b8fb321

Flutterプロジェクトの環境設定
https://zenn.dev/am10/scraps/38ab668821cee4

※flutter pub run flutter_flavorizrコマンドは
 各ファイル書き換えになるので注意
https://zenn.dev/ymgn____/articles/f087e2fac830a8

※普通に更新したら内容が書き変わる
 なので下を参考にする
【Flutter】flutter_flavorizrでflavorを設定する
https://blog.mrym.tv/2021/11/flutter_flavor_setting_using_flutter_flavorizr/

自分は下記を追加して書き換え阻止していますが、
あまり良い方法ではないので参考にならないかもしれません。

※基本的に書き換えた場合はmain-devなどで追加したコードが消失します。
書き換えたい場合と書き換えたくない場合が存在します。

pubspec.yaml追加

  instructions: # 不要なものはコメントアウトする
    - assets:download
    - assets:extract
    - android:androidManifest
    - android:buildGradle
    - android:dummyAssets
    #- flutter:flavors
    #- flutter:app
    #- flutter:pages
    #- flutter:targets
    - ios:xcconfig
    - ios:buildTargets
    - ios:schema
    - ios:dummyAssets
    - ios:plist
    - ios:launchScreen
    - google:firebase
    - assets:clean
    - ide:config

以上、誰かのお役に立てれば幸いです!

Discussion