flutter create してから5日で iPhone / Androidアプリを公開した話

Twitter を見ていたら、 「Eテレでドット絵を使ったエンコードとデコードの説明をやっていた」とのツイートを見つけ、ふと、「これ、うちの子もやったら勉強になるんじゃないかなー」と思ったので Flutter でアプリにしてみました。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">これいいな。うちの子（4歳と3歳）にもできる、こんな感じのゲーム感覚でデータ構造の基本が身に付く系のやつあるかな。作るかな。 <a href="https://t.co/Yda6vvoi5x">https://t.co/Yda6vvoi5x</a></p>&mdash; ちゅーやん - Tsuyoshi Chujo (@chooyan_i18n) <a href="https://twitter.com/chooyan_i18n/status/1181388504296652801?ref_src=twsrc%5Etfw">October 8, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

実際に公開したアプリがこちらです。

[ドット絵でおぼえるエンコードとデコード - App Store](https://apps.apple.com/app/id1482741418)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134943/4d314e5e-f448-c173-ab1f-e5065116a181.png)

上のツイートの直後から開発を初めて5日間で公開までできたので、具体的にどんなことをやったのかを1日ずつ振り返りながらこの記事にまとめてみたいと思います。

個人でアプリを作って公開してみたい方や、仕事で初めて Flutter アプリ開発をしようとしている方が、アプリ開発開始から公開までの流れをイメージする参考になれば嬉しいです。

なお、コードは以下に公開しています。

[chooyan-eng/endecode - GitHub](https://github.com/chooyan-eng/endecode)

ではどうぞ。

# 0日目

前提として、開発を開始する前に以下は完了していました。

## Apple デベロッパー登録

[登録 - サポート - Apple Developer](https://developer.apple.com/jp/support/enrollment/)

iPhone アプリを公開するには年1万円払って開発者登録しなければならない、とはおそらくアプリを公開したいと思った方なら聞いたことがあるの話なのではないかと思います。それです。

上のリンクに説明されている内容に従い、自分の (2段階認証を有効にした) Apple ID でサインインし、デベロッパ情報（法人の場合は法人の情報）を入力して支払いのためのクレカ情報を入力すると作業完了です。

審査の後、問題がなければメールがきて登録完了です。
通常2営業日以内に完了するらしいのですが、僕の場合は2営業日経っても音沙汰なく、問い合わせからさらに2営業日たってようやく登録完了でした。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">あと5分くらいで48時間たつけどステータスがpendingのまま変わらない、、、 <a href="https://t.co/iqgODkGaHv">https://t.co/iqgODkGaHv</a></p>&mdash; ちゅーやん - Tsuyoshi Chujo (@chooyan_i18n) <a href="https://twitter.com/chooyan_i18n/status/1148225040866934784?ref_src=twsrc%5Etfw">July 8, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

## Android デベロッパー登録

[Play Console の使用方法 - Play Console ヘルプ](https://support.google.com/googleplay/android-developer/answer/6112435?hl=ja)

Android アプリを公開するためには上のページを参考にしながら Android のデベロッパー登録をする必要があります。

こちらは登録料3,000円くらいを1度払うのみで、審査等もなかった（と思う）のですぐに登録できます。

## Flutter の環境構築

[Install - Flutter](https://flutter.dev/docs/get-started/install)

上のリンクを参考に、Flutter の環境構築を済ませます。

Flutter ( Dart も含まれる) のインストール、VSCode, Android Studio, Xcode のインストール、 Flutter / Dart 各プラグインのインストールなどを順番にしていきます。さすがに Android, iOS 両方の開発環境に加えて Flutter 用の開発環境のインストールが必要ということもあり、なかなかやることが多いです。頑張りましょう。

僕は仕事ですでに Flutter を使っていたため、今回は環境構築済みでした。

# 1日目

以上、0日目の内容はすでにできていたところから、1日目がスタートです。

## どんなアプリにするかを考える

まずは要件定義的な部分ですが、冒頭のツイートにあったような、「ドット絵を数字に変換（エンコード）して、その数字を基にドット絵が復元（デコード）できる」ことがうちの子たち（3歳と4歳）に伝わればいいかな、程度だったため、機能として以下を作ることにしました。

* ドット絵を描く機能
* ドット絵を独自ルール（元ツイートの画像から推測）で数列に変換する機能
* 数列を保存する機能
* 保存した数列を一覧する機能

## コーディングする

機能が決まったら `flutter create` して早速コーディング開始です。

10分くらいで 16 * 16 の白黒のドット絵が書けるようになり、1時間程度で数列への変換ができるようになり、その日のうちには保存と一覧表示、エンコード画面とデコード画面のつなぎこみ、シェアなど、一通りアプリとして使えるくらいにはできあがりました。 Flutter の開発効率に感動です。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">ひとまずここまで。自分で打ったドット絵から作ったデータ保存して、それを見ながら今度はドット絵に戻すところまで。<br><br>ここまで作って TestFlight に配信するまで半日って Flutter 効率良すぎではなかろうか。しかも Android でも動かせる。 <a href="https://t.co/cVgBh9XW1T">pic.twitter.com/cVgBh9XW1T</a></p>&mdash; ちゅーやん - Tsuyoshi Chujo (@chooyan_i18n) <a href="https://twitter.com/chooyan_i18n/status/1181523285328064512?ref_src=twsrc%5Etfw">October 8, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

## iOS向けアイコンを作る

やはりアイコンがあるだけで「ちゃんとしたアプリ感」が全然違う、ということで、アイコンの作成もこの日のうちにやっています。アイコンはイラレで丸と四角を駆使して適当に作りました。
できあがったものはストアをご参照ください。（特にここに書くほどの内容は無いです）

なお、アイコンはプラグインなど使わず、直接 Xcode の `Assets.xcassets` にセットしています。

## Codemagic を設定する

[Codemagic - CI/CD for Flutter](https://codemagic.io/start/)

Push をトリガーにビルドと配信を自動化するため、 Codemagic を利用しています。まずは iOS だけ設定します。

### GitHub との連携

Codemagic の利用はとても簡単で、 GitHub アカウントでサインアップした後に連携したいリポジトリを選択するだけです。これだけでデバッグビルドして成果物（APKファイルやIPAファイルなど）をダウンロードできるようになります。

### ビルド設定を変更する

今回、 Codemagic は完全にストアアップ用に利用するため、ビルドの設定を

* Android / iOS のみ
* リリースビルド

に変更します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134943/ac791d40-ab1f-655f-84bb-55329b12cebb.png)

Android は "Build Android App Bundles" にチェックを入れるのを忘れないようにしてください。
最終的にストアにアップするのは APK ではなく App Bundle を利用しますが、デフォルトでは App Bundle がビルドされない設定になっているため、ここで忘れずチェックを入れます。

### リリース設定を変更する

iOS アプリを自動で署名し、 App Store Connect へアップできるようにするため、 iOS の配信設定を変更します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134943/97b55189-4876-18a0-d6fb-ecc5898a5061.png)

が、その前に設定に必要になる certificate ファイル、 provisioning ファイルをそれぞれ Apple のアカウント設定画面から作成しておきます。

[Certificates, Identifiers & Profiles - Apple Developer](https://developer.apple.com/account/resources/certificates/list)

1. 開発者と権限を証明する Certificates
2. アプリのIDや機能などの情報を保持する Identifiers
3. アプリの配信先などを保持する Profiles

の順に作成します。このうち 1 と 3 を Codemagic に登録します。

## App Store Connect の設定

App Store Connect の方にも、アプリのストア情報などを入力をするための枠を作っておきます。

[マイ App - App Store Connect](https://appstoreconnect.apple.com/WebObjects/iTunesConnect.woa/ra/ng/app)

細かな作り方は割愛しますが、ここで上記 2 で作った Identifiers を利用します。

ここまでが1日目です。 Flutter の開発効率と Codemagic の自動ビルド & アップロードがとても良い仕事をしてくれました。

# 2日目

2日目は引き続きコーディングです。

ドット絵のマスの数を選べるようにしたり、編集機能をちゃんと作ったり、見た目を整えたり、残っていた細かい部分を整えていきます。

具体的には[コミットログ](https://github.com/chooyan-eng/endecode/commits/master)をご参照ください。

# 3日目

## 仕上げ

UIの調整、シェアされたデータのインポート、削除などの残りを仕上げます。
こちらも[コミットログ](https://github.com/chooyan-eng/endecode/commits/master)をご参照ください。

## Android のアイコン作成とビルド設定

### アダプティブアイコンの作成

[Adaptive icons | Android Developers](https://developer.android.com/guide/practices/ui_guidelines/icon_design_adaptive)

Android は　OS バージョン8.0 以降の端末向けに「アダプティブアイコン」が別途必要になるため、作ります。
ちょうどいい感じに表示されるサイズ感がわからないため若干面倒でした。

### Android のビルド設定

[Preparing an Android app for release - Flutter](https://flutter.dev/docs/deployment/android)

Android はリリースビルドのためにいくつか設定ファイルの修正が必要です。
上記のページに従って署名ファイルの作成やリリースビルドの設定、難読化の設定などを行います。

また、プロジェクト側の設定が完了したら、次は Codemagic 側もリリースビルドの設定と配信設定をしていきます。

特に Play Store への配信設定のためにはリリース権限を持ったユーザーの作成などの作業が必要になるため、以下のドキュメントを読みながらユーザーの設定と JSON ファイルのダウンロードを進めます。

[Publishing to Google Play - Codemagic](https://docs.codemagic.io/publishing/publishing-to-google-play/)

## 申請

アプリがだいたい形になり、 Codemagic も設定できたらアプリをビルド＆ストアへアップして Android / iOS それぞれのコンソール画面から申請します。

ストアの申請には下準備として以下が必要になります。

### Android / iOS 共通

* ストア文言
    * アプリ名、アプリの説明文など。頑張って作文します。
* キャプチャ画像
    * Android, iOS それぞれのエミュレーターで保存していきます。タブレットなど複数の画像サイズで取る必要があるので地味に面倒です。
* プライバシーポリシー
    * 今回のアプリは通信も一切せず広告も出さないため個人情報と言える情報も何もとらないのですが、特に iOS の方は必須だったため専用のページが必要です。
    * 今回は GitHub Pages を利用して[こちら](https://chooyan-eng.github.io/EndecodePages/privacy.html)につくりました。
    * プライバシーポリシーの文章はググって出てきたテンプレートを微調整して掲載しています。もし将来情報取ることになった場合はこれに従うよ、という内容になっています。

### Android 
* 1024px * 500px の「フィーチャー グラフィック」画像
    * ストアに特集された時に使われる（と思われる）横長の画像です。
    * 今回のアプリがフィーチャーされることはおそらく無いため、イラレで適当に作ります。

### その他
Android / iOS とも、あとはストアの案内通りにカテゴリや連絡先、年齢制限や価格などを入力していきます。

すべて入力できたら iOS は審査に提出、 Android はベータ版（いきなりリリースで良い場合は製品版）にリリースをします。
どちらのプラットフォームも審査が入るため、一旦この日はここまでです。

# 4日目

## iOS リジェクト対応

最近の App Store の審査はとてもスピーディーになり、1日あれば審査してくれることもあります。
今回のアプリも申請した夜中（サンフランシスコのお昼ごろ）に審査をしてくれたらしく結果が出ていました。

が、結果は「拒否」とのことで、以下の2点が原因でした。

### ストア画像に Flutter の "DEBUG" ラベルがついている

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134943/186bea25-4a49-1663-d5a1-bf4c8ff9bb55.png)

こいつですね。完全に忘れていました（というか気づいたのですがきっと大丈夫直すのも面倒臭いし、と思って放置していました。ダメでした。）

[How to remove debug banner in flutter on android emulator? - Stackoverflow](https://stackoverflow.com/questions/48893935/how-to-remove-debug-banner-in-flutter-on-android-emulator)

こちらのページを参考に、以下のコードを追加してラベルを消し、再度キャプチャを取ってストアにアップします。

```dart
MaterialApp(
  debugShowCheckedModeBanner: false
)
```

### 外部へのリンクにペアレンタルコントロールがない

今回は「キッズ」カテゴリに申請しているため、外部へのリンクや広告にも厳しい制限がかけられます。で、その1つが「外部リンクを子供がタップできないようにする」というものです。

[https://developer.apple.com/app-store/parental-gates/](Parental Gates - App Store - Apple Developer)

要は、子供には分からない質問を出し、正解した場合だけ外部リンクを開くことができるようにする、というものです。

今回はドット絵をエンコードして作った数列のシェア機能がこれにあたるとのことだったので、シェアボタンを押した時に以下のようにランダムで掛け算の問題を出すようにしました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134943/cd236bde-78de-b703-32bb-9080d5fb2486.png)

というかシェア機能（OS の別アプリを呼び出すだけ）も「外部リンク」に当たるんですね。ペアレンタルゲートについては認識していましたが、アプリ連携が該当することは頭から抜けていました。

以上2点を修正し、再申請。

# 5日目

## iOS 申請通過と公開

またしても1日で審査してくれ、さらに問題もなかったとのことで無事通過し、公開されていました。（審査通過したら自動で公開の設定にしていたため）

ということで iOS はこれでひと段落、子供の iPad でもインストールできるようになりました。

# その後

~~Android はまだ審査が終わらないのか、ステータスが「公開待ち」のままベータテストもできずストアにも公開されていない状態です。人によるチェックが入るのであればおそらく週が明けて1, 2日たてばステータスも変わるかと思いますが、~~

(2019.10.16 追記)
[Android もストアに公開されました！だいたい5営業日くらいかかりました。

[ドット絵でおぼえるエンコードとデコード - Google Play](https://play.google.com/store/apps/details?id=jp.co.chooyan.endecode)

公開されるとこんな感じのメールがくるようです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134943/6147fd78-cca4-1ccc-603f-78a88907ed6c.png)
(追記ここまで)

このあたりのスピード感は昔と比べて完全に iOS と Android で逆転してしまった印象です。（昔は審査がなかったので「公開」ボタンポチから1時間程度で公開されていました）


アプリの完成度としては、まだまだ口頭で補足しながらでないと遊べるモノではないため、時間を見つけてコツコツバージョンアップしていければな、と思います。

自分の子がちょうどいろいろ覚え始めている時期なので、この手の子供向けの学習アプリはこれからも色々作っていきたいと思っていて、そういう細かなアプリを1人でサクッと作るのに Flutter は最適だな、と思っている今日この頃です。オススメです。

# まとめ

というわけで、この記事では Flutter を使ってアプリを開発・公開する流れをざっと書いてみました。
最初にも書きましたが、アプリを作り始めてから公開までの大まかな流れをイメージする手助けになれたらとても嬉しいです。

細かなところはいろいろと割愛しているため、「ここもっと詳しく書いて」などありましたらコメントください。追記したり別の記事に書いてみたいと思います。
また、もっと効率的に開発・公開を進められるツールやプラグインなどありましたらぜひ教えてください。

ついでにこのアプリの機能追加や UX の向上などがあればプルリクいただけるととても嬉しいです。お待ちしています。

https://github.com/chooyan-eng/endecode