🍨

Create flavors of a Flutter app in Android

2024/08/08に公開

Flutterの環境分けをやってみる

公式の解説を参考に、Androidの環境分けをprod, stg, devでやってみようと思ったが、見てもさっぱりわからなかった😅

flutter_flavor

この記事を参考に設定した。ビルドするだけなので、参考にはならないかも。

Androidのflavor設定。
android/app/build.gradleのファイルに設定を追加する。

flavorDimensions "environment"
    productFlavors {
        prod {
            dimension "environment"
            applicationIdSuffix ""
            resValue "string", "app_name", "Flutter Flavor App"
        }
        stg {
            dimension "environment"
            applicationIdSuffix ".stg"
            resValue "string", "app_name", "Flutter Flavor App (Staging)"
        }
        dev {
            dimension "environment"
            applicationIdSuffix ".dev"
            resValue "string", "app_name", "Flutter Flavor App (Dev)"
        }
    }

修正後のファイル

plugins {
    id "com.android.application"
    id "kotlin-android"
    id "dev.flutter.flutter-gradle-plugin"
}

def localProperties = new Properties()
def localPropertiesFile = rootProject.file("local.properties")
if (localPropertiesFile.exists()) {
    localPropertiesFile.withReader("UTF-8") { reader ->
        localProperties.load(reader)
    }
}

def flutterVersionCode = localProperties.getProperty("flutter.versionCode")
if (flutterVersionCode == null) {
    flutterVersionCode = "1"
}

def flutterVersionName = localProperties.getProperty("flutter.versionName")
if (flutterVersionName == null) {
    flutterVersionName = "1.0"
}

android {
    namespace = "com.jboycode.flutter_flavor_app"
    compileSdk = flutter.compileSdkVersion
    ndkVersion = flutter.ndkVersion

    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_1_8
        targetCompatibility = JavaVersion.VERSION_1_8
    }

    defaultConfig {
        applicationId = "com.jboycode.flutter_flavor_app"
        minSdk = flutter.minSdkVersion
        targetSdk = flutter.targetSdkVersion
        versionCode = flutterVersionCode.toInteger()
        versionName = flutterVersionName
    }

    flavorDimensions "environment"
    productFlavors {
        prod {
            dimension "environment"
            applicationIdSuffix ""
            resValue "string", "app_name", "Flutter Flavor App"
        }
        stg {
            dimension "environment"
            applicationIdSuffix ".stg"
            resValue "string", "app_name", "Flutter Flavor App (Staging)"
        }
        dev {
            dimension "environment"
            applicationIdSuffix ".dev"
            resValue "string", "app_name", "Flutter Flavor App (Dev)"
        }
    }

    buildTypes {
        release {
            signingConfig signingConfigs.debug
        }
    }
}

flutter {
    source = "../.."
}

スクリーンショットだとこんな感じ

実行するときのコマンド

コマンドを実行すると、prod, stg, devごとにビルドできます。
prod:

flutter run --flavor prod

stg:

flutter run --flavor stg

dev

flutter run --flavor dev

Android Studioの設定をする

libの中にカウンターアプリのファイル名を変えたもので良いので用意してください。

スクリーンショット貼るのでこちらを参考にしてください。

+ボタンを押すと新しく設定を追加できる。

同じように、prod, stgも作成する。

切り替えて、Run, Debugどちらか押してビルドすると、環境分けしたファイルを指定して実行できる。



感想

Androidは難しくないように感じました。しかし、iOSは、xcodeの設定が難しい。もう少し時間がかかりそうですね。

まだ試せていないですが、REST APIを本番用とテスト用で、URLを変更する場合は、こんな感じでやるみたいです。

lib/config/environment.dartファイルを作成

import 'package:flutter/foundation.dart';

enum Flavor { prod, stg, dev }

class Environment {
  static Flavor? flavor;

  static String get apiBaseUrl {
    switch (flavor) {
      case Flavor.prod:
        return 'https://api.example.com';
      case Flavor.stg:
        return 'https://stg-api.example.com';
      case Flavor.dev:
        return 'https://dev-api.example.com';
      default:
        return 'https://api.example.com';
    }
  }

  static void init() {
    if (kReleaseMode) {
      flavor = Flavor.prod;
    } else {
      const flavorName = String.fromEnvironment('FLAVOR', defaultValue: 'dev');
      flavor = Flavor.values.firstWhere(
        (e) => e.toString() == 'Flavor.$flavorName',
        orElse: () => Flavor.dev,
      );
    }
    print('Current flavor: $flavor');
    print('API Base URL: $apiBaseUrl');
  }
}

lib/main.dartファイルを修正して、アプリ起動時に環境を初期化

import 'package:flutter/material.dart';
import 'config/environment.dart';

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  Environment.init();
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Flavor App',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Flavor Demo'),
    );
  }
}

class MyHomePage extends StatelessWidget {
  final String title;

  MyHomePage({Key? key, required this.title}) : super(key: key);

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text('Current Flavor: ${Environment.flavor}'),
            Text('API Base URL: ${Environment.apiBaseUrl}'),
          ],
        ),
      ),
    );
  }
}

Discussion