ionic+FirebaseCloudMessaging(FCM)+iOSでつまづきまくったので各エラーの対策まとめ

ionic+FCM+iOSでiOSアプリ上でプッシュ通知を実装するをやりました。
細かい手順はネット上にいっぱいあがってますし、基本的にはすごいお手軽です。
うまくいけば、、、

そう！うまくいかなかったときに原因がionicなのかFCMなのかiOSなのか全くわからず、
自分はFCMについても、iOSのAPNｓについてもほぼ知識がなかったこともありつまづきまくりました。
そんなエラーと対処法の数々を愚痴をこぼす気持ちで残してます。

# まずは簡単にionic+FCM+iOSの実装手順
1. iOSアプリのAPNｓ認証を通す
2. FCMのプロジェクト作成、iOSアプリの登録、APNsの登録
3. ionicプロジェクトへcordovaプラグイン、ionic-nativeプラグインを追加

やることをぎゅっとまとめるとこんな感じです。
ただiOS、FCM、ionicそれぞれにネット上に上がっている記事が古かったり、バージョンの互換で死んだりとまったくの初めてで取り掛かると迷うとこつまづくところが結構ありました。

# つまづき１: iOSアプリでAPNsを使えるようにする編
iOSアプリでリモートを通知する際に必須となるAPNsですが、旧来の方法であるアプリごとにAPNs証明書を設定する方法の他にAPNs Auth Keyという方法があります。
参考URL) https://qiita.com/m-hosoi/items/f722c43750086d88afd9

キーを使った方法にはメリットも多く、FCMでもキーを使った方法が推奨されています。

## APNs Auth Keyだとどうしてもメッセージがエラーになる。。。:persevere:
APNs Auth KeyをつかってFCMへの設定をすまし、アプリの登録もばっちり、
[公式のドキュメント通り](https://firebase.google.com/docs/cloud-messaging/ios/first-message?authuser=0)にアプリの実行ログから端末のトークンをコピーしてFirebaseコンソールの[Notifications Composer](https://console.firebase.google.com/project/_/notification?authuser=0)からメッセージを送信！！

来ない、、、

何度設定に間違いがないか見直しても 
`App ID Prefix、キー ID、APNs 認証キーの組み合わせが無効です。`
とエラー文が出るだけで送信が出来ません。。

<img width="583" alt="スクリーンショット 2018-08-07 17.52.31.png" src="https://qiita-image-store.s3.amazonaws.com/0/35271/1f1dc46d-50c9-aa3d-6d9e-eb6924454bf5.png">

### 対策 :raised_hands:
結局これは原因はわからずじまいでした。。
Appleを恨めばいいのか、FCMを恨めばいいのか、己を恨むべきなのか、、
うやむやなままですが、対処としては旧来の方法であるアプリごとにAPNs証明書を設定する方法で実装しました。
こっちの方法は `iOS FCM 実装` とかで古い記事とか探せばいっぱいあります。

<img width="583" alt="スクリーンショット 2018-08-07 12.29.58.png" src="https://qiita-image-store.s3.amazonaws.com/0/35271/5e710047-f85f-04cc-9cec-fc6b376136c6.png">

# つまづき２ : FCMの動作確認でメッセージを送ってみる編
これでiOSアプリとFCMの設定は出来たことが確認できました。
ちなみにここまではionicではなくFCMが公式に公開している[iOSのサンプルアプリ](https://github.com/firebase/quickstart-ios)をもとに検証してます。
FCMのメッセージには不特定多数へのコンテンツ配信向きのトピック、特定の複数端末に送信する向きのグループ、ほかデバイスtoken指定の個別送信などいろいろあります。
いろいろ試してみよう！！ということでPostmanを開いた私、つまづきました。

## FCMのHTTP v1 APIはPostmanでやるにはOAuth 2.0のトークン取得する必要がある:persevere:
いろんな記事にてメッセージ送信のテストにPostmanを使った方法が紹介されてます。
ただし！この方法は古いAPIを使ったもの（公式の言葉を使うとHTTP レガシー プロトコルのほう)です。
現行のAPIであるv1は `Authorization` ヘッダにサーバキー埋め込んでちょちょいとAPI叩くって方法は出来ません。

v1にこの方法でなげてもレスポンスすら返してくれません。
いや、まあ気づくの遅れた自分が悪いんですが、
レスポンスくらい返してよ、、旧APIつかってるって書いてよ、、、って思ったり。。

さらに公式にはv1でOAuth 2.0通してトークン取得する方法は各言語のGoogleAPIライブラリ使う方法しか紹介されてなく、
この辺を見ると多分できそうですが、未検証です。
https://qiita.com/howdy39/items/cd01cbd3c1109e140fd0

### 対策 :raised_hands:
__気軽にPostmanでの検証は出来ないので、公式のおすすめどおりFirebaseコンソールの[Notifications Composer](https://console.firebase.google.com/project/_/notification?authuser=0)使うのが楽ちんかと！__

# つまづき3 : ionicプラグインでハマりまくる編
iOSの設定、FCMの送信をいろいろ試してみて、さあ！！いよいよionicプロジェクトへFCMを組み込んでいきます。
今回はionicプロジェクトはすでにあり、そこにプラグインを追加していきます。

## ionicのFCMプラグインめっちゃ種類ある。。。:persevere:
ionicのFCM関連のプラグインは公式に掲載されているのは全部で３つあります。

- [FCM](https://ionicframework.com/docs/native/fcm/)
- [Firebase](https://ionicframework.com/docs/native/firebase/)
- [Firebase Messaging](https://ionicframework.com/docs/native/firebase/)

FCMとFirebaseが昔からあるものっぽく、cordova pluginのスター数もだいたい同じくらいです。
Firebase Messagingはまだβ版でまだ新しいものでしたが、メソッドの呼び出しかたなど１番使いやすそうで最初こちらにしたのですが、Issueにもあるようにまだ不具合がわりとあるようで今回は断念しました。
FCMとFirebaseは違いがあまりわからなかったので今回はFCMを使うことにしました。

### 対策 :raised_hands:
とりあえずFCM関連のプラグインは[FCM](https://ionicframework.com/docs/native/fcm/)か[Firebase](https://ionicframework.com/docs/native/firebase/)が安定してるっぽい。

## ionic-nativeプラグインで `Uncaught TypeError: Object(...) is not a function` とでる:persevere:
ionic、cordovaでわりとあるあるな謎のエラー。
今回もなんかしら出ました。
今回の原因は `@ionic-native/core` と `@ionic-native/fcm` のバージョンが違うというもの！
ionic-native開発でも出てきがちですが、基本的に `@ionic-native/core` とionic-nativeプラグインのバージョンはあわせたほうが良いです。
`npm install` 時にバージョンを固定で指定してcoreのバージョンと合わせることで無事解決しました。

### 対策 :raised_hands:
__@ionic-native/coreとionic-nativeプラグインはバージョンを合わせる！__

## cordova-plugin-fcmプラグインでGoogleService-Info.plistがあるのに、ないと怒られる:persevere:
iOSアプリとFCMをつなげるためにiOSアプリにはGoogleService-Info.plistというファイルを埋め込む必要があります。
cordova-plugin-fcmプラグインはプロジェクトルートにGoogleService-Info.plistを置いておけばiOSビルド時に複製して配置してくれると記述があるのですが、これは不具合なのかうまく動いてくれずアプリ起動時にGoogleService-Info.plistの読み込みエラーでアプリが落ちます。
（実際に使っているのは依存関係を更新した[cordova-plugin-fcm-with-dependecy-updated](https://github.com/andrehtissot/cordova-plugin-fcm-with-dependecy-updated)です。)

### 対策 :raised_hands:
手動でionicプロジェクトルートにGoogleService-Info.plistファイルを設置し、config.xmlの `<platform name="ios">` 内にresouce-fileとして書いておけばちゃんとビルド時に複製してくれます。

```xml
<platform name="ios">
....
   <resource-file src="GoogleService-Info.plist" target="Resources/GoogleService-Info.plist" />
....
</platform>
```

以上、複数のプロダクトの上に実現するサービスはある程度それぞれ理解しつつ一つ一つ検証していったほうが早いなあ、と気付かされた１件でした。まとまりのない記事ですが、誰かの役にたてば嬉しいです。

# ちょっと一言: FCM感想
今までプッシュ通知は避けて通ってきましたが、FCMは送信にいろいろ選択肢もあり、採用候補としてはかなり有力だなと思いました。
またFCMを含んだFirebaseはホスティングや、認証、データベースなどサーバーレスなモバイルバックエンドとして完結出来るのではって思ってます。この辺もまた試してみようと思います〜