概要
Flutterでアプリ開発をしていると、本番アプリ、開発アプリの名前を分けて確認したいことありますよね。
この切替には複数のSchemeを用意する方法、Flavorを使う方法、ビルド時の--releaseと--debugを使って切り分ける方法がありますが、Flutter 1.17からビルド引数の--dart-defineで定数を渡せるようになりました。今回はこの--dart-define
の方法で本番、開発それぞれのアプリをスマホ内に入れる方法を説明します。
前提
- Flutterのサンプルプロジェクトを作成しシミュレーターで実行できる
- Flutter 1.20以降
- --dart-define の設定ができる(こちらの記事を参照)
環境
$ flutter doctor
Doctor summary (to see all details, run flutter doctor -v):
[+ ] Flutter (Channel stable, 1.22.4, on Mac OS X 10.15.7 19H2 darwin-x64, locale en-JP)
[+ ] Android toolchain - develop for Android devices (Android SDK version 30.0.0)
[+ ] Xcode - develop for iOS and macOS (Xcode 12.1)
[+ ] Android Studio (version 4.1)
[+ ] Connected device (1 available)
iOS用の設定
iOSの場合Bundle identifer
でアプリを識別しています。この値が同じものだと上書きインストールされてしますので、この値を本番と開発で変える必要があります。
Flutterの設定
以下のように、コンパイル引数で渡します。
開発用
flutter build ios --dart-define=DEFINE_IOS_SUFFIX=.dev
本番用
flutter build ios --dart-define=DEFINE_IOS_SUFFIX=
※ --dart-define の基本的な設定についてはこちらの記事を見てください。(記事中のInfo
>Custom iOS Target Properties
は設定せず、下記'Xcodeの設定'を参考に設定してください)
Xcodeの設定
Build Settings
のPackaging
にあるProduct Bundle Identifier Debug
の値をダブルクリックし、もともとの値の後ろに$(DEFINE_IOS_SUFFIX)
を追加します。
Runner/Info.plist
のInformation Property List
にあるBundle name
にあるもともとの値の後ろに$(DEFINE_IOS_SUFFIX)
を追加します。
動作確認
開発用、本番用、それぞれ実行してみてください。
どうでしょうか?スクリーンにDEFINE_IOS_SUFFIX
のついたBundle Identifer
が表示されたでしょうか。また、ホームスクリーンにも2つのアプリが入ったと思います。
※ 元の名前が長くて「flutter_define...」となってしまいました。
Android用の設定
Androidの場合はapplicationId
によってアプリが識別されます。この値を本番と開発とで変えていきます。
Flutterの設定
以下のように、コンパイル引数で渡します。
開発用
flutter build apk --dart-define=DEFINE_APP_NAME=flutter_define_dev --dart-define=DEFINE_APP_SUFFIX=dev
本番用
flutter build apk
Gradleの設定
[project]/android/app/src/main/AndroidManifest.xml
にあるandroid:label
を修正します。
<application
android:name="io.flutter.app.FlutterApplication"
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher">
[project]/android/app/build.gradle
を以下のように修正します。
// 〜〜 省略 〜〜
def flutterVersionName = localProperties.getProperty('flutter.versionName')
if (flutterVersionName == null) {
flutterVersionName = '1.0'
}
// ここから追記 --
def dartEnvironmentVariables = [
DEFINE_APP_NAME: 'flutter_define',
DEFINE_APP_SUFFIX: null,
];
if (project.hasProperty('dart-defines')) {
dartEnvironmentVariables = dartEnvironmentVariables + project.property('dart-defines')
.split(',')
.collectEntries { entry ->
def pair = URLDecoder.decode(entry).split('=')
[(pair.first()): pair.last()]
}
}
// ここまで追記 --
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
// 〜〜 省略 〜〜
android {
defaultConfig {
applicationId "com.yana1316.flutter_define"
applicationIdSuffix dartEnvironmentVariables.DEFINE_APP_SUFFIX // 追記
minSdkVersion 16
targetSdkVersion 29
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
resValue "string", "app_name", dartEnvironmentVariables.DEFINE_APP_NAME // 追記
}
動作確認
開発用、本番用、それぞれ実行してみてください。
どうですか?スクリーンにapplicationId
が表示されたかと思います。また、アプリも2つ入りました。
まとめ
以前はFlavorや複数のShceme、--target
オプションや--rerease
と--debug
オプションなどを使って切り替えていました。Flutter1.17から導入された--dart-define
を使うとシンプルに切り分けができたかと思います。
組織で開発をするときはBitriseやfastlaneが既に導入され、自動的に便利に開発できることも多いと思います。一方、個人開発や初めてFlutterを導入する場合にて、この程度の切り分けがちょうどよいケースもありますので、参考になればと思いました。