AmazonSNSとFirebaseを使ってSNSコンポーネントでプッシュ通知

AWS SNSコンポーネントを使用してAndroidアプリへプッシュ通知メッセージを送信してみます。以前はGoogle Cloud Messagingを使用していましたが、Firebaseが強く推奨されていますのでこちらを使用します。

#Firebaseの設定

まずFirebaseのコンソールでプロジェクトを追加します。

![firebaseプロジェクト.PNG](https://qiita-image-store.s3.amazonaws.com/0/180278/9c3302c9-5d2d-ed6c-7b16-ef7257950ebb.png)

ダイアログに「プロジェクト名」と「国/地域」を設定して追加します。

![firebaseプロジェクト作成.PNG](https://qiita-image-store.s3.amazonaws.com/0/180278/aa2a1efc-3e3a-52ee-71ce-44c70e2a019e.png)

プロジェクトが追加されたらAndroidアプリでテストしたいので「AndroidアプリにFirebaseを追加」をクリックします。

![firebaseアプリ追加.PNG](https://qiita-image-store.s3.amazonaws.com/0/180278/b192b599-8942-e6e5-9929-f737e6b36d3e.png)

Androidパッケージ名は、開発しているAndroidアプリのパッケージを指定してあげます。

![firebaseアプリ登録.PNG](https://qiita-image-store.s3.amazonaws.com/0/180278/1be22200-496a-aad5-7f94-9fbdbd601db9.png)

SHA-1はAndroidアプリの開発環境でJDK1.8.0.161を使ってデバッグ用を作成しました。

![firebaseアプリ登録keytool.PNG](https://qiita-image-store.s3.amazonaws.com/0/180278/479ff52e-2897-7038-f1ef-69c0ebc88510.png)

設定ファイルのgoogle-services.jsonをダウンロードしてとっておきます。後で開発するAndroidアプリのappフォルダ直下に置きます。

![firebaseアプリ登録jsonダウンロード.PNG](https://qiita-image-store.s3.amazonaws.com/0/180278/a4490cfc-586d-27da-60cc-4d22acb8a7aa.png)

開発するAndroidアプリのbuild.gradleを指定のように修正する必要があります。

![firebaseアプリ登録gradle修正.PNG](https://qiita-image-store.s3.amazonaws.com/0/180278/cd5453e2-c792-3360-fb88-8e02222c9d0d.png)

Firebaseコンソールでプロジェクトの設定/クラウトメッセージングを開いて
プロジェクト認証情報/サーバーキーのトークンをコピーしておきます。

![firebaseサーバーキー.PNG](https://qiita-image-store.s3.amazonaws.com/0/180278/e0d605f2-ff86-96b5-262e-905ae983e97e.png)

Firebaseで設定することは以上です。

#Android Studio

Android Studioを使用してSNSからメッセージを受け取るAndroidアプリを作成します。

![androidstudio1.PNG](https://qiita-image-store.s3.amazonaws.com/0/180278/a2578863-a907-9085-3932-adcd95545932.png)

プロジェクトを作成します。

![create_app1.png](https://qiita-image-store.s3.amazonaws.com/0/180278/31d17f14-4678-222b-2f2d-e6adf66286a0.png)

今回はAPI 23: Android6.0(Marshmallow)以上を選択します。

![create_app2.png](https://qiita-image-store.s3.amazonaws.com/0/180278/01131aaf-994c-c6cb-d392-fec6309494f3.png)

空で作ります。

![create_app3.png](https://qiita-image-store.s3.amazonaws.com/0/180278/7bc7eebe-ad80-3a64-b54a-9f2c55e34096.png)

![create_app4.png](https://qiita-image-store.s3.amazonaws.com/0/180278/e5e5d916-952b-1c47-6ddb-50d11f9a2ae3.png)

プロジェクトのフォルダが作成できたら、さっそく先ほどダウンロードしたgoogle-services.jsonをappフォルダ下に移動します。

![add_json.PNG](https://qiita-image-store.s3.amazonaws.com/0/180278/f5765dbe-7623-634c-6fdc-1cf2ee1b46f2.png)

build.gradleも修正しておきます。
SDKのバージョンを変更して、firebaseのcompile行を追加します。

```
apply plugin: 'com.android.application'

android {
    compileSdkVersion 27
    buildToolsVersion "27.0.3"
    defaultConfig {
        applicationId "com.infoteria.snsapp"
        minSdkVersion 23
        targetSdkVersion 27
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
   implementation fileTree(dir: 'libs', include: ['*.jar'])
   implementation 'com.android.support.constraint:constraint-layout:1.0.2'
   compile 'com.google.firebase:firebase-core:11.8.0'
   compile "com.google.firebase:firebase-messaging:11.8.0"
   compile 'com.android.support:support-v4:27.1.0'
   compile 'com.android.support:support-compat:27.1.0'
   compile 'com.android.support:appcompat-v7:27.1.0'
   compile 'com.android.support:animated-vector-drawable:27.1.0'
}
apply plugin: 'com.google.gms.google-services'
```
Android StudioのメニューTools/Firebaseからソースのチュートリアルを見れます。

![add_tools_firebase.png](https://qiita-image-store.s3.amazonaws.com/0/180278/9e44df07-f835-cc8c-6a4a-91a29461b620.png)

![add_tools_firebase2.png](https://qiita-image-store.s3.amazonaws.com/0/180278/9c90e5c1-6956-c985-06da-a4d94b6e4c62.png)

![add_tools_firebase3.png](https://qiita-image-store.s3.amazonaws.com/0/180278/13f59986-77a7-9142-19b6-37d146bcf325.png)

Tokenを取得方法は
　FirebaseInstanceId.getInstance().getToken();
このTokenはSNSでアプリケーションのエンドポイントで使用するトークンです。

```
Log.d(LOGNAME, "firebase instance token: " + FirebaseInstanceId.getInstance().getToken());
```

Firebaseのメッセージ受け取りは
FirebaseMessagingServiceクラスを作成し、onMessageReceivedで受け取ります。


```
@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
  Log.d(LOGNAME, "From: " + remoteMessage.getFrom());
  String messageBody = "Empty Message !";
  if (remoteMessage.getData().size() > 0) {
    Log.d(LOGNAME, "--Message Data--");
    java.util.Map<String, String> message = remoteMessage.getData();
    //長かろうが、短かろうが処理する
    StringBuilder sb = new StringBuilder();
    for (java.util.Map.Entry<String, String> entry : message.entrySet()) {
      sb.append(entry.getKey()).append("=")
      .append(entry.getValue()).append("\n");
    }
    messageBody = sb.toString();
  } else if (remoteMessage.getNotification() != null) {
    Log.d(LOGNAME, "--Notification Body--");
    messageBody = remoteMessage.getNotification().getBody();
  }
  Log.d(LOGNAME, messageBody);
  sendMessage(messageBody);
}
```
sendMessageメソッドでUIの方へ取得したメッセージを渡しています。

FirebaseMessagingServiceクラスはAndroidManifest.xmlへサービスとして追加しておきます。

```
<service           
  android:name=".SNSAppMessagingService"
  android:label="SNSAppMessagingService" >
  <intent-filter>
   <action android:name="com.google.firebase.MESSAGING_EVENT" />
  </intent-filter>
</service>
```

ビルドが通ったら、Android Studioの作業は以上になります。
Virtual Devicesでアプリを起動しておきます。

#SNSの設定

FlowのSNSコンポーネントで全てできるので、AWS SNSダッシュボードで行う作業はとくにありません。

#Flowの作成

1.まずSNSコンポーネントの動作のおさらい

- メッセージの送信はAWS SNSPublishコンポーネントで行うが対象はトピックのみである。
- メッセージはTextストリームのみ対応していてる。これはメッセージ形式Rowに対応しているがJSONには対応していないということ。

※SNSを操作できるAWSコネクションは作成済の前提です。
 
2.コンポーネントでやること

- AWS SNSCreateTopicコンポーネントでトピックを作成

![flow1.PNG](https://qiita-image-store.s3.amazonaws.com/0/180278/66cb5265-d6a7-8f46-5997-166f9b7dc141.png)

　「トピック名」プロパティに名前を設定し、実行後にトピックARNを外部変数セットなどに保持しておきます。
　※トピックARNは後でSubscribeするときやPublishするときに使用します。

- AWS SNSCreateEndpointコンポーネントでアプリケーション(GCM)を作成

![flow2.PNG](https://qiita-image-store.s3.amazonaws.com/0/180278/849bb4a3-0a85-3ab5-c4d8-33b546e38660.png)

AWS SNSCreateEndpointコンポーネントをダブルクリックするとアプリケーションのリストが表示され、アプリケーション(GCM)を作成することができます。
アプリケーション名は任意ですが、APIキーはFirebaseコンソールからコピーしておいた「サーバーキーのトークン」を指定します。

- AWS SNSCreateEndpointコンポーネントでAndroidアプリが動作するデバイスのエンドポイントを作成

![flow3.PNG](https://qiita-image-store.s3.amazonaws.com/0/180278/a28fb1a2-084b-2103-697c-e5e44affeddd.png)

Androidデバイスでアプリ実行時に取得するトークンが必要になります。今回は簡単にログでトークンを出力するようにして、Android StudioのLogcatからコピーして取得します。

![logcat.PNG](https://qiita-image-store.s3.amazonaws.com/0/180278/8f207ab8-98a9-b720-2c71-79d555363974.png)

- AWS SNSSubscribeコンポーネントでトピックへエンドポイントをapplicationプロトコルのサブスクリプションとして登録

![flow4.PNG](https://qiita-image-store.s3.amazonaws.com/0/180278/a5156c17-ebca-73bd-a753-013f0a5a01d4.png)

「トピックARN」プロパティ：保持しておいたトピックARNを指定
「プロトコル」プロパティ：「application」を選択
「エンドポイントARN」プロパティ：保持しておいたエンドポイントARNを指定

- AWS SNSPublishコンポーネントでプッシュ通知メッセージの送信

![flow5.PNG](https://qiita-image-store.s3.amazonaws.com/0/180278/a3fc3a8f-15ea-30e2-2d44-475f55825b08.png)

AWS SNSPublishコンポーネントで送信するメッセージをTextストリームで渡します。
「件名」プロパティはサブスクリプションのプロトコルがapplicationのときは使用されませんが、必須プロパティなので何か設定します。

Flowの準備は以上です。

#Flowの実行

作成したFlowを順に実行していき、トピック、アプリケーション、エンドポイント、サブスクリプションを作成します。

最後にプッシュ通知メッセージを送信します。

「SNSPublish from Flow Component 22:34:45」というメッセージを送信しました。

![exec_flow.PNG](https://qiita-image-store.s3.amazonaws.com/0/180278/3f83c865-84bb-3f2d-4785-fc38ddfcc2bf.png)

Androidデバイスのでdefaultの値としてメッセージを受信できました。

![exec_device.PNG](https://qiita-image-store.s3.amazonaws.com/0/180278/88f53d2c-c0e0-ee95-e270-d53dff2261b8.png)

SNSのコンポーネントからGCMと同じようにFirebaseのプロジェクトに設定されているAndroidアプリへプッシュ通知メッセージを送信することができました。