cocos2d-xでFCMのリモート通知を受け取る

# やりたかったこと

- cocos2d-xのアプリでバックグランド動作時にプッシュ通知を出したかった。
- 以前の[WebSocketの記事](https://qiita.com/FrozenVoice/items/12f7a4d38a91b9bddd9c)で通信が来たら通知が出るイメージ

# 道のり

## FCM(Firebase Cloud Messaging)の準備

以前はGCM(Google Cloud Messaging)と呼ばれていた物で、Android/iOS等でPush通知を行うためのプラットフォーム。

### アカウント作成

下記からアカウントを作成する。
[FireBase](https://firebase.google.com/)

### FirebaseのプロジェクトにAndroidアプリを登録

- 登録時に必要になる下記の情報を予めメモしておく
    - Androidパッケージ名
        - build.gradle の applicationId で指定されているJavaパッケージ名
    - デバッグ用証明書のSHA-1ハッシュ
        - 下記のコマンドでJREに含まれているkeytoolから生成する
        - `keytool -exportcert -list -v -alias androiddebugkey -keystore %USERPROFILE%\.android\debug.keystore`
        - 各ユーザープロファイル配下のkeystoreから生成しているので、複数人で共同開発している場合はなんらかの考慮が必要…と思われる。
- Firebaseの[コンソール](https://console.firebase.google.com/)画面に移動してプロジェクトを追加する
- 「AndroidアプリにFirebaseを追加」を選択
- メモしておいた情報を入力して登録

## Android Studio側での設定

### 設定ファイルの配置

Firebaseを利用するための設定が入った `google-services.json` がダウンロード出来るようになるので、AndroidStudioの `/proj.android-studio/app` へ配置する

### /proj.android-studio/build.gradleの変更

```
buildscript {
  dependencies {
    // Add this line
    classpath 'com.google.gms:google-services:3.2.0'
  }
}

allprojects {
    // ...
    repositories {
        // ...
        maven {
            url "https://maven.google.com" // Google's Maven repository
        }
    }
}
```

### /proj.android-studio/app/build.gradleの変更

```
dependencies {
  // Add this line
  compile 'com.google.firebase:firebase-core:11.8.0'
  compile 'com.google.firebase:firebase-messaging:11.8.0'
}
...
// Add to the bottom of the file
apply plugin: 'com.google.gms.google-services'
```

**※Android Studio上で11.8.0ではなく15.0.0を使うように警告が出るのですが、変更するとビルド出来ない状態になりハマりました。**

## cocos2d-xアプリでのメッセージ購読設定

リモート通知はcocosと言うよりはAndroid側の機能なので、cppファイルではなくアプリ起動時のAppActivity.java に対してsubscribeToTopic()を追加してメッセージの購読設定をしています。

```java

import com.google.firebase.messaging.FirebaseMessaging;

public class AppActivity extends Cocos2dxActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        …中略
        // DO OTHER INITIALIZATION BELOW
        FirebaseMessaging.getInstance().subscribeToTopic("news");
```

## WebSocketサーバー側でメッセージ受信時にFCMへ送信

PHPで実装したWebSocketサーバーにFCMに対してメッセージを送信するメソッドを用意します。
クライアントからメッセージが届いた際に下記のメソッドを呼び出してFCM経由でリモート通知を送ります。

```php
	private function sendFCM($msg) {
	    $api_key  = "API_KEY";
        $base_url = "https://fcm.googleapis.com/fcm/send";
        $data = array(
            "to"           => "/topics/news",
            "priority"     => "high",
            "notification" => array(
                             "title" => "通知",
                             "body"  => $msg
            )
        );

        $header = array(
             "Content-Type:application/json"
            ,"Authorization:key=".$api_key
        );

        $context = stream_context_create(array(
            "http" => array(
                 'method' => 'POST'
                ,'header' => implode("\r\n",$header)
                ,'content'=> json_encode($data)
            )
        ));
        file_get_contents($base_url,false,$context);
    }
```

※API_KEYの部分はFirebaseの「プロジェクト設定」→「クラウドメッセージング」タブに表示されている「サーバーキー」を指定します。

「プロジェクト設定」→「全般」タブの「ウェブ API キー」や、「google-services.json」に記載されている「api_key」**ではないのでご注意下さい。** (自分はちょっとハマりました。)

## 注意点

- GenymotionではGoogle Play Serviceがインストールされておらずリモート通知が届かないようです。
- 実機もしくは公式Androidエミュレータであれば通知が届きます。