ionic
FCM
ionic-native
IonicDay 6

IonicでFCMによるpush通知を行う

この記事は Ionic Advent Calendar の6日目の記事です

push通知はアプリにはだいたい必要かつ割とめんどくさいイメージがありますがFCM(Firebase Cloud Messaging)ならサクッと実装できちゃいます
IonicにもFCMのプラグインがあるので今回はそれを使っていきたいと思います

(Firebaseの登録、証明書の作成などは省略します)

使い方

インストール

以下のコマンドで Ionic Native - FCM をインストールします

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

設定ファイル

次にFirebaseの設定ファイル(iOS用:GoogleService-Info.plist、Android用:google-services.json)が必要なのでルートディレクトリに置いておきます
この辺を参考に取得してください
https://support.google.com/firebase/answer/7015592

実装

まずapp.module.tsでインポート

src/app/app.module.ts
import { FCM } from '@ionic-native/fcm';

...

@NgModule({

  ...

  providers: [

    ...

    FCM,

    ...

  ],

  ...

})
export class AppModule { }

あとは起動時やログイン後にDI&初期化します
例えばpage-homeで呼ぶ場合は以下の通りです

src/page/home/home.ts
import { Component } from '@angular/core';
import { IonicPage } from 'ionic-angular';
import { FCM } from '@ionic-native/fcm';

@IonicPage()
@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage {

  constructor(private fcm: FCM) {
  }

  ionViewDidLoad() {
    this.fcm.getToken().then(token => this.registerToken(token));

    this.fcm.onTokenRefresh().subscribe(token => this.registerToken(token));

    this.fcm.onNotification().subscribe(data => {
      if (data.wasTapped) {
        // バックグラウンド時の処理

        ...

      } else {
        // フォアグラウンド時の処理

        ...

      };
    });
  }

  private registerToken(token: string) {
    // WebAPI呼んでトークンを自前のDBなりに登録するなど

    ...

  }

}

あとはサーバ側からFCMに対してこんな感じのJSONを送りましょう

{
  "notification": {
    "title": "通知テスト",
    "body": "いろはにほへと",
    "sound": "default"
  },
  "to": "xxxxxxxxxxxxxxxx[アプリから登録されたトークン]",
  "data": {
    "hoge": 1,
    "fuga": 2,
    "piyo": 3
  }
}

以上
たったこれだけです、お疲れ様でした

と、思いきや

2つほどハマりポイントにぶつかってしまったので共有させていただきたいと思います
(どちらかというとcordova-plugin-fcmの問題ではありますが)

・其の壱 iOSで起動時に落ちる

どうやらビルド時に設定ファイルであるGoogleService-Info.plistplatforms/ios/[プロジェクト名]/Resources/GoogleService-Info.plistに置いてくれているのですが、これはipaファイルには入らず(!?)実際は更に一段掘ったplatforms/ios/[プロジェクト名]/Resources/Resources/GoogleService-Info.plistを見に行っているようでした
見に行った先の中身は空でそこでコケちゃってるみたいです

なので対処するためにplistを正しい位置にコピーします
といってもcpするわけではなくビルド時に自動でやってもらいたいのでconfig.xmlに記述していきます

config.xml
<?xml version='1.0' encoding='utf-8'?>
<widget ...>

    ...

    <platform name="ios">

        ...

        <resource-file src="GoogleService-Info.plist" target="Resources/GoogleService-Info.plist" />

        ...

    </platform>

    ...

</widget>

この状態でビルドするとplatforms/ios/[プロジェクト名]/Resources/Resources/GoogleService-Info.plistにファイルが置かれ無事起動できました

・其の弐 Androidの通知用アイコンを設定する

https://github.com/fechanique/cordova-plugin-fcmREADME.md には以下のように書かれています

For Android >5.0 status bar icon, you must include transparent solid color icon with name 'fcm_push_icon.png' in the 'res' folder in the same way you add the other application icons. If you do not set this resource, then the SDK will use the default icon for your app which may not meet the standards for Android >5.0.

Android5以上から通知のアイコンはアルファチャンネルを使用していない場合に四角い豆腐になってしまいます
アプリのアイコンとして使用している画像が背景を透過していない場合は別途通知用のアイコンを作成する必要があります

参考:https://qiita.com/syarihu/items/95788cbab9b63100c4fb

通知用の透過アイコンを用意したらREADME.mdの通りにresディレクトリ内に置いておきましょう
resディレクトリ下にも複数のディレクトリがありますが以下に置いておけば良さそうです

  • platforms/android/res/mipmap-ldpi
  • platforms/android/res/mipmap-mhdpi
  • platforms/android/res/mipmap-hdpi
  • platforms/android/res/mipmap-xxhdpi
  • platforms/android/res/mipmap-xxhdpi
  • platforms/android/res/mipmap-xxxhdpi

ここでも先程の要領でconfig.xmlに記述していきます

config.xml
<?xml version='1.0' encoding='utf-8'?>
<widget ...>

    ...

    <platform name="android">

        ...

        <resource-file src="resources/android/fcm_push_icon/drawable-ldpi-icon.png" target="res/mipmap-ldpi/fcm_push_icon.png" />
        <resource-file src="resources/android/fcm_push_icon/drawable-mdpi-icon.png" target="res/mipmap-mdpi/fcm_push_icon.png" />
        <resource-file src="resources/android/fcm_push_icon/drawable-hdpi-icon.png" target="res/mipmap-hdpi/fcm_push_icon.png" />
        <resource-file src="resources/android/fcm_push_icon/drawable-xhdpi-icon.png" target="res/mipmap-xhdpi/fcm_push_icon.png" />
        <resource-file src="resources/android/fcm_push_icon/drawable-xxhdpi-icon.png" target="res/mipmap-xxhdpi/fcm_push_icon.png" />
        <resource-file src="resources/android/fcm_push_icon/drawable-xxxhdpi-icon.png" target="res/mipmap-xxxhdpi/fcm_push_icon.png" />

        ...

    </platform>

    ...

</widget>

コピー元のディレクトリ名/ファイル名は一例ではありますが上記のように書いた場合はresources/android/fcm_push_icon/以下に各サイズのアイコンを置いておけばplatforms/android/res/に適宜コピーされます

各アイコンは適当な生成サービスを利用するか本アイコンを退避させてからionic cordova resourcesで生成するなどしてください
こんな感じでもいいです

$ cp /path/to/fcm_push_icon.png resources/icon.png
$ ionic cordova resources --android --icon
$ mv resources/android/icon resources/android/fcm_push_icon
$ git checkout -- resources/android/icon.png resources/android/icon

あとは通知のパラメータにアイコンと透過部分の色を指定するだけです

{
  "notification": {

    ...

    "icon": "fcm_push_icon",
    "color": "#A3C642",

    ...

  },

  ...

}

これで豆腐アイコンじゃなくなりFCMによるpush通知が問題なく行えるようになりました

まとめ

Ionic最高!! :octopus: