Android Notifications

Customizing notifications for Android

Notification Channels

Starting with Android O, each notification must assign a valid notification channel or the notification will not display. The SDK will automatically assign a default channel with the name “Notifications”. The default channel can be overridden either in AirshipConfigOptions or the notification channel can also be set per message by specifying the channel’s ID in the Push API.

Compat Notification Channels

Notification channel compat allows you to define notification channels for all Android versions. For pre-O Android devices, the Airship SDK will apply the notification channel settings on the notification before posting. This allows an app to define channels and use them across all devices.

Creating custom notification channels

override fun onAirshipReady(airship : UAirship) {

    // ...

    val channelCompat = NotificationChannelCompat(
        "customChannel", 
        "Breaking News!",
        NotificationManagerCompat.IMPORTANCE_DEFAULT
    )

    airship.pushManager
            .notificationChannelRegistry
            .createNotificationChannel(channelCompat)
}
@Override
public void onAirshipReady(@NonNull UAirship airship) {

    // ...

    NotificationChannelCompat channelCompat = new NotificationChannelCompat(
        "customChannel", "Breaking News!", NotificationManagerCompat.IMPORTANCE_DEFAULT);

    airship.getPushManager()
            .getNotificationChannelRegistry()
            .createNotificationChannel(channelCompat);
}
 Note

The Airship SDK will fall back to the default notification channel if you set a notification channel ID that doesn’t exist, so make sure that you created one with the same ID.

Clearing Notifications

Notifications can be cleared manually by using standard Android APIs on the NotificationManager or NotificationManagerCompat classes.

Clear all Notifications

NotificationManagerCompat.from(context).cancelAll()
NotificationManagerCompat.from(context).cancelAll();

Customizing Push Notifications

The AirshipNotificationProvider is the recommended factory as it provides full support for all of the Android push features.

All incoming push notifications are built using a class that implements the NotificationProvider .

The Airship SDK uses the AirshipNotificationProvider . With this provider, the standard Android Notification layout will use the application’s title and icon. A default big text style will be applied for all notifications.

Custom Notification Provider

Custom notification factories are supported, but may cause some Android Push features to no longer work. Only features that the custom factory implements will be available.

Custom Provider Example

public class CustomNotificationFactory implements NotificationProvider {
    @WorkerThread
    @NonNull
    @Override
    public NotificationArguments onCreateNotificationArguments(@NonNull Context context, @NonNull PushMessage message) {
        String channel = message.getNotificationChannel("defaultChannel");
        return NotificationArguments.newBuilder(message)
            .setNotificationChannelId(channel)
            .setNotificationId(message.getNotificationTag(), NotificationIdGenerator.nextID())
            .build();
    }

    @WorkerThread
    @NonNull
    @Override
    public NotificationResult onCreateNotification(@NonNull Context context, @NonNull NotificationArguments arguments) {
        PushMessage message = arguments.getMessage();

        // do not display a notification if there is not an alert
        if (UAStringUtil.isEmpty(message.getAlert())) {
            return NotificationResult.cancel();
        }

        // Build the notification
        NotificationCompat.Builder builder = new NotificationCompat.Builder(context)
                .setContentTitle("Notification title")
                .setContentText(message.getAlert())
                .setAutoCancel(true)
                // Make sure that your icon follows Google's Guidelines : a white icon with transparent background
                .setSmallIcon(R.drawable.notification_icon);

        // Notification action buttons
        builder.extend(new ActionsNotificationExtender(context, message, notificationId));

        return NotificationResult.notification(builder.build);
    }

    @WorkerThread
    public void onNotificationCreated(@NonNull Context context, @NonNull Notification notification, @NonNull NotificationArguments arguments) {
        // Called after the notification is built, right before posting the notifications. Apply any global
        // defaults to the notification
    }
}
public class CustomNotificationFactory : NotificationProvider {
    @WorkerThread
    override fun onCreateNotificationArguments(context: Context, message: PushMessage): NotificationArguments {
        val channel = requireNotNull(message.getNotificationChannel("defaultChannel"))
        return NotificationArguments.newBuilder(message)
                .setNotificationChannelId(channel)
                .setNotificationId(message.notificationTag, NotificationIdGenerator.nextID())
                .build()
    }

    @WorkerThread
    override fun onCreateNotification(context: Context, arguments: NotificationArguments): NotificationResult {
        val message = arguments.message

        // do not display a notification if there is not an alert
        if (message.alert.isNullOrEmpty()) {
            return NotificationResult.cancel()
        }
        // Build the notification
        val builder = NotificationCompat.Builder(context)
                .setContentTitle("Notification title")
                .setContentText(message.alert)
                .setAutoCancel(true)
                .setSmallIcon(R.drawable.notification_icon)
        // Notification action buttons
        builder.extend(ActionsNotificationExtender(context, message, notificationId))
        return NotificationResult.notification(builder.build())
    }

    @WorkerThread
    override fun onNotificationCreated(context: Context, notification: Notification, arguments: NotificationArguments) {
        // Called after the notification is built, right before posting the notifications. Apply any global
        // defaults to the notification
    }
}

For simple modifications, it is recommended to extend the AirshipNotificationProvider instead to ensure all Airship push features continue to work.

Extending AirshipNotificationProvider

public class CustomNotificationFactory extends AirshipNotificationProvider {

    public CustomNotificationFactory(
        @NonNull Context context,
        @NonNull AirshipConfigOptions configOptions
    ) {
        super(context, configOptions);
    }

    @WorkerThread
    @NonNull
    @Override
    protected NotificationCompat.Builder onExtendBuilder(
        @NonNull Context context,
        @NonNull NotificationCompat.Builder builder,
        @NonNull NotificationArguments arguments
    ) {
        builder = super.onExtendBuilder(context, builder, arguments);

        // Apply any defaults to the builder

        return builder;
    }
}
public class CustomNotificationFactory(context: Context, configOptions: AirshipConfigOptions) : AirshipNotificationProvider(context, configOptions) {
    @WorkerThread
    override fun onExtendBuilder(
        context: Context,
        builder: NotificationCompat.Builder,
        arguments: NotificationArguments
    ): NotificationCompat.Builder {
        val newBuilder = super.onExtendBuilder(context, builder, arguments)

        // Apply any defaults to the builder

        return newBuilder
    }
}

Register the provider during takeOff

@Override
public void onAirshipReady(UAirship airship) {
    airship.getPushManager()
           .setNotificationProvider(new CustomDefaultNotificationProvider());
}
override fun onAirshipReady(airship : UAirship) {
    airship.pushManager.notificationProvider = CustomDefaultNotificationProvider()
}

Available Notification Extenders

The SDK also provides several notification builder extenders to help support Android Push features.

ActionsNotificationExtender
Supports Android Notification Action Button API features.
PublicNotificationExtender
Supports Public Notification API features.
StyleNotificationExtender
Supports Android style API features.
WearableNotificationExtender
Supports Android Wear API features.

Interactive Notifications

Standard Interactive Notifications

Airship provides a set of standard Interactive Notification types (See: Built-In Interactive Notification Types). It is the type that determines which buttons and corresponding labels will be available when you send a push. See the next section for where to specify that in the push payload. You control what happens when you send the push separately, by tying each button ID to a specific action.

Custom Interactive Notification Types (Notification Action Button Groups)

If you want to define a custom Interactive Notification type, you must register a new notification action button group.

 Note

Airship reserves category IDs prefixed with ua_. Any custom groups with that prefix will be dropped.

Custom NotificationActionButtonGroups are supported by registering the groups with the PushManager right after UAirship.takeOff using the PushManager.addNotificationActionButtonGroup method.

Example

// Define actions for the group
NotificationActionButton hiButtonAction = new NotificationActionButton.Builder("hi")
        .setLabel(R.string.hi)
        .setIcon(R.drawable.your_icon_file)
        .setPerformsInForeground(true)
        .build();

NotificationActionButton byeButtonAction = new NotificationActionButton.Builder("bye")
        .setLabel(R.string.bye)
        .setIcon(R.drawable.your_icon_file)
        .setPerformsInForeground(true)
        .build();

// Define the group
NotificationActionButtonGroup buttonGroup = new NotificationActionButtonGroup.Builder()
        .addNotificationActionButton(hiButtonAction)
        .addNotificationActionButton(byeButtonAction)
        .build();

// Add the custom group
airship.getPushManager().addNotificationActionButtonGroup("custom group", buttonGroup);
// Define actions for the group
val hiButtonAction: NotificationActionButton = NotificationActionButton.Builder("hi")
        .setLabel(R.string.hi)
        .setIcon(R.drawable.your_icon_file)
        .setPerformsInForeground(true)
        .build()

val byeButtonAction: NotificationActionButton = NotificationActionButton.Builder("bye")
        .setLabel(R.string.bye)
        .setIcon(R.drawable.your_icon_file)
        .setPerformsInForeground(true)
        .build()

// Define the group
val buttonGroup = NotificationActionButtonGroup.Builder()
        .addNotificationActionButton(hiButtonAction)
        .addNotificationActionButton(byeButtonAction)
        .build()

// Add the custom group
airship.pushManager.addNotificationActionButtonGroup("custom group", buttonGroup)