はじめに
Amazon Pinpointを導入してみた際の忘備録です。
本記事のスコープ
AWS Mobile SDK for Android
を導入して、AndroidNative側でどのように設定をすればプッシュ通知を受け取れるのかまでをスコープとします。
AWSの設定に関しては、担当をしてくれた弊社エンジニアの記事 を参照してください。
サンプルレポジトリ
各種設定ファイルは各自取得・配置してください。
設定ファイルに関しては後ほど触れます。
Amazon Pinpointとは
ざっくりと紹介すると
- プッシュ通知等が簡単に送れる
- セグメントを定義して、対象のセグメントに対してのみプッシュ通知を送るなども可能
- 各種アナリティクス(イベント送信・DAUなど)
以下、公式開発者ガイドより引用。
Amazon Pinpoint は、複数のメッセージングチャネル間で顧客とやり取りするために使用できる AWS サービスです。キャンペーンの> 目的に応じて、プッシュ通知、E メール、またはテキストメッセージ (SMS) を送信できます。
用意する事・ファイル
- Firebase Cloud Messagingを導入
- 公式ドキュメント など参照。
- 設定ファイルである
awsconfiguration.json
を用意して、root/app/src/main/res/raw
配下に配置-
awsconfiguration.json
を生成する方法は サーバー側の担当をしてくれた弊社エンジニアの記事 を参照
-
Pinpoint導入
だいたい、公式のガイドに沿って設定しています。
1. AWS Mobile SDK を導入する
build.gradleを編集
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
implementation 'com.google.firebase:firebase-core:16.0.1'
implementation 'com.google.firebase:firebase-messaging:17.3.0'
implementation 'com.google.android.gms:play-services-auth:15.0.1'
// 以下がAmazon Pinpointに必要な依存関係
implementation 'com.amazonaws:aws-android-sdk-pinpoint:2.7.+'
implementation('com.amazonaws:aws-android-sdk-mobile-client:2.7.+@aar') { transitive = true }
}
2. FCM のプッシュ通知を受け付けるサービスを設定
<service
android:name=".PushListenerService">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT"/>
</intent-filter>
</service>
import android.content.Intent
import android.os.Bundle
import android.support.v4.content.LocalBroadcastManager
import android.util.Log
import com.amazonaws.mobileconnectors.pinpoint.targeting.notification.NotificationClient
import com.amazonaws.mobileconnectors.pinpoint.targeting.notification.NotificationDetails
import com.google.firebase.messaging.FirebaseMessagingService
import com.google.firebase.messaging.RemoteMessage
import jp.ginyolith.sandbox.MainActivity
import java.util.HashMap
class PushListenerService : FirebaseMessagingService() {
override fun onNewToken(token: String?) {
super.onNewToken(token)
Log.d(TAG,"Registering push notifications token: " + token!!)
MainActivity.getPinpointManager(applicationContext)?.notificationClient?.registerDeviceToken(token)
}
override fun onMessageReceived(remoteMessage: RemoteMessage?) {
super.onMessageReceived(remoteMessage)
Log.d(TAG,"Message: " + remoteMessage?.data)
// プッシュ通知の内容を取得する
val notificationClient = MainActivity.getPinpointManager(applicationContext)?.notificationClient
val notificationDetails = NotificationDetails.builder()
.from(remoteMessage?.from)
.mapData(remoteMessage?.data)
.intentAction(NotificationClient.FCM_INTENT_ACTION)
.build()
val pushResult = notificationClient?.handleCampaignPush(notificationDetails)
if (NotificationClient.CampaignPushResult.NOT_HANDLED != pushResult) {
/** アプリがフォアグラウンドの場合、 alertを表示する */
if (NotificationClient.CampaignPushResult.APP_IN_FOREGROUND == pushResult) {
/* Create a message that will display the raw data of the campaign push in a dialog. */
val dataMap = HashMap(remoteMessage?.data)
broadcast(remoteMessage?.from, dataMap)
}
return
}
}
private fun broadcast(from: String?, dataMap: HashMap<String, String>) {
val intent = Intent(ACTION_PUSH_NOTIFICATION)
intent.putExtra(INTENT_SNS_NOTIFICATION_FROM, from)
intent.putExtra(INTENT_SNS_NOTIFICATION_DATA, dataMap)
LocalBroadcastManager.getInstance(this).sendBroadcast(intent)
}
companion object {
val TAG = PushListenerService.javaClass.simpleName
// Intent action used in local broadcast
val ACTION_PUSH_NOTIFICATION = "push-notification"
// Intent keys
val INTENT_SNS_NOTIFICATION_FROM = "from"
val INTENT_SNS_NOTIFICATION_DATA = "data"
/**
* Helper method to extract push message from bundle.
*
* @param data bundle
* @return message string from push notification
*/
fun getMessage(data: Bundle): String {
return (data.get("data") as HashMap<*, *>).toString()
}
}
}
3. Activity側でpinpoint等のSDKの初期化を行う
import android.content.*
import android.os.Bundle
import android.support.v4.content.LocalBroadcastManager
import android.support.v7.app.AlertDialog
import android.support.v7.app.AppCompatActivity
import android.util.Log
import android.widget.Button
import android.widget.TextView
import android.widget.Toast
import com.amazonaws.auth.AWSCredentialsProvider
import com.amazonaws.mobile.client.AWSMobileClient
import com.amazonaws.mobile.config.AWSConfiguration
import com.amazonaws.mobileconnectors.pinpoint.PinpointConfiguration
import com.amazonaws.mobileconnectors.pinpoint.PinpointManager
import com.amazonaws.mobileconnectors.pinpoint.targeting.endpointProfile.EndpointProfileUser
import com.google.firebase.iid.FirebaseInstanceId
import java.util.*
class MainActivity : AppCompatActivity() {
private var credentialsProvider: AWSCredentialsProvider? = null
private var configuration: AWSConfiguration? = null
private val notificationReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
Log.d(TAG, "Received notification from local broadcast. Display it in a dialog.")
val bundle = intent.extras
val message = PushListenerService.getMessage(bundle!!)
AlertDialog.Builder(this@MainActivity)
.setTitle("Push notification")
.setMessage(message)
.setPositiveButton(android.R.string.ok, null)
.show()
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// AWS Mobile Client インスタンスを初期化
AWSMobileClient.getInstance().initialize(this) {
// AWSCredentialsProvider及びAWSConfigurationオブジェクトへの参照を取得しておく
credentialsProvider = AWSMobileClient.getInstance().credentialsProvider
configuration = AWSMobileClient.getInstance().configuration
}.execute()
val config = PinpointConfiguration(
this@MainActivity,
AWSMobileClient.getInstance().credentialsProvider,
AWSMobileClient.getInstance().configuration
)
// PinpointManager初期化。セッション開始
pinpointManager = PinpointManager(config)
pinpointManager?.sessionClient?.startSession()
pinpointManager?.analyticsClient?.submitEvents()
// カスタムエンドポイント設定
val interestsList = Arrays.asList("science", "politics", "travel")
pinpointManager?.targetingClient?.addAttribute("Interests", interestsList)
pinpointManager?.targetingClient?.updateEndpointProfile()
// ユーザーIDをエンドポイントに割り当てる
val endpointProfile = pinpointManager?.targetingClient?.currentEndpoint()
val user = EndpointProfileUser()
user.userId = "UserIdValue"
endpointProfile?.user = user
Log.d("a", "endpointId = " + endpointProfile?.endpointId)
pinpointManager?.targetingClient?.updateEndpointProfile(endpointProfile)
// エンドポイントIDをコピー出来るように
findViewById<Button>(R.id.copy_endpoint_id).setOnClickListener {
(this.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager).let {
it.primaryClip = ClipData.newPlainText("", endpointProfile?.endpointId)
Toast.makeText(this, "コピー:${endpointProfile?.endpointId}", Toast.LENGTH_SHORT).show()
}
}
// エンドポイントIDを表示
findViewById<TextView>(R.id.end_point_id).text = "endpointId:${endpointProfile?.endpointId}"
}
override fun onPause() {
super.onPause()
// Unregister notification receiver
LocalBroadcastManager.getInstance(this).unregisterReceiver(notificationReceiver)
}
override fun onResume() {
super.onResume()
// Register notification receiver
LocalBroadcastManager.getInstance(this).registerReceiver(notificationReceiver,
IntentFilter(PushListenerService.ACTION_PUSH_NOTIFICATION))
}
/** Amazon Pinpoint イベント送信に関する設定*/
fun setUpForSendEvents() {
// Buttonを押した際の処理を定義
findViewById<Button>(R.id.button_send_ev).setOnClickListener {
val event = pinpointManager?.analyticsClient?.createEvent("clickEvButton")
?.withAttribute("hoge","clicked")
?.withAttribute("fuga","clicked")
?.withMetric("metric", Math.random())
// イベントを記録
pinpointManager?.analyticsClient?.recordEvent(event)
// 記録したイベントを一斉に送信
pinpointManager?.analyticsClient?.submitEvents()
}
}
companion object {
val TAG = MainActivity.javaClass.simpleName
private var pinpointManager: PinpointManager? = null
fun getPinpointManager(context: Context): PinpointManager? {
if (pinpointManager == null) {
val pinpointConfig = PinpointConfiguration(
context,
AWSMobileClient.getInstance().credentialsProvider,
AWSMobileClient.getInstance().configuration)
pinpointManager = PinpointManager(pinpointConfig)
FirebaseInstanceId.getInstance().instanceId
.addOnCompleteListener { task ->
val token = task.result.token
Log.d(TAG, "Registering push notifications token: $token")
pinpointManager!!.notificationClient.registerDeviceToken(token)
}
}
return pinpointManager
}
}
}
4. プッシュ通知を送信する
1. 生成されたエンドポイントを取得する
サンプルレポジトリ、もしくは上記サンプルコードをビルドしたアプリを起動すると、下記のようにエンドポイントIDが表示されてコピペが可能となります。
2. ダッシュボードから Test messaging
を選択
3. Push Notifications
を選択
4. Destinations
-> Endpoint IDs
を選択。テストアプリのエンドポイントIDを所得して入力する。
5. message
の Title
, Body
に適当な文字列を入れて送信
6. 端末にNotificationが送信される
成功すれば、入力した文字列がダイアログ表示されるはずです。
Pinpointのプロジェクトを作成した直後だと、エンドポイントIDを指定してもメッセージが送信出来ない場合がありますが、その場合はある程度時間を置いてから送信をすると、成功するようになりました。
サンプルプロジェクトだと、アプリがフォワードにいる場合はalert、そうでない場合はnotificatonが表示されるようになっています。
まとめ
AWS SDK及びPinpoint SDKの書き方に慣れていないので最初は少し違和感を感じましたが、割と簡単に導入出来たように感じます。プッシュ通知の仕組みを導入する際は、検討してみてはいかがでしょうか。