Android Live Notifications

Create and update dynamic notifications on Android Devices

Live Notifications

Android Live Notifications deliver live, dynamic content in notifications to enhance user engagement and app interactivity. This feature is similar to iOS's Live Activities but uses its own set of tools and APIs that enable similar functionalities. Android users must have push notifications enabled to receive a Live Notification.

Push versus Live Notifications

Live Notifications are an ongoing and constantly updating version of a push notification. The information stays on your screen in the same spot and keeps you informed with the latest.

Android widgets have provided real-time content directly on the home screen for some time. Widgets, in particular, are a staple of Android's Live Notification capability, offering customizable, at-a-glance views of app content without the need to open the app.

With OneSignal, you'll be able to send and update Live Notifications through the same Create Push Notification API but with additional parameters.

Requirements

  • Your Android project is integrated with the latest version of the OneSignal SDK.
  • Android users must have push notification permissions enabled.

Configuration

1. Configure Android Notification Service Extension

Create a new Notification Service Extension that implements the OneSignal INotificationServiceExtension interface, refer to Android Notification Service Extension for detailed instructions. Within this class, override methods to intercept and alter notifications before they are displayed to the user.

Create a custom notification layout

Android provides instructions to create a custom notification layout. Sample code can be found on our Github or below. If you would like to contribute to our sample code, please fork, and not clone, the repository.

Use Notification Extender. Instead of the standard NotificationCompat.Builder, use the Notification.setExtender method to modify your notifications for Live Notifications This allows you to apply your custom layout and any additional modifications programmatically.

package com.onesignal.sample.android;

import com.onesignal.notifications.IActionButton;
import com.onesignal.notifications.IDisplayableMutableNotification;
import com.onesignal.notifications.INotificationReceivedEvent;
import com.onesignal.notifications.INotificationServiceExtension;

public class NotificationServiceExtension implements INotificationServiceExtension {
    @Override
    public void onNotificationReceived(INotificationReceivedEvent event) {
        IDisplayableMutableNotification notification = event.getNotification();

        if (notification.getActionButtons() != null) {
            for (IActionButton button : notification.getActionButtons()) {
                // you can modify your action buttons here
            }
        }

        // this is an example of how to modify the notification by changing the background color to blue
        notification.setExtender(builder -> builder.setColor(0xFF0000FF));
        notification.setExtender(builder -> builder.setAutoCancel(false));

        //If you need to perform an async action or stop the payload from being shown automatically,
        //use event.preventDefault(). Using event.notification.display() will show this message again.
    }
}

2. Modify Android Manifest

Sample code can be found on our Github or below. Be sure to update the android:value on line 17 of your project.

<?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 static final String PROGRESS_LIVE_NOTIFICATION = "progress";

Create notification channels

Channels determine the visual/audio behaviors of the notification and must have an identifier. To learn more about notification channels, refer to Android's documentation.

static final String PROGRESS_CHANNEL_ID = "progress_channel";
progressChannel = new NotificationChannel(PROGRESS_CHANNEL_ID, "Progress Live Notification", NotificationManager.IMPORTANCE_LOW);
progressChannel.setDescription("Shows the progress of a download");
notificationManager.createNotificationChannel(progressChannel);

Design a Live Notification

Live Notifications are most valuable when they present time-sensitive and dynamic information that users would otherwise go into the app to obtain.

int currentProgress = liveNotificationUpdates
                        .getInt("current_progress");
builder = new NotificationCompat.Builder(context, PROGRESS_CHANNEL_ID)
            .setContentTitle("Progress Live Notification")
            .setContentText("It's working...")
            .setSmallIcon(android.R.drawable.ic_media_play)
            .setLargeIcon(BitmapFactory.decodeResource(context.getResources(), android.R.drawable.ic_dialog_info))
            .setOngoing(true)
            .setOnlyAlertOnce(true)
            .setProgress(100, currentProgress, false);
notificationManager.notify(PROGRESS_LIVE_NOTIFICATION, 1, builder.build());

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

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.

JSONObject liveNotificationPayload = Objects
    .requireNonNull(notification.getAdditionalData())
    .optJSONObject("live_notification");

Live Notification Schema

PropertyRequiredDescription
keyYesUsed to load the correct notification UI.
eventYesThe action to perform on the Live Notification.
event_attributesNoStatic data used to initialize the Live Notification; Self-defined schema that defines the data your notification needs.
event_updatesNoDynamic 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 event type from the Payload

String liveNotificationEvent = liveNotificationPayload.getString("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.

EventDescriptionRequired parameters
startStart the Live Notification with static and dynamic content that you want to display.event_attributes, event_updates
updateUpdate the Live Notification with new dynamic content.event_updates
endEnd 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.

  • Setevent_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_iddetermines 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.