🎃
AWS Amplifyを使わず直PinpointからPush通知を受け取ってデータをactivityに渡す方法(android側の実装)
※android側の実装しか書いてないです。
サーバーサイドはドキュメント通りで大丈夫なはずです。
この件に関わるバグが発生したのでよければこちらも見てみてください
結論
- 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)
チャンネルネームが空文字だとクラッシュする模様
参考記事
Discussion