Flutter Flavor対応（パッケージ未使用）


#内容
Flutter開発時にFlavorが導入されたプロジェクトに参画したり、他のメンバーがFlavorを導入した後にFlutterを触ったりすることはあったが、自分でFlavorを導入したことがなかったので、導入までの流れをまとめる。

やり方は様々あるようですが、今回は、main_dev.dartとmain_prod.dartの2ファイルを作成する方法で行います。

#開発環境

PC:macOS Big Sur
エディター：Visual Studio Code, Android Studio, Xcode

Dart：2.13.1
Flutter：2.2.1
Visual Studio Code：1.16.2
Android Studio：4.1.2
Xcode：13.1

その他
　Flavorパッケージは未使用
今回は開発環境と本番環境を作成する。
それぞれの名前は以下のように統一している。（Android, iOS共に同じ名前を使用する。）
開発環境：dev
本番環境：prod


#準備

以下のファイルを作成する。

・main_dev.dart
・main_prod.dart
・app_config.dart
・main_common.dart
・home_page.dart

```main_dev.dart
import 'package:flutter/material.dart';

import 'app_config.dart';
import 'main_common.dart';

void main() {
  var configuredApp = AppConfig(
    appDisplayName: "Dev App",
    child: MyApp(),
  );

  runApp(configuredApp);
}
```

```main_prod.dart
import 'package:flutter/material.dart';

import 'app_config.dart';
import 'main_common.dart';

void main() {
  var configuredApp = AppConfig(
    appDisplayName: "Prod App",
    child: MyApp(),
  );

  runApp(configuredApp);
}
```

```app_config.dart
import 'package:flutter/material.dart';

class AppConfig extends InheritedWidget {
  AppConfig({
    required this.appDisplayName,
    required Widget child,
  }) : super(child: child);

  final String appDisplayName;

  static AppConfig? of(BuildContext context) {
    return context.dependOnInheritedWidgetOfExactType<AppConfig>();
  }

  @override
  bool updateShouldNotify(InheritedWidget oldWidget) => false;
}
```

```main_common.dart
import 'package:flutter/material.dart';
import 'app_config.dart';
import 'home_page.dart';

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    var config = AppConfig.of(context);
    return _buildApp(config!.appDisplayName);
  }

  Widget _buildApp(String appName) {
    return MaterialApp(
      title: appName,
      theme: ThemeData(
        primaryColor: Color(0xFF43a047),
        accentColor: Color(0xFFffcc00),
        primaryColorBrightness: Brightness.dark,
      ),
      home: HomePage(),
    );
  }
}
```

```home_page.dart
import 'package:flutter/material.dart';
import 'app_config.dart';

class HomePage extends StatefulWidget {
  const HomePage({Key? key}) : super(key: key);

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    final config = AppConfig.of(context);
    return Scaffold(
      appBar: AppBar(
        title: Text(config!.appDisplayName),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    );
  }
}
```


#Androidの設定

android/app/src/build.gradleファイルを開き、android{}内にdev、prodという名前でflavorの設定を追加する。

```build.gradle
android {
    compileSdkVersion 30

    sourceSets {
        main.java.srcDirs += 'src/main/kotlin'
    }

    defaultConfig {
        applicationId "com.sample.flutter_flavor_sample_app"
        minSdkVersion 16
        targetSdkVersion 30
        versionCode flutterVersionCode.toInteger()
        versionName flutterVersionName
    }
    // ここから
    flavorDimensions "flutter-flavor"
    productFlavors {
        dev {
            dimension "flutter-flavor"
            applicationId "com.example.dev"
            resValue "string", "app_name", "Dev App"
        }
        prod {
            dimension "flutter-flavor"
            applicationId "com.example.prod"
            resValue "string", "app_name", "Prod App"
        }
    }
    // ここまで追加

    buildTypes {
        release {
            signingConfig signingConfigs.debug
        }
    }
}
```

次にandroid/app/src/main/AndroidManifest.xmlファイルのlabelを変更する。

```AndroidManifest.xml
android:label="hogehoge_app_name" <-ここのアプリ名を変更する（プロジェクト作成時の名前が記載されている）
　　　　　　　　　　↓
android:label="@string/app_name"
```

@string/app_nameにはresValueに記入した値が代入される。

dev環境で実行すると、アプリ名は「Dev App」に、prod環境実行すると、アプリ名は「Prod App」になる。

Android Studioからエントリーポイントを設定する。
以下の画像のような流れで設定をする。

「Edit Configurations...」をクリックする。
![スクリーンショット 2021-10-30 18.15.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/631339/39e09933-96bf-b97b-5dd3-b75bbd2c2cf1.png)

表示されたダイアログの左上にある+ボタンをクリックして、Flutterを選択する。
![スクリーンショット 2021-10-30 18.17.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/631339/1fb5200d-da23-7857-bc71-4f1d772ec500.png)

NameとDart entrypoint、Build flavorを入力する。
devとprodの2つを以下のように設定する。

・dev
Name: dev
Dart entrypoint: hogehoge/lib/main_dev.dart
Build flavor: dev

・prod
Name: prod
Dart entrypoint: hogehoge/lib/main_prod.dart
Build flavor: prod

※Dart entrypointはmain.dartからコピーして、main.dartの部分を変更する。
![スクリーンショット 2021-10-30 18.18.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/631339/ad0ac69f-c43b-66b2-613d-c03655845a28.png)

#iOSの設定

Runner.xcworkspaceを開いて、メニューバーのProduct/Scheme/New Scheme...をクリックする。
![スクリーンショット 2021-10-27 2.17.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/631339/ab146d57-29fa-2ffb-ce48-f7a04d4649d0.png)

以下のようなダイアログが表示されるので、devとprodを追加する。
![スクリーンショット 2021-10-27 2.18.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/631339/b2854e9c-c25f-5fdc-4d65-80f318a6b332.png)

メニューバーのProduct/Scheme/Manage Scheme...をクリックすると、追加したSchemeが確認できる。
（今回はdevとprodを追加している。その他のSchemeもあるが、関係ない。）
![スクリーンショット 2021-10-27 2.19.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/631339/f195b3d4-6e19-9fca-0bad-4214953db18c.png)

PROJECTのRunnerのInfoタブを表示する。
+ボタンをクリックして、ConfigurationにDegug-dev、Degug-prod、Release-prodを追加する。
![スクリーンショット 2021-10-30 20.19.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/631339/30046409-1592-2d42-f5cc-160def2c930e.png)

追加の際には下記のようなダイアログが表示されるので、対応するものを選択する。
![スクリーンショット 2021-10-30 20.23.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/631339/380061c8-d992-dffc-cf85-4175c6151ec9.png)


#参考

https://flutter.dev/docs/deployment/flavors

https://medium.com/flutter-jp/flavor-b952f2d05b5d

https://qiita.com/hiromasa-fun/items/c79c99535f6f1db2a6a9