Pinpoint notifications: Deep link doesn't work
Before opening, please confirm:
- [X] I have searched for duplicate or closed issues and discussions.
Language and Async Model
Kotlin, Kotlin - Coroutines, RxJava
Amplify Categories
Notifications
Gradle script dependencies
amplify = "2.14.12"
amplify = { module = "com.amplifyframework:core-kotlin", version.ref = "amplify" }
amplifyCognito = { module = "com.amplifyframework:aws-auth-cognito", version.ref = "amplify" }
amplifyPushPinpoint = { module = "com.amplifyframework:aws-push-notifications-pinpoint", version.ref = "amplify" }
amplifyAnalyticsPinpoint = { module = "com.amplifyframework:aws-analytics-pinpoint", version.ref = "amplify" }
amplifyRx = { module = "com.amplifyframework:rxbindings", version.ref = "amplify" }
implementation(libs.amplify)
implementation(libs.amplifyCognito)
implementation(libs.amplifyPushPinpoint)
implementation(libs.amplifyAnalyticsPinpoint)
implementation(libs.amplifyRx)
Environment information
# Put output below this line
------------------------------------------------------------
Gradle 8.4
------------------------------------------------------------
Build time: 2023-10-04 20:52:13 UTC
Revision: e9251e572c9bd1d01e503a0dfdf43aedaeecdc3f
Kotlin: 1.9.10
Groovy: 3.0.17
Ant: Apache Ant(TM) version 1.10.13 compiled on January 4 2023
JVM: 11.0.10 (JetBrains s.r.o. 11.0.10+0-b96-7281165)
OS: Mac OS X 14.4.1 x86_64
Please include any relevant guides or documentation you're referencing
https://docs.aws.amazon.com/pinpoint/latest/apireference/apps-application-id-messages.html#apps-application-id-messages-prop-apnsmessage-action
Describe the bug
I'm trying to use deep link in my android app. Seems like Amplify doesn't support it.
What I send from web Pinpoint:
{
"APNSMessage": {
"aps": {
"alert": ""
}
},
"GCMMessage": {
"notification": {
"title": "Merry Christmas",
"body": "Ho ho ho"
},
"Action": "DEEP_LINK",
"url": "link here",
"data": {
"url": "link here",
"screenTitle": "Lorem ipsum dolor sit amet, consectetur adipiscing elit",
"screenDescription": "Lorem ipsum dolor sit amet",
},
"ADMMessage": {
"data": {
"message": ""
}
},
"BaiduMessage": {
"title": "",
"description": ""
}
}
}
As you can see, I specified Action DEEP_LINK as it's described here: https://docs.aws.amazon.com/pinpoint/latest/apireference/apps-application-id-messages.html#apps-application-id-messages-prop-apnsmessage-action
Bu on the client side I receive a notification with no deep link. It means that app gets android.intent.action.MAIN as the intent action by tap. Intent's data is null.
I believe I've done everything correctly according: https://docs.amplify.aws/gen1/android/build-a-backend/push-notifications/set-up-push-notifications/ https://docs.amplify.aws/gen1/android/build-a-backend/push-notifications/register-device/ https://docs.amplify.aws/gen1/android/build-a-backend/push-notifications/record-notifications/
What could be the problem?
Reproduction steps (if applicable)
- Send a FCM push with a deep link
- Receive it on a device
- Tap on the notification Result: App is opened with no deep link. Intent: android.intent.action.MAIN, data: null
Code Snippet
// Put your code below this line.
Log output
// Put your logs below this line
amplifyconfiguration.json
{
"UserAgent": "aws-amplify-cli/2.0",
"Version": "1.0",
"auth": {
"plugins": {
"awsCognitoAuthPlugin": {
"IdentityManager": {
"Default": {}
},
"CredentialsProvider": {
"CognitoIdentity": {
"Default": {
"PoolId": "hidden",
"Region": "eu-west-1"
}
}
},
"CognitoUserPool": {
"Default": {
"PoolId": "hidden",
"AppClientId": "hidden",
"Region": "eu-west-1"
}
},
"PinpointAnalytics": {
"Default": {
"AppId": "hidden",
"Region": "eu-west-1"
}
},
"PinpointTargeting": {
"Default": {
"Region": "eu-west-1"
}
}
}
}
},
"analytics": {
"plugins": {
"awsPinpointAnalyticsPlugin": {
"pinpointAnalytics": {
"appId": "hidden",
"region": "eu-west-1"
},
"pinpointTargeting": {
"region": "eu-west-1"
}
},
"awsPinpointPushNotificationsPlugin": {
"pinpointAnalytics": {
"appId": "hidden",
"region": "eu-west-1"
},
"pinpointTargeting": {
"region": "eu-west-1"
}
}
}
},
"notifications": {
"appId": "hidden",
"region": "eu-west-1",
"plugins": {
"awsPinpointAnalyticsPlugin": {
"pinpointAnalytics": {
"appId": "hidden",
"region": "eu-west-1"
},
"pinpointTargeting": {
"region": "eu-west-1"
}
},
"awsPinpointPushNotificationsPlugin": {
"appId": "hidden",
"region": "eu-west-1",
"pinpointAnalytics": {
"appId": "hidden",
"region": "eu-west-1"
},
"pinpointTargeting": {
"region": "eu-west-1"
}
}
}
},
"IdentityManager": {
"Default": {}
},
"CredentialsProvider": {
"CognitoIdentity": {
"Default": {
"PoolId": "hidden",
"AppClientId": "hidden",
"AppId": "hidden",
"Region": "eu-west-1"
}
}
},
"CognitoUserPool": {
"Default": {
"PoolId": "hidden",
"AppClientId": "hidden",
"AppId": "hidden",
"Region": "eu-west-1"
}
},
"PinpointAnalytics": {
"Default": {
"PoolId": "hidden",
"AppClientId": "hidden",
"AppId": "hidden",
"Region": "eu-west-1"
}
}
}
GraphQL Schema
// Put your schema below this line
Additional information and screenshots
No response
Hi @Andrew0000 ,
Thanks for reporting the issue, one of our team members will take a look and post updates here.
Hi @Andrew0000 ,
I was not able to reproduce the issue. Have you also followed the steps in our Amplify doc and additionally followed the guide on how to enable DEEP linking in your project?
Let me know if there any additional steps that I missed. Meanwhile, I'll retry to replicate your issue.
additionally followed the guide on how to enable DEEP linking in your project?
Yes, we use deep links. It works with other notifications. As I understand, the problem happens even before this. The app is launched from the Amplify's notification with android.intent.action.MAIN action and null data in its intent. I logged the intent in my Activity's onCreate() as the earliest point before every in-app navigation. So there is just no data that the app can get a link from.
Have you also followed the steps in our Amplify doc
I believe so. But let me copy the code:
AndroidManifest:
<service
android:name=".PushNotificationService"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT"/>
</intent-filter>
</service>
App:
Amplify.addPlugin(AWSCognitoAuthPlugin())
Amplify.addPlugin(AWSPinpointAnalyticsPlugin())
Amplify.addPlugin(AWSPinpointPushNotificationsPlugin())
Amplify.configure(applicationContext)
PushNotificationService:
typealias AmplifyKt = com.amplifyframework.kotlin.core.Amplify
import com.amplifyframework.core.Amplify
import com.amplifyframework.notifications.pushnotifications.NotificationContentProvider
import com.amplifyframework.notifications.pushnotifications.NotificationPayload
import com.google.firebase.messaging.FirebaseMessagingService
import com.google.firebase.messaging.RemoteMessage
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.launch
import timber.log.Timber
class PushNotificationService : FirebaseMessagingService() {
private val scope = CoroutineScope(Dispatchers.Main + SupervisorJob())
override fun onNewToken(token: String) {
super.onNewToken(token)
Amplify.Notifications.Push.registerDevice(
token,
{ Timber.i("[PushNotificationService][Push][Auth][Amplify] Successfully registered device") },
{ Timber.e(it, "[PushNotificationService][Push][Auth][Amplify] Error registering device") },
)
}
override fun onMessageReceived(remoteMessage: RemoteMessage) {
super.onMessageReceived(remoteMessage)
scope.launch {
tryProcessWithPinpoint(remoteMessage)
}
}
private suspend fun tryProcessWithPinpoint(remoteMessage: RemoteMessage) {
val notificationPayload = NotificationPayload(NotificationContentProvider.FCM(remoteMessage.data))
val isAmplifyMessage = Amplify.Notifications.Push.shouldHandleNotification(notificationPayload)
if (isAmplifyMessage) {
AmplifyKt.Notifications.Push.handleNotificationReceived(notificationPayload)
}
}
}
It's a little none of my business, but I'm looking at com.amplifyframework.pushnotifications.pinpoint.PushNotificationsUtils and see nothing related to any link. Where is a link supposed to be put into the Intent?
fun showNotification(
notificationId: Int,
payload: PinpointNotificationPayload,
targetClass: Class<*>?
) {
CoroutineScope(Dispatchers.IO).launch {
val largeImageIcon = payload.imageUrl?.let { downloadImage(it) }
val notificationIntent = Intent(context, payload.targetClass ?: targetClass)
notificationIntent.putExtra("amplifyNotificationPayload", payload)
notificationIntent.putExtra("notificationId", notificationId)
val pendingIntent = PendingIntent.getActivity(
context,
notificationId,
notificationIntent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)
val notificationChannel = retrieveNotificationChannel()
val builder = if (isNotificationChannelSupported() && notificationChannel != null) {
NotificationCompat.Builder(context, payload.channelId ?: notificationChannel.id)
} else {
NotificationCompat.Builder(context)
}
builder.apply {
setContentTitle(payload.title)
setContentText(payload.body)
setSmallIcon(R.drawable.ic_launcher_foreground)
setContentIntent(pendingIntent)
setPriority(NotificationCompat.PRIORITY_DEFAULT)
setLargeIcon(largeImageIcon)
setAutoCancel(true)
}
with(NotificationManagerCompat.from(context)) {
notify(notificationId, builder.build())
}
}
}
UPD: I went deeper into AWSPinpointPushNotificationsActivity -> getIntentAction -> PinpointNotificationPayload.fromNotificationPayload ->
action?.get(PushNotificationsConstants.DEEPLINK) != null -> {
// Action is open deeplink
val deepLink = action[PushNotificationsConstants.DEEPLINK]
Intent(Intent.ACTION_VIEW, Uri.parse(deepLink))
}
data[PushNotificationsConstants.PINPOINT_DEEPLINK]?.let {
action.put(PushNotificationsConstants.DEEPLINK, it)
}
const val PINPOINT_DEEPLINK = "$PINPOINT_PREFIX.$DEEPLINK" // pinpoint.deeplink
So maybe I should use pinpoint.deeplink field in my pushes? Just a guess.
Yes, this formatting make deeplinks work:
{
"GCMMessage":{
"data":{
"Action": "DEEP_LINK",
"pinpoint.deeplink": "my url here (deeplink)",
"title": "A title",
"message":"A message"
}
}
}
Could you please confirm that a consumer/developer should use pinpoint.deeplink key in the message in order to make deeplinks work? I literally see no documentation regarding pinpoint.deeplink parameter and I found it only by looking at the Amplify's source code.
Hi @Andrew0000 ,
Glad that you found the solution to it. We will make sure to document these properly so that we can mitigate as many misunderstandings as possible.
Hi @yuhengshs ,
Although my finding works, it would be great if someone could confirm its correctness or provide a code snippet that worked as you mentioned in the first reply. Just to make sure there are no hidden pitfalls in my finding.
@Andrew0000 That looks correct. Amplify is coded to handle templates from using the "Standard message" with "Open a deep link" Action on the Pinpoint console. Using these parameters appears to send as "pinpoint.deeplink".
If you are using the "Raw message" format, then you would still have to follow the same spec as the deep link standard message behavior.
This looks like missing documentation on the Pinpoint site to clarify how the template actions translate into the resulting raw message.