ぴよぴよエンジニアの日記

クラウドベンダーに勤める見習いSEの日記です。発言は私自身の見解であり、必ずしも所属組織の立場、戦略、意見を代表するものではありません。

Bluemix の Push Notifications を試してみた

最近はプッシュ通知といえば mBaaS を使うのがスタンダードという風潮を感じます.

Amazon SNSAzure Notification Hubs など、各社プッシュ通知のサービスを提供しています.


Bluemix にもプッシュ通知のサービスが存在します.

console.bluemix.net


価格プランは"ライト"と"基本"の2つになります.

f:id:Santea:20170801213024p:plain

f:id:Santea:20170801213252p:plain


クライアント SDK は以下の4つが用意されています.

サーバー SDK は以下の3つが用意されています.

  • Java
  • Node.js
  • Swift


今回はクライアントサイドに Android SDK を、サーバーサイドに Java SDK を用いたパターンを試してみたいと思います.



クライアントサイド

github.com
github.com

上記が iOS, Android 用の SDK となります.
今回は Android の実装を行います.


github.com

サンプルアプリはこちらになります.
サンプルアプリの中でポイントとなるところを抜粋して説明します.


AndroidManifest.xml

<activity
    android:name=".MainActivity"
    android:label="@string/app_name" >
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>

    <!--Notification Intent -->
    <intent-filter>
        <action android:name="com.ibm.hellopush.IBMPushNotification" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>

Activity に通知インテントを受けるための記述を加えます.

<service android:exported="true" android:name="com.ibm.mobilefirstplatform.clientsdk.android.push.api.MFPPushIntentService">
    <intent-filter>
        <action android:name="com.google.firebase.MESSAGING_EVENT"/>
    </intent-filter>
</service>
<service android:exported="true" android:name="com.ibm.mobilefirstplatform.clientsdk.android.push.api.MFPPush">
    <intent-filter>
        <action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>
    </intent-filter>
</service>

IntentService の記述を加えます.
自前で IntentService を書かなくてもよいのは便利ですね.


MainActivity.java

MFPPushResponseListener registrationResponselistener = new MFPPushResponseListener<String>() {
            @Override
            public void onSuccess(String response) {
                // Split response and convert to JSON object to display User ID confirmation from the backend
                String[] resp = response.split("Text: ");
                try {
                    JSONObject responseJSON = new JSONObject(resp[1]);
                    setStatus("Device Registered Successfully with USER ID " + responseJSON.getString("userId"), true);
                } catch (JSONException e) {
                    e.printStackTrace();
                }

                Log.i(TAG, "Successfully registered for push notifications, " + response);
                // Start listening to notification listener now that registration has succeeded
                push.listen(notificationListener);
            }
            ...
};

トークン登録時のリスナーの記述です.
レスポンスの JSON は以下のようなものが返ってきます.

{"createdTime":"2017-07-27T13:45:33Z",
"lastUpdatedTime":"2017-07-31T09:18:04Z",
"createdMode":"API",
"deviceId":"XXXXXXX-01b0-36df-96d7-3cbc3c32118f",
"userId":"1234567890",
"token":"XXXXXXXXX-VrbN5G5QHqw9snkRhzNEf6-XXXXXX",
"platform":"G",
"href":"https:\/\/imfpush.ng.bluemix.net\/imfpush\/v1\/apps\/XXXXXX-43c2-8bfc-c5c2eb0e9124\/devices\/XXXXXX-36df-96d7-3cbc3c32118f"}

こちらに含まれる deviceId をサーバーサイドで指定することで、トークンを意識することなく通知を送れます.
この deviceId はアプリ再インストールなどでトークンが変わっても維持されるものです.
トークンのメンテナンスが必要ないのは大変便利ですね.

push.registerDeviceWithUserId("1234567890",registrationResponselistener);

先ほどの JSON に含まれていた userId はトークン登録時に明示的に指定することができます.
これにより、複数のデバイスを1人のユーザーに紐づけることが可能なり、ユーザー単位でのプッシュ通知送信を実現できます.


クライアントサイドの説明は以上になります.



サーバーサイド

今回は maven プロジェクトで実装しました.


pox.xml

<dependencies>
	<dependency>
		<groupId>com.ibm.mobilefirstplatform.serversdk.java</groupId>
		<artifactId>push</artifactId>
		<version>1.0.1</version>
	</dependency>
</dependencies>

上記の dependency の記述を追加します.



public static void main( String[] args ) throws SSLException, IOException
    {
        //(appGuid, appSecret)
        PushNotifications.init("XXXXXXXX-5ce7-43c2-8bfc", "XXXXXXXX-89d0-40b1-bdaf", PushNotifications.US_SOUTH_REGION);

        NotificationBuilder builder = new NotificationBuilder("This is the notification's text!");

        JSONObject notification = builder
    	.setTarget(new String[]{"XXXXXXX-01b0-36df-96d7-3cbc3c32118f"},
    			new String[]{"1234567890"},
    			new PushNotificationsPlatform[]{PushNotificationsPlatform.GOOGLE},
    			new String[]{"Tag1", "Tag2"})
    	.build();


    	PushNotifications.send(notification, new PushNotificationsResponseListener(){

    		public void onSuccess(int statusCode, String responseBody) {
    			System.out.println("Successfully sent push notification! Status code: " + statusCode + " Response body: " + responseBody);

    		}

    		public void onFailure(Integer statusCode, String responseBody, Throwable t) {
    			System.out.println("Failed sent push notification. Status code: " + statusCode + " Response body: " + responseBody);

    			if(t != null){
    				t.printStackTrace();
    			}
    		}
    	});
}

こちらがサーバーサイドのコードになります.

//(appGuid, appSecret)
PushNotifications.init("XXXXXXXX-5ce7-43c2-8bfc", "XXXXXXXX-89d0-40b1-bdaf", PushNotifications.US_SOUTH_REGION);

初期化の部分では、第一引数にサービス資格情報の appGuid を、第二引数に appSecret を指定します.

JSONObject notification = builder
    	.setTarget(new String[]{"XXXXXXX-01b0-36df-96d7-3cbc3c32118f"}, // deviceId
    			new String[]{"1234567890"}, // userId
    			new PushNotificationsPlatform[]{PushNotificationsPlatform.GOOGLE}, // Platform
    			new String[]{"Tag1", "Tag2"}) // Tag
    	.build();

上記がプッシュ通知オブジェクト生成部分です.
deviceId やクライアントサイドで登録した userId を指定することができます.
いづれか1つ以上を指定する必要があります(指定しない場合は Null または空文字をセットします).

builder.setMessageURL(urlToBeIncludedWithThePushNotification)
	.setTarget(deviceIdArray, userIdArray, platformArray, tagNameArray)
	.setAPNSSettings(badge, category, iosActionKey, payload, soundFile, APNSNotificationType)
	.setGCMSettings(collapseKey, delayWhileIdle, jsonPayload, GCMPriority.HIGH, soundFile, secondsToLive)
        .build();

また、各プラットフォームごとの設定も個別に行えるようになっています.


以上がサーバーサイドの実装でした.



まとめ

今回は Bluemix の Push Notifications を試してみました.


mBaaS を利用することで、プラットフォーム間の差異を吸収できたり、トークンを意識する必要がなかったりと、自前で実装するのに比べ優位な点が見えました.
気になるランニングコストも100万リクセストにつき1$であれば運用しやすいかと思います.


Bluemix Push Notifications ならではの特徴としては、やはり サーバーサイド Swift の SDK が提供されているところでしょうか.
サーバーサイドを Swift で書かれている方には有効な選択肢になるかと思います.


以上です.