🎃

AWS Amplifyを使わず直PinpointからPush通知を受け取ってデータをactivityに渡す方法(android側の実装)

2022/11/25に公開

※android側の実装しか書いてないです。
サーバーサイドはドキュメント通りで大丈夫なはずです。

この件に関わるバグが発生したのでよければこちらも見てみてください
https://zenn.dev/arsaga/articles/57371023a4f077

結論

  • receiveOnBackGroundには受け取れるもののPushが届かないのでPush通知自体は自作する必要がある
  • データはIntent.putExtraして渡す
  • dataはPinpointのカスタムプロパティにJson形式で突っ込んでおくと楽
  • 受け取りはactivity.intent.extras.getStringして取得する

サンプルコード

override fun receiveOnBackGround(intent: Intent) {
        super.receiveOnBackGround(intent)
        val bundle = intent.extras ?: return
        val notificationJson =
            bundle.getString(PushNotificationKeyType.PinpointJsonBody.keyName) ?: return
        val notificationData = Json.decodeFromString<PushResponse>(notificationJson)

        // 通知チャンネルの作成
        val name = "hogehoge"
        val descriptionText = "fugafuga"
        val channelId = BuildConfig.APPLICATION_ID + name
        val channel =
            NotificationChannel(channelId, name, NotificationManager.IMPORTANCE_DEFAULT).apply {
                description = descriptionText
            }
        val notificationManager: NotificationManager =
            getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager

        // チャンネルをシステムに登録
        notificationManager.createNotificationChannel(channel)

        val senderId = bundle.getString(PushNotificationKeyType.SenderId.keyName)?.toIntOrNull()
            ?: (0..9999999).random()
        val pendingIntent: PendingIntent = Intent(this, MainActivity::class.java).let {
            it.putExtra(
                PushNotificationKeyType.PinpointJsonBody.keyName,
                notificationJson
            )
            it.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
            it.action = PushNotificationKeyType.PendingIntentPushActionId.keyName
            PendingIntent.getActivity(
                this,
                senderId,
                it,
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S)
                    PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
                else PendingIntent.FLAG_UPDATE_CURRENT
            )
        }

     val image =
            getBitmapFromUrl(bundle.getString(PushNotificationKeyType.PinpointNotificationImageUrl.keyName))
        //通知の実施
        notificationManager.notify(
            senderId,
            notificationCompatBuilder(
                this,
                channelId,
                bundle.getString(PushNotificationKeyType.PinpointNotificationTitle.keyName),
                bundle.getString(PushNotificationKeyType.PinpointNotificationBody.keyName),
                pendingIntent,
                image
            ).build()
        )
    }
    
private fun getBitmapFromUrl(url: String?): Bitmap? =
        if (!url.isNullOrBlank()) URL(url).openStream().use {
            try {
                BitmapFactory.decodeStream(it)
            } catch (e: Exception) {
                return@use null
            }
        } else null
    
private fun notificationCompatBuilder(
        context: Context,
        channelId: String,
        title: String?,
        message: String?,
        pendingIntent: PendingIntent?,
        image: Bitmap?
    ) = NotificationCompat.Builder(context, channelId)
        .setContentTitle(title)
        .setContentText(message)
        .setPriority(NotificationCompat.PRIORITY_DEFAULT)
        .setContentIntent(pendingIntent)
        .setAutoCancel(true)
        .setStyle(
            NotificationCompat.BigPictureStyle()
                .bigPicture(image)
        )

Bundle[mParcelledData.dataSize=]ってなんやねん

ハマりポイント1

push通知からputExtraして起動するactivityに値を渡し際に

activityから取得できる値が

Bundle[mParcelledData.dataSize=120]

みたいな感じになってしまっている

ハマりポイント1@結論 受け取れている

for (key in intent.extras?.keySet() ?: listOf()) {
            val value = intent.extras?.getString(key)
            Timber.d(
                "extrasKeyValue: $key $value}"
            )
        }

するとことで値をちゃんと確認できる。

元々普通に確認できていた気がしていたので謎のmParcelledDataになっていて無駄にハマった

ハマりポイント2

Push通知にintent.extrasして画面遷移させる場合

遷移した後バックしても無限ループしてしまう


ハマりポイント2@結論 ちゃんと消してあげる

activity?.intent?.removeExtra(PushNotificationKeyType.PinpointJsonBody.keyName)

的なことをして遷移処理した後でちゃんと値を消してあげる。

safeArgsで渡す場合は

private val args by navArgs<HogeArgs>()
private var navArgs: String? = null

override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        navArgs = args.announcementId
    }

してnavArgsの方を参照するようにしてあげる。


ハマりポイント3

// クラッシュする
// 通知チャンネルの作成
        val name = ""
        val descriptionText = ""
        val channelId = BuildConfig.APPLICATION_ID + name
        val channel =
            NotificationChannel(channelId, name, NotificationManager.IMPORTANCE_DEFAULT).apply {
                description = descriptionText
            }
        val notificationManager: NotificationManager =
            getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager

        // チャンネルをシステムに登録
        notificationManager.createNotificationChannel(channel)
	
// クラッシュしない
// 通知チャンネルの作成
        val name = "hogehoge"
        val descriptionText = "fugafuga"
        val channelId = BuildConfig.APPLICATION_ID + name
        val channel =
            NotificationChannel(channelId, name, NotificationManager.IMPORTANCE_DEFAULT).apply {
                description = descriptionText
            }
        val notificationManager: NotificationManager =
            getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager

        // チャンネルをシステムに登録
        notificationManager.createNotificationChannel(channel)

チャンネルネームが空文字だとクラッシュする模様

https://stackoverflow.com/questions/49072959/creating-a-notificationchannel-throws-an-illegalargumentexception

参考記事

https://developer.android.com/training/notify-user/build-notification?hl=ja

https://firebase.google.com/docs/cloud-messaging/android/receive#handling_messages

https://qiita.com/ryo_mm2d/items/77cf4e6da7add219c75c

https://muumuutech.hatenablog.com/entry/2021/05/31/205855

https://stackoverflow.com/questions/62639146/android-navargs-clear-on-back

https://www.chikach.net/category/android-app/appwidget-listview-fillin/

https://stackoverflow.com/questions/4520961/removing-extras-from-passed-in-intent

https://stackoverflow.com/questions/36877196/android-intents-passed-one-bundle-to-secondactivity

Discussion