`ionic start`の"aws"って何なの？ - ionic-angular AWS Mobile Hub Starterを使ってみた

:christmas_tree: オープンストリーム Advent Calendar 2017 の 9 日目です :santa: :christmas_tree: 

# `ionic start`の"aws"って何なの？

みなさんは `ionic start` でIonicのプロジェクトを始めるとき、"aws"の文字を見て気になったことはありませんか？:confused:

<img width="614" alt="ionic start aws" src="https://qiita-image-store.s3.amazonaws.com/0/216963/91f342c3-0852-ae03-6012-4d96773ea144.png">

そうです、これです。
**"ionic-angular AWS Mobile Hub Starter"** とありますね。

今回はこの "aws" で生成されるIonicプロジェクト(Starter)について見て・触れてみようと思います。


## AWS Mobile Hubとは？

先ほどの通り `ionic start`の"aws"で生成されるプロジェクトは **AWS Mobile Hub** に関係するプロジェクトです。

AWS Mobile Hubとは、ブラウザの操作だけでAWSを用いたモバイルアプリ開発がすぐスタートできるサービスになります。

画面は英語表記ですが(2017/12現在)、AWSのサービス名を知らなくとも、
:grinning:「Facebookのアカウント一つでアプリが使えるようにしたい！」
:smiley_cat:「スマートフォンで通知を受け取るアプリを作りたい！」
など、実現したいことに従ってクリックするだけで、AWSのサービスが展開されて機能がすぐに実現できます。

**「モバイルアプリケーションを最短の時間で構築する方法」**とある通りですね！

AWS Mobile Hubの詳細はこちらになります。

AWS Mobile Hub（モバイルアプリケーションの構築、テスト、モニタリング）| AWS 
https://aws.amazon.com/jp/mobile/

なお、Mobile Hubを実際に使った説明やサンプルは他の記事に譲ります。


# プロジェクト開始直後を見てみる

`blank` を選んだときと比べ、プロジェクトのルートには `cors-policy.xml`, `mobile-hub-project.zip` が追加されています。

`mobile-hub-project.zip` は、このプロジェクトで使うAWSのリソースの設定が格納されています。
このプロジェクトのためにAWSをセットアップするために必要となります。

```bash
$ ls -l
-rw-r--r--    1 ysd  staff    3622 Dec  7 14:00 README.md
-rw-r--r--    1 ysd  staff    6173 Dec  7 23:02 config.xml
-rw-r--r--    1 ysd  staff     539 Dec  7 14:00 cors-policy.xml
-rw-r--r--    1 ysd  staff     113 Dec  7 23:02 ionic.config.json
-rw-r--r--    1 ysd  staff     775 Dec  7 14:00 mobile-hub-project.zip
drwxr-xr-x  470 ysd  staff   15980 Dec  7 23:02 node_modules
-rw-r--r--    1 ysd  staff  174985 Dec  7 23:02 package-lock.json
-rw-r--r--    1 ysd  staff    1125 Dec  7 23:01 package.json
drwxr-xr-x    7 ysd  staff     238 Dec  7 23:02 resources
drwxr-xr-x   10 ysd  staff     340 Dec  7 23:01 src
-rw-r--r--    1 ysd  staff     576 Dec  7 14:00 tsconfig.json
-rw-r--r--    1 ysd  staff     178 Dec  7 14:00 tslint.json
```

さらに `src/assets` の中にあらかじめAWSのJavaScript SDKが入っていました。

```bash
$ ls -l ./src/assets
total 10712
-rw-r--r--  1 ysd  staff    43875 Dec  7 14:00 amazon-cognito-identity.min.js
-rw-r--r--  1 ysd  staff   317909 Dec  7 14:00 amazon-cognito-identity.min.js.map
-rw-r--r--  1 ysd  staff   510404 Dec  7 14:00 aws-cognito-sdk.js
-rw-r--r--  1 ysd  staff   259601 Dec  7 14:00 aws-cognito-sdk.min.js
-rw-r--r--  1 ysd  staff   346715 Dec  7 14:00 aws-cognito-sdk.min.js.map
-rw-r--r--  1 ysd  staff  2658078 Dec  7 14:00 aws-sdk.js
-rw-r--r--  1 ysd  staff  1285371 Dec  7 14:00 aws-sdk.min.js
drwxr-xr-x  3 ysd  staff      102 Dec  7 23:01 icon
drwxr-xr-x  3 ysd  staff      102 Dec  7 23:01 imgs
-rw-r--r--  1 ysd  staff    51794 Dec  7 14:00 ionic-aws-logo.png
```

プロジェクトのルートに配置されるファイルと `package.json` で導入されるパッケージから、 https://github.com/ionic-team/starters/tree/master/ionic-angular/official/aws の内容が展開されるようです。


# AWS Mobile Hub Starterを使ってみる

次に、プロジェクト同梱の `README.md` に従ってAWS Mobile Hub Starterを使ってみましょう。

## pip, AWS CLIをインストールする

この後のステップでAWS CLIが必要になります。ターミナルを開いて次のコマンドを実行します。

```bash
$ pip install --upgrade pip
$ pip install awscli
```

## Mobile Hub を始める

このサンプルで使うAWSのリソースをセットアップするために AWS Mobile Hub を使います。Mobile Hubでプロジェクトを作成し、このプロジェクトで使う/作成するAWSのリソースをまとめます。

Mobile Hubのコンソールを開くとプロジェクトの一覧が表示されます。ここで目につく Create や + Create Project を押したくなりますが、その隣の `Import` ボタンをクリックします。

<img width="808" alt="Mobile Hub top" src="https://qiita-image-store.s3.amazonaws.com/0/216963/f090bffc-0efe-7532-12bf-e1fec2cb2be3.png">

Importボタンを押すと、次のようにimportするプロジェクトの設定画面が表示されます。
ここで `mobile-hub-project.zip` を使います！ 

"Import your Mobile Hub project zip file" にある "You can also drag and drop your file here" にこの `mobile-hub-project.zip` をドラッグします。

<img width="617" alt="Mobile Hub Import" src="https://qiita-image-store.s3.amazonaws.com/0/216963/a969a05f-7972-a309-2ee1-a9a18bb634db.png">

AWS Mobile Hub Starterで使うAWSのリソースが `mobile-hub-project.zip` にあらかじめ記述されているため、このファイルからプロジェクトをインポートすることでAWSのリソースをセットアップできます。

その他の項目は次の通りになります。

 - Enter a name for your Mobile Hub project: Mobile Hubのプロジェクト名になります。 `ionic start` で設定したプロジェクト名でも可能です
 - Allow AWS Mobile Hub to administer resources on my behalf: Mobile HubでAWSのリソースをセットアップできるようにチェックを入れます
   - 既にMobile Hubを使っている場合は表示されないことがあります
 - Resources for your project will be created: リージョン名をクリックすると、Mobile HubでセットアップされるAWSのリソースのリージョンを指定することができます

設定例としてこのようになります :bulb: 

<img width="609" alt="Mobile Hub import sample.png" src="https://qiita-image-store.s3.amazonaws.com/0/216963/3e8cbaae-5a52-da11-1ebd-d96f3ac8a450.png">


設定値を入力したら `Import project` ボタンをクリックします。
**クリックするとAWSのリソースが一括で作成されます。1-2分ほどかかります。**

完了するとMobile Hubのプロジェクトが開きます。

![](https://qiita-image-store.s3.amazonaws.com/0/216963/903cf2fb-3280-2abc-2dcd-7c21d40e3705.png)


ここで作成されたAWSのリソースを見ると、
Amazon Pinpoint のプロジェクトが作成され…………(プッシュ通知などに使います)
<img width="398" alt="" src="https://qiita-image-store.s3.amazonaws.com/0/216963/e899edb6-dca1-3437-a054-94930b54162a.png">

Amazon Cognitoのユーザープールが作成され…………(ユーザーの認証などに使います)
<img width="595" alt="" src="https://qiita-image-store.s3.amazonaws.com/0/216963/381964f1-b3ef-0453-1997-76026049ff04.png">

Amazon Cognitoのフェデレーティッドアイデンティティが作成され…………(ユーザーの認証などに使います)
<img width="690" alt="" src="https://qiita-image-store.s3.amazonaws.com/0/216963/aa69e48b-38b5-6331-dda6-e9c6d41109fb.png">

Amazon S3のバケットが3つ作成され…………(アプリの配布やユーザーデータの保存などに使います)
<img width="1353" alt="" src="https://qiita-image-store.s3.amazonaws.com/0/216963/90e4cf96-c744-1e3c-bda8-75eeceab49b6.png">

Amazon CloudFrontのディストリビューションが作成され…………(アプリの配布などに使います)
<img width="1619" alt="" src="https://qiita-image-store.s3.amazonaws.com/0/216963/4f3b1054-1dac-4fcd-24b9-4255452a17d9.png">

Amazon DynamoDBのテーブルが作成され…………
<img width="1016" alt="" src="https://qiita-image-store.s3.amazonaws.com/0/216963/fa2696aa-21f5-3ecf-9bab-534ec9954261.png">

IAMロールが4つ作成されました。

<img width="1708" alt="" src="https://qiita-image-store.s3.amazonaws.com/0/216963/89f658eb-d2ab-eb98-8269-519f0565fd13.png">


通常はこのMobile Hubの画面で各項目を一つずつクリックして設定するところ、このAWS Mobile Hub Starterを使うことで一度に設定できます。

~~恐ろし…~~ 一通りそろって便利ですね！ ※この段階では無料利用枠に収まります。

料金 - AWS Mobile Hub | AWS
https://aws.amazon.com/jp/mobile/pricing/


### AWS Mobile Hub Starterでセットアップされないリソース

先ほどの方法でMobile Hubがセットアップしないリソースは次の2つです。

 - Cloud Logic: Amazon API Gateway + AWS Lambda
 - Conversational Bots: Amazon Lex

Cloud Logicはモバイルアプリから送信されたデータを、サービス側で処理する……構造が実現できます。
一方のConversational Botsは、自動で会話できるチャットボットを作成するサービスになります。2017/12現在で米国英語のみの対応になりますが、アプリと会話して注文を受け付ける機能 :shopping_bags: などが実現できます。


## Mobile Hubから `aws-config.js` をダウンロードする

しかし、設定はまだ終わっていません。 **先ほど作成されたS3バケットが次の設定で重要になります。**

<img width="1353" alt="" src="https://qiita-image-store.s3.amazonaws.com/0/216963/90e4cf96-c744-1e3c-bda8-75eeceab49b6.png">
(再掲)

`hosting-mobilehub` を含むS3バケットの名前を記録します。
そして、Ionicのプロジェクトに戻り、 `BUCKET_NAME` を先ほどのS3バケットの名前に置き換えて `aws-config.js` をダウンロードします。

```bash
aws s3 cp s3://BUCKET_NAME/aws-config.js src/assets
```

この例では次の通りになります。

```bash
$ aws s3 cp s3://myawsionic-hosting-mobilehub-1404708309/aws-config.js src/assets
download: s3://myawsionic-hosting-mobilehub-1404708309/aws-config.js to src/assets/aws-config.js
```

この、 `aws-config.js` はMobile Hubで作成されたAWSリソース達のARNが記録されています。
「モバイルアプリがアップロードしたファイルをどこのS3バケットに配置すべきか」などが決まります。


## ユーザーがS3バケットにファイルをアップロードできるようにする

AWS Mobile Hub Starterの初期状態は、アプリを使っているユーザーがS3バケットにファイルをアップロードできる機能がありますが、この機能を使うためにはアップロード先のS3バケットで設定が必要になります。

`userfiles` を含むS3バケットを開きます。
次に、アクセス権限 -> CORSポリシー を開き、 `README.md` で説明された内容 もしくはプロジェクトルートにある `cors-policy.xml` の内容に差し替えて「保存」ボタンをクリックします。

<img width="1154" alt="userfiles S3 CORS setting" src="https://qiita-image-store.s3.amazonaws.com/0/216963/8ae44a49-814e-f402-9def-13a2aa106abc.png">


## 実行する

プロジェクトのルートで `ionic serve` を実行するとブラウザで動きを確認することができます。

### ユーザーアカウントの登録

`ionic serve` 実行後に開くブラウザではログイン画面が表示されますが、AWSやIonic Proのアカウントを入力するわけではなく、このアプリ用のユーザーアカウントを登録します。

<img width="440" alt="Login screen" src="https://qiita-image-store.s3.amazonaws.com/0/216963/baa187ca-96e7-d495-056a-657c6553bdb5.png">


"Create one."のリンクをクリックし必要な項目を入力するとアカウントの登録ができますが、**次のステップで確認コードがメールで送られてそれを入力する必要があるため**メールアドレスが適当すぎると詰みます。
(詰んだ場合はブラウザをリロードするとログイン画面に戻ります)

<img width="439" alt="email confirm screen" src="https://qiita-image-store.s3.amazonaws.com/0/216963/8d31fcf6-d501-9902-5462-e630f7de3a5d.png">


ユーザー登録完了後は特に何も表示されることなくログイン画面に遷移します。

ここで Amazon Cognitoのユーザープールを見るとユーザーが作成されていることや、確認コード入力の時点で詰んだことがわかります。

<img width="1137" alt="Cognito User Pool" src="https://qiita-image-store.s3.amazonaws.com/0/216963/b3a69560-721b-3ab3-dfb1-4d2f83a8333a.png">


### タスクを追加する

ログインできると"Tasks"の画面が表示されます。

![tasks screen](https://qiita-image-store.s3.amazonaws.com/0/216963/169a33d8-2640-8ba4-2b92-75167b75be5d.png)

右上にある 「+」 ボタンをクリックして項目を追加できます。

![input tasks screen](https://qiita-image-store.s3.amazonaws.com/0/216963/bd6ab661-3522-a3c9-51e3-50567d382641.png)

![inputed tasks screen](https://qiita-image-store.s3.amazonaws.com/0/216963/c135e1aa-0763-944f-f58c-44494bb88eb6.png)

項目を追加した後にAmazon DynamoDBを見ると、データベースに先ほどの内容が記録されていることが分かります。

<img width="1119" alt="DynamoDB Table Contents" src="https://qiita-image-store.s3.amazonaws.com/0/216963/9be26c58-f7a5-1ffd-47db-0a61452391b5.png">


### ユーザーの写真を更新する

Settings -> Account を開き，「CHANGE PHOTO」をクリックするとユーザーの写真を更新することができます。

![account edit screen](https://qiita-image-store.s3.amazonaws.com/0/216963/d6e74ba6-9914-e91e-f6a9-57ca0a233f12.png)


正しく更新されると即時反映されます。反映されない場合はS3バケットのCORSポリシーの設定を再度確認します。

ここでは `userfiles` を含むS3バケットを見るとユーザーの写真がアップロードされていることが分かります。 `protected` のディレクトリにあります。


# 結論(`ionic start`の"aws"って何だったの？）

AWSのサービスを用いたToDoアプリができるひな形になります。

Settings -> About this app を確認すると、実際に次のサービスが使われている旨が表示されます。

 - Cognito
 - DynamoDB
 - S3

言い換えると、AWS Mobile Hub StarterからIonicのプロジェクトをスタートすると、この3つのサービスがアプリ内ですぐに利用できます。

AWS Mobile Hub Starterを動かすだけで長くなりましたが、Ionicを使うと少し手を動かすだけで

 - ユーザー登録時に確認コードでメールアドレスの所在が保証でき
 - DynamoDBでクラウドに内容が保存できる
 - ToDoアプリ

が作れました！ :smiley: 


# おわりに

……と言いたいのですが、動かしただけではAWS Mobile Hub Starterからどのようにアプリにしていくのか分かりにくいですね？

そこで、この先は **AWS Mobile Hub Starterで用意されたAmazon PinpointとFirebaseを組み合わせてAndroidのプッシュ通知を受け取るサンプル** を作ろうとしましたが、

AWSブログにて紹介されている方法でFirebaseの送信者IDを入れると、トークン取得の段階で次のエラーが出て正しく動作させることができませんでした。

> console.error: Error with Push pluginError: AUTHENTICATION_FAILED


Push Notifications with Ionic and Amazon Pinpoint | AWS Mobile Blog
https://aws.amazon.com/jp/blogs/mobile/push-notifications-with-ionic-and-amazon-pinpoint/


その他の方法を調べましたが、Androidのビルド環境の問題なのかビルドができませんでした :confused: 


Mobile HubでセットアップされるAWSの各サービスのドキュメントを読んでも、先ほどのAWSブログ以外にIonicを用いた実装例が見つかりませんでした。
そのため、「せっかく用意したPinpointでプッシュ通知を使ってみたい」「メールアドレスではなくFacebookとCognitoとIonicでユーザー登録を実現したい」など、IonicのAWS Mobile Hub Starterのコードで用意された範囲を超えるのは非常に難しい印象でした(個人の感想です)


紹介できなかったCloud Logicについても試してみたかったのですが、次回の機会に……

翌日 10 日目は @granoeste さんです！


# セットアップしたAWSリソースのクリーンアップ

プロジェクトが不要な場合は、Mobile Hubコンソールのトップ画面から操作します :bulb: 

削除したいプロジェクトの右上に「…」がありますので、カーソルを合わせて「Delete」をクリックします。

<img width="721" alt="" src="https://qiita-image-store.s3.amazonaws.com/0/216963/d2c54ce4-e58c-a9c3-9145-780682af5019.png">

Mobile HubでセットアップされたAWSリソースが削除されアクセス拒否される旨の確認ダイアログが表示されるので、「Delete project」ボタンをクリックするとMobile Hubのプロジェクトが削除されます。

<img width="638" alt="MobileHub project delete confirm dialog" src="https://qiita-image-store.s3.amazonaws.com/0/216963/25b675f6-bfb7-1662-e99b-0bcd6559dca9.png">

しかし、完全にAWSリソースが削除されないため注意が必要です。

削除されるAWSリソース

 - Amazon Pinpoint のプロジェクト
 - Amazon Cognitoのフェデレーティッドアイデンティティ
 - Amazon S3のバケット(`userdata`, `deployments`)
 - プロジェクトに関わるIAMロール

削除されないAWSリソース

 - Amazon Cognitoのユーザープール
 - Amazon CloudFrontのディストリビューション
 - Amazon DynamoDBのテーブル
 - Amazon S3のバケット(`hosting`)
 - Mobile Hubのサービスが使うIAMロール


# 動作環境

今回の記事で使った環境はこちらになります :computer: 

```bash
$ sw_vers
ProductName:	Mac OS X
ProductVersion:	10.12.6
BuildVersion:	16G29

$ node -v
v8.1.4

$ npm -v
5.4.2

$ ionic --version
3.19.0

$ cordova --version
7.1.0
```