Flutter：ビルドの種類に応じてアイコンを切り替える

https://qiita.com/daidara_bo/items/dba67f8cadeb3582aa0e

前回の記事で、Flutterにおけるビルドの切り替え方法について記載しました。
今回は、その手法を用いての、alpha or product用アイコンの切り替え方法についてをネタに書きます。

# アイコン適用方法

まず、初めに。
こちらの記事が参考になります。

https://medium.com/flutter-jp/icon-935d637d2da0

`flutter_launcher_icons`というパッケージを使います。

https://pub.dev/packages/flutter_launcher_icons

## packageのインストール
```pubspec.yaml
dev_dependencies:
  flutter_launcher_icons: "^0.13.1"

## icon設定の基本
flutter_icons:
  windows:
    generate: true
    image_path: "assets/icon/hoge.png"
    icon_size: 48
  macos:
    generate: true
    image_path: "assets/icon/hoge.png"

```

あとはいつものpub getします。
```console
$ flutter pub get
```

次に、アイコンの生成です。
```console
$ flutter pub run flutter_launcher_icons -f <your config file name here>
```
実際に箱のような感じ。
```console
$ flutter packages pub run flutter_launcher_icons:main
```
これをすると、iconが各platformごとに生成されます。

## Windows版における問題点

mac版は問題なかったのですが、Windows版において問題が１つありました。
Windows版は、icoとして生成するのですが、icoとしてアプリケーションのウィンドウの左上隅に表示したとき、`アイコンがギザギザ`としているのです。

おそらく、アイコンが内部に保持する、サイズごとの画像が内包されていないからではないか、と推測されました。

よって、windows版については別の（弊社従来の）方法でアイコンを生成して回避しました。

### ImageMagickを使ってアイコンをキレイに生成

pngをicoにするのには、既存ツールや、photoshop？あたりでコンバートは可能なのですが、実際にコンバートするとアイコンが汚い、ということがあったので、`imagemagick`をオススメします。

https://imagemagick.org/script/convert.php


**pngをicoに変換**

```
magick convert icon.png -define icon:auto-resize=16,32,64,128,256 hoge.ico
```
これで、ico用のアイコンがキレイに生成できます。都合上、アイコンの実物は割愛します。

# alpha版とproduct版のアイコンを作成する

yamlファイルをそれぞれ用意します。
- flutter_launcher_icons-alpha.yaml
- flutter_launcher_icons-product.yaml

それぞれのファイルは、こんな感じ。
```flutter_launcher_icons-alpha.yaml
flutter_launcher_icons:
  windows:
    generate: true
    image_path: "assets/icon/sample_alpha.png"
    icon_size: 256
  macos:
    generate: true
    image_path: "assets/icon/sample_alpha.png"
```

```flutter_launcher_icons-product.yaml
flutter_launcher_icons:
  windows:
    generate: true
    image_path: "assets/icon/sample.png"
    icon_size: 256
  macos:
    generate: true
    image_path: "assets/icon/sample.png"
```

pubspec.yamlはその分、一番最初に書いた部分を減らします。
```pubspec.yaml
  # icon設定
flutter_launcher_icons:
  windows: true
  macos: true
```
flavor分ける前は、サイズ設定とか書いてたけど、その部分をごそっと削除。

用意したらフォルダに配置します。
構成は下記のようになっています。
```
Project_Root
├── README.md
├── assets
│   ├── icon
│   │   ├── sample.png       // product用アイコン
│   │   └── sample_alpha.png // alpha用アイコン
.....
├── flavor
│   ├── alpha.json           // alpha用ビルド設定
│   └── product.json         // product用ビルド設定
├── flutter_launcher_icons-alpha.yaml   // アイコン生成設定
├── flutter_launcher_icons-product.yaml // アイコン生成設定
├── macos
│   │   
│   ├── Runner
│   │   ├── Assets.xcassets
│   │   │   ├── AppIcon.appiconset // flutter_launcher_icons により生成される
│   │   │   │   ├── Contents.json
│   │   │   │   ├── app_icon_1024.png
│   │   │   │   ├── app_icon_128.png
│   │   │   │   ├── app_icon_16.png
│   │   │   │   ├── app_icon_256.png
│   │   │   │   ├── app_icon_32.png
│   │   │   │   ├── app_icon_512.png
│   │   │   │   └── app_icon_64.png
│   │   │   └── Contents.json
│   │   │ 
│   │   .....
│   ├──Runner.xcodeproj // Flutterに生成されるもの
│   .....
│
├── pubspec.lock
├── pubspec.yaml
└── windows
    ├── CMakeLists.txt
    ├── flutter
    │   ├── CMakeLists.txt
    │   ├── ephemeral
    │   ├── generated_plugin_registrant.cc
    │   ├── generated_plugin_registrant.h
    │   └── generated_plugins.cmake
    └── runner
        ├── CMakeLists.txt
        ├── Runner.rc          // アイコン適用するためだったり、目的色々rcファイル
        ├── flutter_window.cpp
        ├── flutter_window.h
        ├── main.cpp
        ├── resource.h
        ├── resources
        │   ├── app_icon.ico       // 生成される
        │   └── app_icon_alpha.ico // 生成される
        ├── runner.exe.manifest
        ├── utils.cpp
        ├── utils.h
        ├── win32_window.cpp
        └── win32_window.h
```
Windows版にC++コードが入っているのは、アプリが、諸事情によりdart -> C++呼び出す構成になっているためです。本稿で特に気にする必要はありません。

icon生成のためのコマンドを打ちます。
```console
%flutter pub get
%flutter packages pub run flutter_launcher_icons:main
```
ただし、これ問題があります。

```
  ════════════════════════════════════════════
     FLUTTER LAUNCHER ICONS (v0.13.1)                               
  ════════════════════════════════════════════
  

Flavor: alpha
Creating Icons for Windows...          done
Creating Icons for MacOS...            done

Flavor: product
Creating Icons for Windows...          done
Creating Icons for MacOS...            done

✓ Successfully generated launcher icons for flavors
```
成功した、というログが出るんですが、実はこれ、**product用のアイコンしか作られてないんですよ。**
sample.pngは適用されるけど、sample_alpha.pngに関しては、生成されない。
でも、成功といっている、おそらく`バグ挙動`ではないかと思われます。

## icon生成時に、alpha & product用のアイコンがそれぞれ生成されない問題の解決方法

### アイコンがflavorごとに生成されない問題の回避方法
sample.pngにだけしか生成されないのですが、直し方は泥臭いです。
productでしか生成されないので、名前を小賢しく変更して、生成させます。
1. sample.pngでアイコンを一度生成しておき、別ファイル名として保存。
1. flutter_launcher_icons-product.yaml側で、sample_alpha.pngをsample.pngとして保存
1. sample.icnsを生成しておき、alphaへとリネーム。

これでなんとか、別々にアイコンが生成できます。
ぶっちゃけ色々面倒なので、icnsファイルを、macのプレビューアプリケーションで変換したほうが早い気もします。

### Runner.xcodeprojでアイコンが認識しない問題
各種アイコンは、Xcodeで、自動でassetsファイルとして登録されます。
ただし、その各種設定ファイルである`AppIcon.appiconset`もまた、flavorごとにファイルを分ける必要があります。

ココも自動で行ってくれないので
AppIcon.appiconsetをコピーして複製しておき、デフォルトの名前で、alphaおよびproduct用のアイコンをそれぞれ適用します。
その後、下記ファイル名へと変更します。

- AppIcon-alpha.appiconset
- AppIcon-product.appiconset

最後に、Xcodeの設定を少し変更します。
![スクリーンショット 2023-08-07 19.50.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2988173/f79f2ec3-65d1-baac-86ec-2654409b90c2.png)

こんな状態にしてから、もう一度アイコン生成をすれば、AppIconにAlpha用のアイコンを適用して、生成することができるというわけです。

生成されたらファイル名をリネーム
![スクリーンショット 2023-08-07 19.51.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2988173/ef72291d-3cac-a721-9749-dc5b6de67b8f.png)

Xcodeの設定を変更します。

![スクリーンショット 2023-08-07 19.51.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2988173/c5434097-e40f-2ed4-3656-1a70a10529a6.png)

![スクリーンショット 2023-08-07 19.52.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2988173/86c31807-d768-6bcb-c628-19c2eeb988f9.png)

`Primary App Icon Set Name`が、flavorごとの名前で適用されるように変更します。

```
AppIcon-$(flavor)
```
このflavorの要素は、設定したjsonファイルから取得して来れます。
このように、flavorごとにアイコンを変更する事ができます。

![スクリーンショット 2023-08-07 19.57.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2988173/16ca937b-3e28-8b98-d4cf-59066fdab1e7.png)


### おまけ：windows版アイコンについて

alpha or productの切り分けができていれば、Runner.rcファイルにアイコンを適用する条件分岐をかけば、切り替えができます。

```Runner.rc
/////////////////////////////////////////////////////////////////////////////
//
// Icon
//

// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
#ifdef FLAVOR_ALPHA
IDI_APP_ICON            ICON                    "resources\\app_icon_alpha.ico"
#else
IDI_APP_ICON            ICON                    "resources\\app_icon.ico"
#endif
```


# まとめ
最近だとChatGPTに色々聞いたりして解決することもあるのですが、Flutterは最新リリースも早いし、不安定な情報も多く、どうやったら？を見つけるのがそこそこ面倒です。

何か、開発の手助けになれば、良いなと思います。

補足：アイコンは、いらすとやさんのだいだらぼっちの画像を使わせていただきました。

https://www.irasutoya.com/2014/09/blog-post_389.html