🦄

【Flutter】Build flavor を使うプロジェクトを作成する

2024/03/01に公開

flavorのWEB対応について(追記:2024-02-26)

とある日の会話

確かにAndroidStudioのRun/Debug ConfigurationsにもBuild flavorという項目は存在していまして、自分も何でここを使わないんだろうなぁ〜とは思っていました。
「どーせ、iOS側の設定が色々と面倒くさいからやろ」くらいに見過ごしてきましたが、いい機会だしやってみることに。

以下、flutter createからの差分を記載していく流れになります。
(最低限の内容で記載していくため、実際のコードとは異なります)

Android

高度な次元で悩んでるたっつー氏は置いておいて、Android側の設定を見てみましょう。

applicationIdにsuffixをつける

android/app/build.gradleに対して、以下のようにproductFlavorsの設定を追加します。
この例では、デフォルトをdevとして、prodのビルド以外でapplicationIdにsuffixをつけるような設定にしてあります。

android/app/build.gradle
android {
+    flavorDimensions += "hoge"
+    productFlavors {
+        dev {
+            isDefault = true
+            applicationIdSuffix = ".dev"
+            dimension = "hoge"
+        }
+        stg {
+            applicationIdSuffix = ".stg"
+            dimension = "hoge"
+        }
+        prod {
+            dimension = "hoge"            
+        }
+    }
}

label(ディスプレイ名)をflavorごとに分かりやすくする

AndroidManifest.xmlにおいて、app_nameという値を使用してlabelを表示するように修正します。

android/app/src/main/AndroidManifest.xml
 <manifest xmlns:android="http://schemas.android.com/apk/res/android">
     <application
-        android:label="app"
+        android:label="@string/app_name"
         android:name="${applicationName}"
         android:icon="@mipmap/ic_launcher">

そうしたら、以下のように各Flavor名のディレクトリを用意し、flavorName/res/values/strings.xmlのようなファイルを作ります。
このとき、Flavorごとに表示したいアプリ名を入れてください。

android/app/src/dev/res/values/strings.xml
+<resources>
+    <string name="app_name">(dev)APP</string>
+</resources>
android/app/src/stg/res/values/strings.xml
+<resources>
+    <string name="app_name">(stg)APP</string>
+</resources>
android/app/src/prod/res/values/strings.xml
+<resources>
+    <string name="app_name">APP</string>
+</resources>

productFlavorsの便利なところは、Flavorのディレクトリにリソースを置いておくことで、Flavorに応じてよしなに使用されるところです。

iOS


Configurationsを複製する

プラスボタンを押すと、複製ができるので、Flavorに合わせて複製し、リネームします。

Targetsを複製する

同じようにTargetsもFlavorに合わせて複製し、リネームします。
複製時にInfo.plistも一緒に出来上がるので、Flavorごとにフォルダを用意して、配置しなおします(ここはFinderとXcodeを駆使して頑張ってください)。
Xcodeでのファイル操作が難しいと感じた場合、こちらの記事を閲覧するとスムーズに行くと思います。
https://qiita.com/naipaka/items/b73ec1fe4c7b52bcb24d

ちなみに、配置しなおす中でInfo.plistの参照が狂っても、ここで紐つけなおせます。

Testを編集する

複製をするとHost Applicationが飛んでるので、適切なTargetを選択しなおします。

また、同様に関係ないTarget(複製元)が入っているので、それも除いておきます。

Schemeを編集する

Manage Schemes ...を開いて、プラスボタンから新しいSchemeを作成します。
このとき、Test側を選んで作成しました。







Podを編集する

package_info_plusなどpodを必要とするパッケージを追加して、一旦ビルドすると、Podfileができるので、それを編集していきます。

作成したConfigurationsに合う形に編集します。

ios/Podfile
project 'Runner', {
-  'Debug' => :debug,
-  'Profile' => :release,
-  'Release' => :release,
+  'Debug-prod' => :debug,
+  'Debug-stg' => :debug,
+  'Debug-dev' => :debug,
+  'Profile-prod' => :release,
+  'Profile-stg' => :release,
+  'Profile-dev' => :release,
+  'Release-prod' => :release,
+  'Release-stg' => :release,
+  'Release-dev' => :release,
}

作成したTargetsに合う形に編集します。

ios/Podfile
-target 'Runner' do
-  use_frameworks!
-  use_modular_headers!
-
-  flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
-  target 'RunnerTests' do
-    inherit! :search_paths
-  end
-end
+target 'Prod' do
+  use_frameworks!
+  use_modular_headers!
+
+  flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
+  target 'ProdTests' do
+    inherit! :search_paths
+  end
+end
+
+target 'Stg' do
+  use_frameworks!
+  use_modular_headers!
+
+  flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
+  target 'StgTests' do
+    inherit! :search_paths
+  end
+end
+
+target 'Dev' do
+  use_frameworks!
+  use_modular_headers!
+
+  flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
+  target 'DevTests' do
+    inherit! :search_paths
+  end
+end

最後にxcconfigを編集します。

ios/Flutter/Debug.xcconfig
-#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
+#include? "Pods/Target Support Files/Pods-Dev/Pods-Dev.debug-dev.xcconfig"
+#include? "Pods/Target Support Files/Pods-Stg/Pods-Stg.debug-stg.xcconfig"
+#include? "Pods/Target Support Files/Pods-Prod/Pods-Prod.debug-prod.xcconfig"
ios/Flutter/Release.xcconfig
-#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
+#include? "Pods/Target Support Files/Pods-Dev/Pods-Dev.release-dev.xcconfig"
+#include? "Pods/Target Support Files/Pods-Stg/Pods-Stg.release-stg.xcconfig"
+#include? "Pods/Target Support Files/Pods-Prod/Pods-Prod.release-prod.xcconfig"

一旦、必要な組み合わせを全て入れましたが、pre-actionなどで、flavorに必要なものだけを使う方がいいなぁと思いつつもシンプルに行きたいのでやめました。

SPMの設定をする(2024-08-07追記)

全ては公式ドキュメントを見れば分かりますが、一応。
https://docs.flutter.dev/packages-and-plugins/swift-package-manager/for-app-developers

まずは以下のコマンドを入力して、SPMをONにします。

flutter config --enable-swift-pacakge-manager

対象のアプリケーションにurl_launcherなどを入れてdart pub getを行うと、以下のファイルが生成されます。
(余談ですが、自分はFlutter3.24.0でやれると思っており、ファイルが作成されなかったため、手動で作成しました。その後、SPMに追加がされなかったので、mainで実行して成功するアホをかましましたが、階層や名称が合っていれば動いてくれました。)

ios
└── Flutter
    └── ephemeral
        └── Packages
            └── FlutterGeneratedPluginSwiftPackage
                ├── Package.swift
                └── Sources
                    └── FlutterGeneratedPluginSwiftPackage
                        └── FlutterGeneratedPluginSwiftPackage.swift

この FlutterGeneratedPluginSwiftPackage を使用してゴニョゴニョやっていきます。

  1. RunnerのPacakgeDependenciesで追加を選択します。
  2. Localファイルからの追加を選択します。
  3. Finderが開かれるのでFlutterGeneratedPluginSwiftPackageのフォルダを選択し、Targetを入れます。
  4. 追加されると以下のように3で選択したTargetのFramework部分に追加されるので、この作業をTargetごとに実施してください。

  5. Schemeをいじります。
  6. TargetそれぞれでBuild/Pre-actionsへ以下を追加します(名称も変更しています)。

おしまいです。
PluginがSPMに対応されている場合はSPMに、そうでない場合はPodにて取得されます。

Bundle Identifier等を編集する

各Targetごとに変更したい値を編集していきます。
以下はBundle IdentifierBundle display nameの編集例です。

なぜTargetを分けたのか?

Info.plistAssets.xcassetsなど、Flavorごとに異なるリソースをシンプルに管理したかったからです。
Target Membershipを使い、リソースを参照できるTargetを絞りながら、各TargetのCopy Bundle Resourcesで読み込ませればよいので、別途スクリプトを組む必要がありません。

終劇

アイコンとかの仕分け方法も追々、記載をしていきたいと思います。

Discussion