Android live notifications
Create and update dynamic notifications on Android Mobile Devices
OneSignal's Android Live Notifications simulates iOS Live Activities for Android devices, delivering dynamic content through notifications to enhance user engagement and app interactivity. To receive Live Notifications, Android users must have push notifications enabled.
Requirements
- Your Android project is integrated with the latest version of the OneSignal SDK.
- Android users must have push notification permissions enabled.
Comparing push notifications and live notifications
Live Notifications allow you to display the most up-to-date information from your app in a dynamic notification for an event. Instead of getting multiple notifications, users get one notification with the latest changes over a set time updated through the same Create Message API to send push notifications.
Configuration
1. Configure Android Notification Service Extension
Create a new Notification Service Extension that implements INotificationServiceExtension
interface from OneSignal Android SDK. Within this class, override methods to intercept and alter notifications before they are displayed to the user.
Refer to Android Notification Service Extension for more details.
package com.onesignal.sample.android
import android.app.NotificationChannel
import android.app.NotificationManager
import android.content.Context
import android.os.Build
import com.onesignal.notifications.INotificationReceivedEvent
import com.onesignal.notifications.INotificationServiceExtension
import org.json.JSONObject
import java.util.logging.Logger
class NotificationServiceExtension : INotificationServiceExtension {
override fun onNotificationReceived(event: INotificationReceivedEvent) {
val context = event.context
val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as? NotificationManager
?: run {
logger.warning("NotificationManager not available.")
return
}
notificationManager.let {
if (!notificationChannelsCreated) {
createNotificationChannels(notificationManager)
}
}
// Use `additional_data`to submit the Live Notification payload.
val additionalData = event.notification.additionalData
val liveNotificationPayload = additionalData?.optJSONObject("live_notification")
if (liveNotificationPayload == null) {
logger.info("No live notification payload found. Showing original notification.")
return
}
event.preventDefault()
handleLiveNotification(event, liveNotificationPayload, notificationManager, context)
}
}
2. Modify Android Manifest
Update the Android Manifest with the following property:
<meta-data android:name="com.onesignal.NotificationServiceExtension"
android:value="com.onesignal.sample.android.NotificationServiceExtension" />
After updating, your manifest should look similar to the following code:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:name=".MainApplication"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.OneSignalAndroidSample"
tools:targetApi="31">
<meta-data android:name="com.onesignal.NotificationServiceExtension"
android:value="com.onesignal.sample.android.NotificationServiceExtension" />
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
3. Create Live Notification Types
A Live Notification Type indicates which Live Notification to start.
Define notification identifiers
Notification identifiers indicate which notification to load and are used as keys in the Notification payload
private const val PROGRESS_LIVE_NOTIFICATION = "progress"
Create notification channels
Channels determine the visual and audio behaviors of the notification and must have an identifier. To learn more about notification channels, refer to Android's documentation.
private fun createNotificationChannels(notificationManager: NotificationManager) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
if (notificationManager.getNotificationChannel(PROGRESS_CHANNEL_ID) == null) {
val progressChannel = NotificationChannel(
PROGRESS_CHANNEL_ID,
"Progress Live Notification",
NotificationManager.IMPORTANCE_LOW
).apply {
description = "Shows the progress of a download"
}
notificationManager.createNotificationChannel(progressChannel)
notificationChannelsCreated = true
logger.info("Notification channel created: $PROGRESS_CHANNEL_ID")
}
}
}
Design a Live Notification
When designing a Live Notification, you have the flexibility to create a notification design for each update type. Each design you create must be assigned a specific type, allowing for varied presentations of a Live Notification.
private fun updateProgressNotification(
liveNotificationUpdates: JSONObject,
context: Context,
notificationManager: NotificationManager
) {
val currentProgress = liveNotificationUpdates.optInt("current_progress", 0)
val builder = NotificationCompat.Builder(context, PROGRESS_CHANNEL_ID)
.setContentTitle("Progress Live Notifications")
.setContentText("It's working...")
.setSmallIcon(android.R.drawable.ic_media_play)
.setLargeIcon(BitmapFactory.decodeResource(context.resources, android.R.drawable.ic_dialog_info))
.setOngoing(true)
.setOnlyAlertOnce(true)
.setProgress(100, currentProgress, false)
notificationManager.notify(keyMap[PROGRESS_LIVE_NOTIFICATION]!!, builder.build())
logger.info("Updated progress notification with progress: $currentProgress")
}
It's important to consider:
- Duration Live Notification will live in the notification center
- Outcomes you're trying to achieve and what information is most important to display
- Simple in design so users are not overwhelmed
A Live Notification can have:
- Small icon & accent color
- Large icon & accent color
- App name
- Big picture
- Notification sound
- Action buttons
Android provides instructions to create a custom notification layout.
4. Extract the Live Notification payload
The additional_data
property is optional, so build accordingly. If you send a regular push, nothing will happen because there is no Live Notification payload.
val additionalData = event.notification.additionalData
val liveNotificationPayload = additionalData?.optJSONObject("live_notification")
Live Notification Schema
Property | Required | Description |
---|---|---|
key | Yes | Used to load the correct notification UI. |
event | Yes | The action to perform on the Live Notification. |
event_attributes | No | Static data is used to initialize the Live Notification; a Self-defined schema that defines the data your notification needs. |
event_updates | No | Dynamic content of the Live Notification. Must conform to the ContentState interface defined within your app's Live Notification. |
Example payload
{
"key": "celtics-vs-lakers",
"event": "start",
"event_attributes": {
"homeTeam": "Celtics",
"awayTeam": "Lakers",
"game": "Finals Game 1"
},
"event_updates": {
"quarter": 1,
"homeScore": 0,
"awayScore": 0,
}
}
5. Respond to Live Notification events
Obtain the Live Notification event type from payload
val liveNotificationEvent = liveNotificationPayload.optString("event", "")
Event types
There are three events that you must handle when implementing Live Notifications: start
, update
, and end
. The event your request contains determines which properties must be included in your request.
Event | Description | Required parameters |
---|---|---|
start | Start the Live Notification with static and dynamic content that you want to display. | event_attributes , event_updates |
update | Update the Live Notification with new dynamic content. | event_updates |
end | End the Live Notification. | None |
Usage
This is the Live Notification schema for our example.
{
"live_notification": {
"key": "string",
"event": "start | update | end",
"event_attributes": {
"widget_attribute": "string"
},
"event_updates": {
"widget_content_state": "string"
}
}
}
Start Live Notification
This is the first step in sending Live Notifications to your customers.
- Set
event_attributes
to initialize the static data for the Live Notification with. This data will not change during the lifetime of the Live Notification. - Set
event_updates
data to initialize the dynamic data for the Live Notification. This is the data that can and will change during the lifetime of the Live Notification. - A
collapse_id
determines which notification to update and enables us to emulate a "Live Activity" by updating the same notification instead of showing a new notification. Set a collapse ID that is unique to this Live Notification to ensure subsequent updates are reflected in the same notification.
Example cURL request
curl -X "POST" "https://api.onesignal.com/notifications" \
-H 'Authorization: BASIC <OS_REST_API_KEY>' \
-H 'Content-Type: application/json; charset=utf-8' \
-d $'{
"app_id": "<APP_ID>",
"target_channel": "push",
"isAndroid": true,
"collapse_id": "13"
"data": {
"live_notification": {
"key": "progress",
"event": "start",
"event_attributes": {},
"event_updates": {
"current_progress": 0
}
}
},
"headings": {
"en": "Start"
},
"contents": {
"en": "Starting Live Notification"
},
"include_aliases": {
"external_id": ["EID1", "EID2"]
}
}'
Update Live Notification
You can update a Live Notification as many times as you like, so long as it's started first.
- Set
event_updates
data to initialize the dynamic data for the Live Notification. This is the data that can and will change during the lifetime of the Live Notification and informs what to update your Live Notification's content with.
Example cURL request
curl -X "POST" "https://api.onesignal.com/notifications" \
-H 'Authorization: BASIC <OS_REST_API_KEY>' \
-H 'Content-Type: application/json; charset=utf-8' \
-d $'{
"app_id": "<APP_ID>",
"target_channel": "push",
"isAndroid": true,
"collapse_id": "13"
"data": {
"live_notification": {
"key": "progress",
"event": "update",
"event_attributes": {},
"event_updates": {
"current_progress": 80
}
}
},
"headings": {
"en": "Update"
},
"contents": {
"en": "Updating Live Notification"
},
"include_aliases": {
"external_id": ["EID1", "EID2"]
}
}'
End Live Notification
Example cURL request
curl -X "POST" "https://api.onesignal.com/notifications" \
-H 'Authorization: Basic <OS_REST_API_KEY>' \
-H 'Content-Type: application/json; charset=utf-8' \
-d $'{
"app_id": "<APP_ID>",
"target_channel": "push",
"isAndroid": true,
"collapse_id": "13"
"data": {
"live_notification": {
"key": "progress",
"event": "dismiss"
}
},
"headings": {
"en": "Dismissing"
},
"contents": {
"en": "Dismissing Live Notification"
},
"include_aliases": {
"external_id": ["EID1", "EID2"]
}
}'
Recommended
Prevent Auto-dismissal of Notifications
To keep a notification visible even after a user taps on it, call builder.setAutoCancel(false)
on your notification builder. This prevents the notification from being automatically dismissed, allowing it to stay in the notification tray until explicitly removed by the user or the app.
Updated about 2 months ago