permission_handler でAndroid権限を実践的に扱う(カメラ・ストレージ・Bluetooth) の次に、配布準備で手を入れることが多いのがネイティブ設定です。Flutter 側の UI ができていても、ホーム画面では初期アイコンのまま、起動時は既定のスプラッシュのまま、release build は未署名という状態で止まりやすくなります。この記事では Android 向けに範囲を絞り、アプリ名、ランチャーアイコン、スプラッシュ、リリース署名を最小構成でまとめて整えます。
1. ゴールと非対象
対象読者
- Flutter プロジェクトを作成して
flutter runした経験がある人 - Android 配布前に必要な設定をまとめて整理したい人
AndroidManifest.xml、画像生成パッケージ、署名設定の位置関係がまだ曖昧な人
この記事で到達する状態
- Android 側のアプリ名を
strings.xmlとAndroidManifest.xmlで固定できる flutter_launcher_iconsでランチャーアイコンを生成できるflutter_native_splashで起動画面を生成できるkeytool、android/key.properties、build.gradle.ktsで release 署名を設定できるflutter runとflutter build appbundleで見た目と署名付き build の入口を確認できる
非対象
- iOS のアプリ名、アイコン、Launch Screen、証明書設定
- flavor ごとのアイコンや署名の切り替え
- Play Console へのアップロード
- Firebase や Sentry など配布後の運用設定
- 独自のネイティブコード追加
今回は Android 向けの仕上げに絞ります。iOS と配布後の運用は後続記事へ分け、まずは見た目と release build の前提を固める方針です。
4〜6章の見た目調整は Flutter と Android の開発環境があれば進められます。7章のリリース署名まで進める場合は、keytool が使える Java が必要です。Android Studio を入れている場合は、同梱の Java を使えることがあります。
2. 先に全体の流れを掴む
ネイティブ設定は Flutter の Widget ツリーだけでは完結しません。今回触る場所は次の 3 層です。
flowchart LR
A[lib/main.dart] --> B[flutter run で見た目を確認]
C[flutter_launcher_icons.yaml] --> D[dart run flutter_launcher_icons]
E[flutter_native_splash.yaml] --> F[dart run flutter_native_splash:create]
D --> G[android/app/src/main/res の icon リソース]
F --> H[android の splash 設定]
I[strings.xml / AndroidManifest.xml] --> J[ホーム画面のアプリ名]
K[android/key.properties] --> L[android/app/build.gradle.kts]
L --> M[flutter build appbundle]
見る順番を先に分けておくと混乱しにくくなります。
- アプリ名は Android の文字列リソースと Manifest で決まる
- アイコンとスプラッシュは生成設定ファイルを書いてからコマンドで反映する
- 署名は release build にだけ効く設定として
key.propertiesとbuild.gradle.ktsに置く
ここで「どこを直せば何が変わるか」を先に掴んでおくと、あとで画像だけ差し替えたいときも戻り先が明確になります。
3. プロジェクトを作成し、生成用パッケージを追加する
3-1. Flutter の環境構築がまだなら先に済ませる
環境構築がまだの場合は Windows 11で始めるFlutter開発環境 を先に参照してください。
3-2. Flutter プロジェクトを作成する
次のコマンドでプロジェクトを作成します。
flutter create my_branding_app
cd my_branding_app
3-3. エミュレーターを起動する
利用可能なエミュレーター一覧を確認します。
flutter emulators
表示された ID を指定して起動します。
flutter emulators --launch <emulator_id>
3-4. パッケージを追加する
プロジェクト直下で次のコマンドを実行します。
flutter pub add --dev flutter_launcher_icons
flutter pub add --dev flutter_native_splash
役割は次の通りです。
flutter_launcher_icons: Android のランチャーアイコン画像を各解像度向けに生成するflutter_native_splash: Android の起動画面用リソースを生成する
3-5. 画像ファイルの置き場を決める
今回は次のようにそろえます。確認を進めやすいように、サンプル画像もこの記事へ同梱します。
assets/
└─ branding/
├─ app_icon.png
└─ splash_logo.png
app_icon.png: 正方形の PNG。最低でも 1024 x 1024 程度を用意すると荒れにくいsplash_logo.png: 起動画面中央に置く PNG。余白込みで 512 x 512 程度から始めると調整しやすい
今回同梱したサンプルは次の 2 点です。ボタンを押すと画像が新しいタブで開くので、内容を確認して保存できます。元データは SVG で持ち、Flutter プロジェクトでは書き出した PNG を assets/branding/ へ置く想定にしています。
- PNG: app_icon.png別タブで開く / splash_logo.png別タブで開く
- SVG 原本: app_icon.svg別タブで開く / splash_logo.svg別タブで開く
ブランド色に合わせて調整したい場合は SVG を直し、assets/branding/app_icon.png と assets/branding/splash_logo.png へ書き出して使ってください。
3-6. pubspec.yaml を更新する
flutter create した直後で、まだ依存パッケージや設定をほとんど足していないなら、この節の内容へ丸ごと置き換えて大丈夫です。すでに別パッケージや設定を追加している場合は、次の 3 点だけを既存ファイルへ反映してください。
dev_dependenciesにflutter_launcher_iconsを追加するdev_dependenciesにflutter_native_splashを追加するflutter > assetsにassets/branding/を追加する
新規作成直後に近い状態なら、pubspec.yaml は次のように更新します。
name: my_branding_app
description: "A new Flutter project."
publish_to: 'none'
version: 1.0.0+1
environment:
sdk: ^3.0.0
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^1.0.8
dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^5.0.0
flutter_launcher_icons: ^0.14.4
flutter_native_splash: ^2.4.6
flutter:
uses-material-design: true
assets:
- assets/branding/
既存の pubspec.yaml を活かしたい場合は、最低限この差分だけ入れば進められます。
dev_dependencies:
flutter_launcher_icons: ^0.14.4
flutter_native_splash: ^2.4.6
flutter:
assets:
- assets/branding/
assets 宣言を入れておくと、スプラッシュ用画像を lib/main.dart 内でも同じパスで参照できます。アイコン生成自体は Android リソースへ変換されますが、起動後の確認画面でも同じ画像を見せておくと、差し替え後のズレを見つけやすくなります。
4. Android のアプリ名を固定する
Flutter のデフォルトプロジェクトでは、AndroidManifest.xml の android:label にプロジェクト名が直接入っています。最初はそれでも動きますが、あとで表記を変えたいときに Manifest を直接直し続けるより、文字列リソースへ寄せたほうが整理しやすくなります。
4-1. strings.xml を作成する
android/app/src/main/res/values/strings.xml を次の内容で作成します。
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">Warehouse Pocket</string>
</resources>
4-2. AndroidManifest.xml の android:label を更新する
変更するのは android/app/src/main/AndroidManifest.xml の <application> タグにある android:label の 1 行です。まずは次の差分だけ押さえてください。
<!-- 変更前 -->
<application
android:label="my_branding_app"
... >
<!-- 変更後 -->
<application
android:label="@string/app_name"
... >
my_branding_app の部分は、flutter create したときのプロジェクト名になっていることがあります。そこを @string/app_name に差し替えると、4-1 で作成した strings.xml の値を参照する形に変わります。
ファイル全体で見ると次のようになります。
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application
android:label="@string/app_name"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTop"
android:taskAffinity=""
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme"
/>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<meta-data
android:name="flutterEmbedding"
android:value="2" />
</application>
</manifest>
android:label へ直接 Warehouse Pocket と書く方法でも動きます。ですが、文字列リソースへ寄せておくと、後で名称変更や多言語化を入れるときに Android 側の文字列置き場を広げやすくなります。
5. アイコンとスプラッシュを生成する
ここでは画像生成系の設定をファイルへ分けます。pubspec.yaml に直接書いても動きますが、用途ごとにファイルを分けたほうが修正箇所を追いやすくなります。
5-1. flutter_launcher_icons.yaml を作成する
プロジェクト直下に flutter_launcher_icons.yaml を作成します。
flutter_launcher_icons:
android: true
ios: false
image_path: assets/branding/app_icon.png
adaptive_icon_background: "#0F172A"
adaptive_icon_foreground: assets/branding/app_icon.png
remove_alpha_ios: true
5-2. flutter_native_splash.yaml を作成する
プロジェクト直下に flutter_native_splash.yaml を作成します。
flutter_native_splash:
color: "#0F172A"
image: assets/branding/splash_logo.png
android: true
ios: false
android_12:
color: "#0F172A"
image: assets/branding/splash_logo.png
5-3. 生成コマンドを実行する
次のコマンドを実行します。
dart run flutter_launcher_icons -f flutter_launcher_icons.yaml
dart run flutter_native_splash:create --path=flutter_native_splash.yaml
ここで反映されるのは Android のネイティブリソースです。PNG を差し替えたあとに flutter run だけを実行しても、アイコンやスプラッシュは更新されません。画像を差し替えたら、生成コマンドももう一度流す必要があります。再実行が必要な生成処理だと覚えておくと切り分けが楽です。
コードのポイント
① アイコンは foreground と background を分けておくと Android 13 以降で崩れにくい
flutter_launcher_icons:
android: true
image_path: assets/branding/app_icon.png
adaptive_icon_background: "#0F172A"
adaptive_icon_foreground: assets/branding/app_icon.png
Android では adaptive icon が使われるため、背景色と前景画像を分けておくと丸型や角丸でも見た目が安定しやすくなります。1 枚絵だけで始めるより、背景色を固定しておくほうが業務アプリのロゴ差し替えにも対応しやすい構成です。
② Android 12 以降の splash も個別に指定しておく
android_12:
color: "#0F172A"
image: assets/branding/splash_logo.png
Android 12 以降は起動画面の扱いが従来と少し変わります。android_12 ブロックを明示しておくと、端末差で見え方がずれる箇所を減らしやすくなります。
6. 確認用の lib/main.dart を作り、flutter run で見た目を確認する
lib/main.dart は次の内容で作成します。
このファイルは、起動後の確認画面として最低限の情報だけを載せたサンプルです。アプリ名、ロゴ色、次に見る確認ポイントを 1 画面に集め、ネイティブ設定を変えたあとも flutter run で動作確認しやすい形にしています。
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Warehouse Pocket',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: const Color(0xFF0F172A)),
),
home: const BrandingCheckPage(),
);
}
}
class BrandingCheckPage extends StatelessWidget {
const BrandingCheckPage({super.key});
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
return Scaffold(
appBar: AppBar(
title: const Text('Warehouse Pocket'),
),
body: ListView(
padding: const EdgeInsets.all(24),
children: [
Container(
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
color: theme.colorScheme.primaryContainer,
borderRadius: BorderRadius.circular(20),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.asset(
'assets/branding/splash_logo.png',
height: 64,
),
const SizedBox(height: 16),
Text(
'ネイティブ設定の確認',
style: theme.textTheme.titleLarge,
),
const SizedBox(height: 8),
const Text(
'アプリ名、アイコン、スプラッシュ、署名の 4 点をそろえたあとに見る確認画面です。',
),
],
),
),
const SizedBox(height: 24),
const _CheckTile(
title: 'アプリ名',
description: 'ホーム画面やアプリ一覧で Warehouse Pocket と表示されるかを確認します。',
),
const _CheckTile(
title: 'アイコン',
description: 'ランチャー上のアイコンが既定の Flutter ロゴから差し替わっているかを確認します。',
),
const _CheckTile(
title: 'スプラッシュ',
description: '起動直後に濃紺背景とロゴが表示されるかを確認します。',
),
const _CheckTile(
title: '署名',
description: 'release build が署名エラーなしで通るかを terminal で確認します。',
),
],
),
);
}
}
class _CheckTile extends StatelessWidget {
const _CheckTile({
required this.title,
required this.description,
});
final String title;
final String description;
@override
Widget build(BuildContext context) {
return Card(
margin: const EdgeInsets.only(bottom: 16),
child: ListTile(
leading: const Icon(Icons.check_circle_outline),
title: Text(title),
subtitle: Text(description),
),
);
}
}
次のコマンドで起動します。
flutter run
ここで見る場所は 2 つです。
- アプリを起動する前: ホーム画面やアプリ一覧でアプリ名とアイコンを確認する
- アプリを起動した瞬間: スプラッシュが変わっているかを見る
flutter run が通っても、ホーム画面のアイコンキャッシュが残ることがあります。その場合はアプリをいったんアンインストールしてから再インストールすると確認しやすくなります。
7. リリース署名を設定する
見た目が整っても、release build に署名がなければ配布段階で止まることがあります。ここでは Flutter 公式の Android 配布ガイドに沿って、keytool、key.properties、build.gradle.kts の 3 点をそろえます。
この章を進める前提は、keytool が使える Java が入っていることです。Android Studio を入れている場合は同梱の Java を使えることがあるため、別途 JDK を入れ直す前に flutter doctor -v で Java の場所を確認すると切り分けしやすくなります。
7-1. キーストアを作成する
まず keytool が呼べることを確認したうえで、PowerShell から次のコマンドを実行します。
keytool -genkey -v -keystore $env:USERPROFILE\upload-keystore.jks `
-storetype JKS -keyalg RSA -keysize 2048 -validity 10000 `
-alias upload
Java 17 以降では JKS 形式に対する非推奨警告が表示されることがありますが、キーストア自体はそのまま作成できます。
対話入力では、少なくとも次の 3 つを控えておいてください。
- キーストアの保存先パス: この例では
$env:USERPROFILE\upload-keystore.jks storePassword/keyPassword: 7-2 のandroid/key.propertiesでそのまま使うalias: この例ではupload
名前、組織名、都市名などの証明書情報は、まずローカルで build を通す段階なら仮の値でも進められます。あとで 7-2 に転記するときに必要なのは、パス、パスワード、alias の対応関係です。
keytool にパスが通っていない場合は、flutter doctor -v に表示される Java の場所を確認し、同じディレクトリの keytool.exe をフルパスで実行してください。
7-2. android/key.properties を作成する
android/key.properties を次の内容で作成します。
storePassword=your-store-password
keyPassword=your-key-password
keyAlias=upload
storeFile=C:\\Users\\your-name\\upload-keystore.jks
your-store-password、your-key-password、your-name はサンプル値ではなく、実際の値へ必ず書き換えます。keyAlias=upload は 7-1 の -alias upload と対応しているため、どちらかを変えた場合は両方そろえてください。
Windows では storeFile のバックスラッシュを二重にします。key.properties は機密情報を含むため、公開リポジトリへコミットしません。
7-3. .gitignore に android/key.properties を追加する
.gitignore へ次の行を追加します。
android/key.properties
キーストア自体をリポジトリ外へ置いておけば、Git 管理へ入り込むのは key.properties だけです。まずここを除外しておくと、作業中の誤コミットを防ぎやすくなります。
7-4. android/app/build.gradle.kts を更新する
android/app/build.gradle.kts では、android { ... } ブロックの前で key.properties を読み込み、signingConfigs を release に割り当てる形にします。Kotlin DSL では import をファイル先頭に置く必要があるため、plugins ブロックより前へ書きます。
この節は build.gradle.kts 全体の丸ごと置換ではなく、既存ファイルへ署名設定を追記する イメージです。既存テンプレートにある compileOptions、kotlinOptions、compilerOptions は消さずに残してください。
import java.io.FileInputStream
import java.util.Properties
plugins {
id("com.android.application")
id("kotlin-android")
id("dev.flutter.flutter-gradle-plugin")
}
val keystoreProperties = Properties()
val keystorePropertiesFile = rootProject.file("key.properties")
if (keystorePropertiesFile.exists()) {
keystoreProperties.load(FileInputStream(keystorePropertiesFile))
}
android {
namespace = "com.example.my_branding_app"
compileSdk = flutter.compileSdkVersion
ndkVersion = flutter.ndkVersion
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
defaultConfig {
applicationId = "com.example.my_branding_app"
minSdk = flutter.minSdkVersion
targetSdk = flutter.targetSdkVersion
versionCode = flutter.versionCode
versionName = flutter.versionName
}
signingConfigs {
create("release") {
val storeFilePath = keystoreProperties.getProperty("storeFile")
keyAlias = keystoreProperties.getProperty("keyAlias")
keyPassword = keystoreProperties.getProperty("keyPassword")
storeFile = storeFilePath?.let { rootProject.file(it) }
storePassword = keystoreProperties.getProperty("storePassword")
}
}
buildTypes {
release {
signingConfig = signingConfigs.getByName("release")
}
}
}
flutter {
source = "../.."
}
既存の Flutter テンプレートでは release が debug signing のままになっていることがあります。そこを自前の release 設定へ差し替えるのが核心です。
エラーになりやすい点は次の 2 つです。
import java.io.FileInputStreamとimport java.util.Propertiesをpluginsより下に書いてしまうkeystoreProperties["storeFile"]のように添字アクセスで受け取り、型が曖昧なままfile(...)へ渡してしまう
Unresolved reference: Properties や Unresolved reference: FileInputStream が出た場合は import 位置を、storeFile ... Unresolved reference: it が出た場合は getProperty("storeFile") で文字列として受け取れているかを確認してください。
Inconsistent JVM Target Compatibility Between Java and Kotlin Tasks が出た場合は、Java 側と Kotlin 側の target がずれています。既存ファイルに kotlinOptions { jvmTarget = ... } や kotlin { compilerOptions { ... } } がある場合はその設定を残し、compileOptions の sourceCompatibility / targetCompatibility も同じバージョンへそろえてください。たとえば Kotlin 側が 17 なら Java 側も JavaVersion.VERSION_17 にそろえます。
7-5. flutter build appbundle を実行する
次のコマンドを実行します。
flutter build appbundle
ビルドが通れば、署名付きの AAB は次の場所に出力されます。
build/app/outputs/bundle/release/app-release.aab
VS Code Explorer では次のように出力を確認できます。
社内配布や実機確認で APK が必要なら、次も使えます。
flutter build apk --release
ここで止まりやすい点は次の 4 つです。
keytoolが見つからないstoreFileの Windows パスで\\が不足している- Java 側と Kotlin 側の target がずれている
build.gradle.ktsを変えたあとにキャッシュが残る
Inconsistent JVM Target Compatibility Between Java and Kotlin Tasks が出た場合は、既存の kotlinOptions や compilerOptions を消さずに残したうえで、Java 側の compileOptions も同じバージョンへそろっているかを確認してください。
Gradle 側の変更後に不自然なエラーが続く場合は、flutter clean を挟んでから再実行すると切り分けしやすくなります。
8. まとめ
今回そろえたのは次の 4 点です。
strings.xmlとAndroidManifest.xmlでアプリ名を固定したflutter_launcher_iconsでランチャーアイコンを生成したflutter_native_splashで起動画面を生成したkeytool、android/key.properties、build.gradle.ktsで release 署名を設定した
ここまで整っていれば、次は環境切り替え、権限確認、release build の確認項目を配布前チェックとしてまとめやすくなります。続けて進めるなら Flutterの環境切替と配布前チェック(flavor / release build / 権限確認) を参照してください。環境構築自体を見直したい場合は Windows 11で始めるFlutter開発環境 を、Android 権限の導線を先に固めたい場合は permission_handler でAndroid権限を実践的に扱う(カメラ・ストレージ・Bluetooth) を参照してください。