14
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

iRidgeAdvent Calendar 2018

Day 21

Amazon Pinpointをモバイルアプリに導入して、とりあえずプッシュ通知が送れるようになるまで:Android編

Last updated at Posted at 2018-12-20

はじめに

Amazon Pinpointを導入してみた際の忘備録です。

本記事のスコープ

AWS Mobile SDK for Android を導入して、AndroidNative側でどのように設定をすればプッシュ通知を受け取れるのかまでをスコープとします。
AWSの設定に関しては、担当をしてくれた弊社エンジニアの記事 を参照してください。

サンプルレポジトリ

各種設定ファイルは各自取得・配置してください。
設定ファイルに関しては後ほど触れます。

Amazon Pinpointとは

ざっくりと紹介すると

  • プッシュ通知等が簡単に送れる
  • セグメントを定義して、対象のセグメントに対してのみプッシュ通知を送るなども可能
  • 各種アナリティクス(イベント送信・DAUなど)

以下、公式開発者ガイドより引用。

Amazon Pinpoint は、複数のメッセージングチャネル間で顧客とやり取りするために使用できる AWS サービスです。キャンペーンの> 目的に応じて、プッシュ通知、E メール、またはテキストメッセージ (SMS) を送信できます。

用意する事・ファイル

Pinpoint導入

だいたい、公式のガイドに沿って設定しています。

1. AWS Mobile SDK を導入する

build.gradleを編集

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 のプッシュ通知を受け付けるサービスを設定

AndroidManifest.xml
<service
     android:name=".PushListenerService">
     <intent-filter>
         <action android:name="com.google.firebase.MESSAGING_EVENT"/>
     </intent-filter>
 </service>
PushListenerService.kt
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の初期化を行う

MainActivity.kt
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 を選択

スクリーンショット 2018-11-22 16.25.18.png

4. Destinations -> Endpoint IDs を選択。テストアプリのエンドポイントIDを所得して入力する。

スクリーンショット 2018-11-22 16.25.45.png

5. messageTitle , Body に適当な文字列を入れて送信

スクリーンショット 2018-11-22 16.25.57.png

6. 端末にNotificationが送信される

成功すれば、入力した文字列がダイアログ表示されるはずです。
Pinpointのプロジェクトを作成した直後だと、エンドポイントIDを指定してもメッセージが送信出来ない場合がありますが、その場合はある程度時間を置いてから送信をすると、成功するようになりました。
サンプルプロジェクトだと、アプリがフォワードにいる場合はalert、そうでない場合はnotificatonが表示されるようになっています。

まとめ

AWS SDK及びPinpoint SDKの書き方に慣れていないので最初は少し違和感を感じましたが、割と簡単に導入出来たように感じます。プッシュ通知の仕組みを導入する際は、検討してみてはいかがでしょうか。

参考

14
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?