Android Push Notifications Integration Guide

This guide provides a comprehensive walkthrough for implementing and customizing push notifications using the Reteno SDK for Android.


Table of Contents

  1. Customize default notification channel
  2. Deeplinks
  3. Push notification events
  4. Handling custom data
  5. Image carousel
  6. Push subscription status
  7. Custom push notifications
  8. Migrate from legacy notification events

Customize default notification channel

By default, the Reteno SDK creates a notification channel with the following parameters:

  • ID: retenoId
  • Name: General
  • Description: Marketing notifications, news, app updates
  • Importance: IMPORTANCE_DEFAULT
  • Lights: disabled
  • Vibration: disabled
  • Lockscreen visibility: visible
  • Bypass DND: false
  • Show badge: true

To customize the default notification channel, use the defaultNotificationChannelConfig builder parameter during SDK initialization:

Note: The channel is created when the first push notification arrives in the app. After the channel is created, changes to these parameters are limited. Read more

Reteno.initWithConfig(
    RetenoConfig.Builder()
        .accessKey(...)
        .defaultNotificationChannelConfig { builder ->
            builder
                .setName("Custom name")
                .setDescription("Custom description")
                .setImportance(NotificationManagerCompat.IMPORTANCE_HIGH)
                .setLightColor(Color.RED)
                .setLightsEnabled(true)
                .setShowBadge(true)
                .setVibrationEnabled(true)
                .setVibrationPattern(longArrayOf())
                .setSound(...)
        }
        .build()
)
Reteno.initWithConfig(
    new RetenoConfig.Builder()
        .accessKey(...)
        .defaultNotificationChannelConfig((builder) -> {
            builder
                .setName("Custom name")
                .setDescription("Custom description")
                .setImportance(NotificationManagerCompat.IMPORTANCE_HIGH)
                .setLightColor(Color.RED)
                .setLightsEnabled(true)
                .setShowBadge(true)
                .setVibrationEnabled(true)
                .setVibrationPattern(longArrayOf())
                .setSound(...);
            return Unit.INSTANCE;
        })
        .build()
);

User-visible channel name and description can be modified at any time during the application lifecycle. To edit those, use RetenoNotifications.updateDefaultNotificationChannel:

RetenoNotifications.updateDefaultNotificationChannel(
    name = "New name",
    description = "New description"
)
RetenoNotifications.updateDefaultNotificationChannel(
    "New name",
    "New description"
);

Deeplinks

Read more

The Reteno SDK optimizes the user experience by attempting to open deep links directly within your app, bypassing the browser's app-selection step.

  • Behavior: If the app can handle the URL, it opens immediately. If not, it falls back to the system web browser.
  • Android 12+ compatibility: Ensure your app complies with web intent resolution changes. Read more
  • Setup: You must configure the appropriate Intent Filters in your AndroidManifest.xml. Read more

Push notification events

Push received

To start listening for receive events:

RetenoNotifications.received.addListener { bundle ->
}
RetenoNotifications.getReceived().addListener(bundle -> {
});

To stop listening for receive events:

val myListener = Procedure<Bundle> {
    //...
}
RetenoNotifications.received.removeListener(myListener);
Procedure<Bundle> myListener = bundle -> {
    //...
};
RetenoNotifications.getReceived().removeListener(myListener);

Bundle contains all push notification information from Firebase.

Push clicked

To start listening for click events:

RetenoNotifications.click.addListener { bundle ->
}
RetenoNotifications.getClick().addListener(bundle -> {
});

To stop listening for click events:

val myListener = Procedure<Bundle> {
    //...
}
RetenoNotifications.click.removeListener(myListener);
Procedure<Bundle> myListener = bundle -> {
    //...
};
RetenoNotifications.getClick().removeListener(myListener);

Bundle contains all push notification information from Firebase.

Push swiped from notification tray

To start listening for close events:

RetenoNotifications.close.addListener { bundle ->
}
RetenoNotifications.getClose().addListener(bundle -> {
});

To stop listening for close events:

val myListener = Procedure<Bundle> {
    //...
}
RetenoNotifications.close.removeListener(myListener);
Procedure<Bundle> myListener = bundle -> {
    //...
};
RetenoNotifications.getClose().removeListener(myListener);

Bundle contains all push notification information from Firebase.


Handling custom data

You can pass your custom data in push notifications using the Custom data box in the Reteno admin panel. You can handle this custom data payload in the Launcher activity or the activity that handles deeplinks in the onCreate or onNewIntent methods. Custom data is delivered via intent extras.

override fun onNewIntent(intent: Intent?) {
    super.onNewIntent(intent)
    val customDataValue = intent?.extras?.getString("customDataKey")
}
@Override
protected void onNewIntent(Intent intent) {
    super.onNewIntent(intent);
    String customDataValue = intent.getExtras().getString("customDataKey");
}

Alternatively, all custom data is also passed to all Push notification event listeners.

Note: If you send a push notification containing a link that your application cannot handle, the web browser will handle this link. In this case, the web browser handles the custom data payload. To retrieve custom data from such a push, check the next section.


Image carousel

In the Reteno admin dashboard, you may select up to 10 images to be sent with a push notification. On Android, the notification will be shown as a DecoratedCustomViewStyle. Images will be scaled to 500 × 250 px to satisfy Android OS limits. The carousel will flip images automatically with a 2500 ms interval.


Push subscription status

Your end-user may prohibit receiving pushes by disabling the Reteno notification channel or disabling notifications for your application in Android OS settings. In this case, the SDK will notify its servers to prevent sending push notifications to this specific device.

SDK checks notifications enabled status in these cases:
  • On app resume
  • On push received event
  • On settings changed in Android OS Settings menu (starting from Android 9.0, using system broadcast)

Once status false is sent to the server, the backend won't send any push notifications to this device until the end-user re-enables the channel/notifications. Once the end-user re-enables the channel/notifications, the server will be notified and will send push notifications again.


Custom push notifications

As an app developer, you may want to send not only Reteno marketing push notifications to your user, but your own pushes. These may be push notifications related to your app-specific functionality, like chat, calendar events, incoming call notification, etc.

To start listening for custom push notifications:

RetenoNotifications.custom.addListener { bundle ->
}
RetenoNotifications.getCustom().addListener(bundle -> {
});

To stop listening for custom push notifications:

val myListener = Procedure<Bundle> {
    //...
}
RetenoNotifications.custom.removeListener(myListener);
Procedure<Bundle> myListener = bundle -> {
    //...
};
RetenoNotifications.getCustom().removeListener(myListener);

Bundle contains all push notification information from Firebase.

IMPORTANT

  1. Don't send custom push notifications with a notification block in the JSON body. Use data only. This will guarantee that the BroadcastReceiver receives your data payload consistently.

    DON'T:

    {
      "to": "FCM_token",
      "notification": {
        "title": "Title_here",
        "body": "Body_here"
      }
    }

    DO:

    {
      "to": "FCM_token",
      "data": {
        "Name": "John",
        "Room": 4,
        "Building": 3
      }
    }
  2. Don't send the following key in your data payload: es_interaction_id.

    DON'T:

    {
      "to": "FCM_token",
      "data": {
        "Name": "John",
        "es_interaction_id": 123
      }
    }

Migrate from legacy notification events

If Android receivers were used to listen for push notification events, manifest conflicts can arise. They can be resolved in two ways:

Retaining legacy event receivers

If you do not want to migrate to new listeners yet, you should override meta-data manifest entries adding tools:node="replace". Receivers with <action> intent filter can be left intact.

     <meta-data
            android:name="com.reteno.Receiver.PushReceived"
            android:value="com.your.package.CustomReceiverPushReceived"
            tools:node="replace"/>

Migrating to new receivers

You can migrate your old receivers to new listener approach using this table:

EventMetadata nameNew receiver
Push receivedcom.reteno.Receiver.PushReceivedRetenoNotifications.received.addListener
Push clickedcom.reteno.Receiver.NotificationClickedRetenoNotifications.click.addListener
Push swiped from notification traycom.reteno.Receiver.NotificationDeletedRetenoNotifications.close.addListener
Custom push receivedAny receiver with <action android:name="com.reteno.custom-push" />RetenoNotifications.click.addListener