Ionic + FCMを使ってお手軽にPush通知を実装する

IonicでPush通知を実装する方法はいくつかありますが、お手軽な方法は[Firebase Messaging Service(FCM)](https://ionicframework.com/docs/native/fcm/)を使った実装です。  
公式ドキュメントでは、FCMの導入方法については詳しく言及されていないため、プラグイン作者のドキュメントに従って導入することになりますが、初手の導入に幾つか難所や確認点があったので、備忘録を兼ねて導入手順を概略で説明します。

## 実装・検証時のバージョン
* MacOS: 10.12.6
* NodeJS: 8.4.0
* Cordova: 8.0.0
* ionic: 3.1.9.1
* [cordova-plugin-fcm: 2.1.2](https://ionicframework.com/docs/native/fcm/)
* cordova-android: 6.4.0
* cordova-ios: 4.5.4

## Ionic(cordova)でのFCM実装のポイント
1. iOSはPush通知用証明書の作成は不要（Keyで代用）。
2. iOSのFirebase初期セットアップに書かれているCocoaPodsのセットアップは不要。
3. iOS、Android共々、Firebaseのネイティブコード設定項目は対応不要。
4. 他のプラグイン同様、FCMはDeviceReady後にのみ動作する。

## 作業前提
Android Studio、及びXcodeなどのアプリケーション、cordova,Ionicなどのメインフレームワーク、CLIについてはインストール済みである程度知識があるとした上で説明します。


## 事前作業（共通）
### 各プラットフォームの追加
Ionicプロジェクトに作成したいプラットフォームを追加します。既に追加済みの場合はスキップしてください。

```shell
$ ionic cordova platform add ios
$ ionic cordova platform add android
```

### cordova-plugin-fcmプラグインの追加
プロジェクトにFCMプラグインを追加します。こちらは[公式ドキュメント](https://ionicframework.com/docs/native/fcm/)通りで問題ありません。

```shell
$ ionic cordova plugin add cordova-plugin-fcm
$ npm install --save @ionic-native/fcm
```

### Firebaseプロジェクトの新規追加
[FirebaseのConsole](https://console.firebase.google.com/)に移動し、必要な情報を入力して「プロジェクトを作成」をクリックします。

![firebase-add.png](https://qiita-image-store.s3.amazonaws.com/0/22445/2478aeaf-04af-0fe5-58e0-b758bc70ed23.png)


## iOS

### 1.各種証明書作成
iOSの場合は証明書の発行が必要なので、Firebaseだけで設定が完結しません。ネイティブアプリを作る時と同じように、Apple Developer Accountで以下のファイル生成と設定が必要です。

* Certificates
* App ID **※1**
* Provisioning Profiles
* key(Push Notification証明書の代わりに必要)**※2**

主だった証明書の作成方法について、当記事では説明しません。[この記事](https://i-app-tec.com/ios/apply-application.html)などを参考に生成してください。

##### ※1 App IDについて
作成後、Push Notification ServiceをONにします。Push通知用Certificateを作成しないため、**Configuarbleとなりますが、これはこれで問題ありません。**

![appid.png](https://qiita-image-store.s3.amazonaws.com/0/22445/63a65073-5715-ed67-c3fd-f5cf2b6a8a49.png)


##### ※2 keyについて
Push通知用証明書の代わりに必要です。発行の際、Key ServicesのAPNsにチェックを入れてください。発行後にAuthKeyが発行されるので、控えておいてください。

![ios-keys.png](https://qiita-image-store.s3.amazonaws.com/0/22445/e00965d3-fb67-165c-61c3-3ef760f77168.png)

**AuthKey_{ユニークキー}.p8**ファイルが生成されるので、ローカルに保存します。


### 2.FirebaseプロジェクトにiOSを追加
Firebase Consoleのプロジェクトに移動後、iOSアプリを追加してください。

![ios-firebase-add.png](https://qiita-image-store.s3.amazonaws.com/0/22445/4514e5e0-15e1-7a63-0074-99aab6043c87.png)

#### アプリの登録
iOSのバンドルIDを入力します。cordovaのconfig.xmlに記述しているwidgetのIDがバンドルIDです

![スクリーンショット 2018-02-23 11.23.18.png](https://qiita-image-store.s3.amazonaws.com/0/22445/12a3bfd8-a89c-d3e6-269e-35e31d5378f5.png)


#### GoogleService-Info.plistのダウンロード
iOS用の設定ファイルをダウンロードして、**Ionicのプロジェクトのルートディレクトリにコピーします。**
その後の"3. Firebase SDK の追加"と"4. 初期化コードを追加"の手順は不要なのでスキップしてください。

![GoogleService-Info.plist](https://qiita-image-store.s3.amazonaws.com/0/22445/b97b2a24-369a-0e1a-cf47-c5f79676c4ce.png)

#### Auth Keyのアップロード
証明書作成時に生成したAuth Keyをプロジェクトにアップロードします。Consoleの設定>クラウドメッセージングに移動し、APNs認証キー項目のアップロードボタンを押します。

![Auth Keｙ](https://qiita-image-store.s3.amazonaws.com/0/22445/4653a01d-11ba-d1f1-3d3b-687eb520941a.png)

アップロードにはキーIDと、App ID Prefixが必須です。キーIDはApple Developer ConsoleのKeyｓの詳細のKey ID、App ID PrefixはMembershipのTeam IDが該当します。

![スクリーンショット 2018-02-23 11.27.12.png](https://qiita-image-store.s3.amazonaws.com/0/22445/41d55228-28b5-3421-0824-7eae2191ce27.png)


### 3.config.xmlに記述追加（cordova-plugin-fcm固有の問題）
cordova-plugin-fcmプラグインのバグ？の問題で、plistの配置先が`platforms/ios/{{プロジェクト名}}/Resources/Resources/GoogleService-Info.plist`と一段深く潜ってしまい、Resources内のplistを正しく読み込まずエラーとなります。そのため、config.xmlのplatform:iosの中に以下の一文を記述します。

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

詳しくは[IonicでFCMによるpush通知を行う](https://qiita.com/saihoooooooo/items/34712738d5cc6f03cdf4)で説明されています。なお、まだベータ版ではありますが[cordova-plugin-firebase](https://ionicframework.com/docs/native/firebase/)ではこのバグはなく、手順自体不要です。


## Android

### 1.FirebaseプロジェクトにAndroidを追加
Firebaseのプロジェクトに、Androidアプリを追加してください。

![android-firebase-add.png](https://qiita-image-store.s3.amazonaws.com/0/22445/3cc2b7a1-9a7b-e6af-9dc9-99c64aa132f5.png)

#### アプリの登録
Androidのパッケージ名を入力します。iOSと同じくcordovaのconfig.xmlに記述しているwidgetのIDを入力します。

![android-id.png](https://qiita-image-store.s3.amazonaws.com/0/22445/35f1d4d6-73b6-6084-f7f1-f835ca69aa1e.png)

##### SHA-1の入力について
入力は必須ではありませんが、念のため記述方法（生成方法）を説明します。任意の場所で下記コマンドを実行することで入手可能です。コマンド実行後「キーストアのパスワードを入力してください:」と出てきますが、設定していなければそのままEnterを押してスキップします。するとSHA-1を含めたハッシュリストが表示されますので、そのまま入力欄にコピーしてください。

```shell
$ keytool -exportcert -list -v -alias androiddebugkey -keystore ~/.android/debug.keystore
```

この手順は[公式ドキュメント](https://developers.google.com/android/guides/client-auth)にも手順は書かれています。


#### 設定ファイル（google-services.json）のダウンロード
アプリ登録により生成されたgoogle-services.jsonを、iOSのplistと同じように**Ionicのルートディレクトリにコピーします。**その後の"3. Firebase SDK追加"についてはスキップします。

![android-json.png](https://qiita-image-store.s3.amazonaws.com/0/22445/05d90cc9-d145-2263-c706-ccef14aa72a5.png)


## プロジェクトへの反映、Push通知テスト

### 1.プロジェクト編集
他プラグイン同様、`/src/app/app.module.ts`のprovidersにFCMを登録した上で、
`/src/app/app.component.ts`に以下のように記述します（関連の無いコードは省いています）。これで`device.ready`が発火次第、FCMプラグインが実行されます。

```typescript:app.component.ts
  constructor(platform: Platform, fcm: FCM) {
    platform.ready().then(() => {

      if (platform.is('cordova')) { //browserで使うとエラーになるため
        fcm.getToken().then(token => this.registerToken(token));
      }
    });
  }

  private registerToken(token: string) {
    alert(token); //tokenが取得できれば表示
  }
```

最後にIonicのprepareコマンドで各プラットフォームを更新すれば、設定作業は完了です。

```shell
$ ionic cordova prepare ios
$ ionic cordova prepare android
```

#### iOSプロジェクトについての補足
phonegap-push-pluginと違い、プロジェクトは`xxx.xcodeproj`から開けます。また、プラグインを入れたからといってCapabillitiesのPush Notificationsは有効にならないため、かならず設定した上でBuildしてください。

![スクリーンショット 2018-02-23 12.12.59.png](https://qiita-image-store.s3.amazonaws.com/0/22445/8d91a109-21c3-49e8-c766-b212e8083bb5.png)


### 2.Push通知テスト
Build後、Firebase ConsoleのNotificationsから任意のデバイス、またはターゲットを選択して「メッセージを送信」で送信してください。デバイスにPush通知が表示されれば基本的な実装は完了です。

![capture.png](https://qiita-image-store.s3.amazonaws.com/0/22445/7281dd71-b74f-2970-e7a0-0a04a961d880.png)


## [追記] cordova-plugin-firebaseを使った実装方法
cordova-plugin-fcmを再インストールしようとしたところ、cordovaあるあるのpluginがインストールできなくて積むケースが発生したため（汗）、[cordova-plugin-firebase](https://ionicframework.com/docs/native/firebase/)の実装に切り替えた方法も紹介します。

### 実装・検証時のバージョン
* MacOS: 10.12.6
* NodeJS: 8.4.0
* Cordova: 8.0.0
* ionic: 3.1.9.1
* [cordova-plugin-firebase: 0.1.25](https://ionicframework.com/docs/native/firebase/)
* cordova-android: 6.4.0
* cordova-ios: 4.5.4

#### 実装方法
基本的な手順はcordova-plugin-fcmとほぼ一緒です。実装コードはtoken取得までは同じですが、`grantPermission`で通知許可を与えないと、AppのPush通知許可となりませんので、注意してください。

```typescript:app.component.ts
constructor(platform: Platform, firebase: Firebase) {

  if (platform.is('cordova')) {
    firebaseNative.getToken()
      .then(token => this.registerToken(token))
      .catch(error => console.error('Error getting token', error));

      firebaseNative.hasPermission().then( data => {
      if(data.isEnabled != true){
        firebaseNative.grantPermission().then( data => { //通知を許可する
          console.log(data);
        });
      }
    });

    firebaseNative.onNotificationOpen().subscribe( data => {
        console.log(data);
    });
  }
}

private registerToken(token: string) {
  alert(token); //tokenが取得できれば表示
}
```