Customize Push Notification Functionality for Android Apps
The MobilePush Android SDK offers extensive customization options for notifications through the NotificationCustomizationOptions class and the Engagment UI. The example provided in the Initialize the SDK section of the Android Quickstart Guide depicts the basic configuration, requiring only the Small Icon Resource ID to be provided to the SDK. This example represents only the minimum configuration needed for displaying notifications on your Android apps with the SDK. For information on status bar icons, see Icons in Google’s Material Design documentation.
You can further customize push notifications by providing a Launch Intent Provider or specifying the action to be taken when a notification is tapped. For an example configuration, see Basic Customization.
You can also take complete control over push notifications, as described in the Full Control Customization section.
To facilitate additional customization such as deep linking or handling custom keys, use the NotificationMessage class.
Basic Customization
The NotificationCustomizationOptions class facilitates push notification customization through a NotificationChannelIdProvider, enabling the assignment of a specific Notification Channel for each NotificationMessage.
When you target apps that run Android 12 or later, specify the mutability of your Pending Intent. See Android Developer Documentation: Intents and Intent Filters.
Note
10.x or higher
1SFMCSdk.configure(applicationContext as Application, SFMCSdkModuleConfig.build{2 this.pushFeatureModuleConfig = PushFeatureConfig.builder().apply{3 // Other configuration values4 setNotificationCustomizationOptions(5 NotificationCustomizationOptions.create(R.drawable.ic_notification_icon,6 NotificationManager.NotificationLaunchIntentProvider {context, notificationMessage ->7 val requestCode = Random().nextInt()8 val url = notificationMessage.url9 when{10 url.isNullOrEmpty() ->11 PendingIntent.getActivity(12 context,13 requestCode,14 Intent(context, MainActivity::class.java),15 PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE16)17 else ->18 PendingIntent.getActivity(19 context,20 requestCode,21 Intent(Intent.ACTION_VIEW, url.toUri()),22 PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE23)24}25},26 NotificationManager.NotificationChannelIdProvider {context, notificationMessage ->27 if(TextUtils.isEmpty(notificationMessage.url)){28 NotificationManager.createDefaultNotificationChannel(context)29}else{30 "UrlNotification"31}32}33)34)35}.build()36})37{38 // Handle initialization status39}
8.x or higher
1SFMCSdk.configure(applicationContext as Application, SFMCSdkModuleConfig.build{2 pushModuleConfig = MarketingCloudConfig.builder().apply{3 // Other configuration values4 setNotificationCustomizationOptions(5 NotificationCustomizationOptions.create(R.drawable.ic_notification_icon,6 NotificationManager.NotificationLaunchIntentProvider {context, notificationMessage ->7 val requestCode = Random().nextInt()8 val url = notificationMessage.url9 when{10 url.isNullOrEmpty() ->11 PendingIntent.getActivity(12 context,13 requestCode,14 Intent(context, MainActivity::class.java),15 PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE16)17 else ->18 PendingIntent.getActivity(19 context,20 requestCode,21 Intent(Intent.ACTION_VIEW, Uri.parse(url)),22 PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE23)24}25},26 NotificationManager.NotificationChannelIdProvider {context, notificationMessage ->27 if(TextUtils.isEmpty(notificationMessage.url)){28 NotificationManager.createDefaultNotificationChannel(context)29}else{30 "UrlNotification"31}32}33)34)35}.build(applicationContext)36}){37 // TODO handle initialization status38}
7.x
1MarketingCloudSdk.init(applicationContext as Application, MarketingCloudConfig.builder().apply{2 // Other configuration values3 setNotificationCustomizationOptions(4 NotificationCustomizationOptions.create(R.drawable.ic_notification_icon,5 NotificationManager.NotificationLaunchIntentProvider {context, notificationMessage ->6 val requestCode = Random().nextInt()7 val url = notificationMessage.url()8 when{9 url.isNullOrEmpty() ->10 PendingIntent.getActivity(11 context,12 requestCode,13 Intent(context, MainActivity::class.java),14 PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE15)16 else ->17 PendingIntent.getActivity(18 context,19 requestCode,20 Intent(Intent.ACTION_VIEW, Uri.parse(url)),21 PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE22)23}24},25 NotificationManager.NotificationChannelIdProvider {context, notificationMessage ->26 if(TextUtils.isEmpty(notificationMessage.url())){27 NotificationManager.createDefaultNotificationChannel(context)28}else{29 "UrlNotification"30}31}32)33)34}.build(applicationContext)){35 // TODO handle initialization status36}
Icons
MobilePush SDK supports icons in various notification elements, including small icons (in the status bar and notification header), large icons (in the notification body) and rich button icons.
You can use icons by placing icon files in the PNG format inside drawables-**hdpi folders within your client app’s resources. The SDK then references these icons by their resource names (for example, ic_notification_icon).
Here’s how you can configure and set icons:
Small icons: Provide the resource ID within NotificationCustomizationOptions when using MarketingCloudConfigBuilder. Alternatively, you can specify the icon’s resource name directly in the Engagement UI.
Large icons: Provide the resource name and optional public URL for remote retrieval in the Engagement UI.
Rich button icons: Provide the resource names in the Engagement UI.
For example, to use an icon named ic_notification_icon.png, place it in the appropriate drawables-**hdpi folder. Then, provide ic_notification_icon as the resource name on the Engagement UI. If its a small icon, you can also specify the resource ID in NotificationCustomizationOptions when using MarketingCloudConfigBuilder.
Sound
You can customize notification channels by setting priorities, colors, and sounds. To use a custom sound in notifications, follow these steps:
Add the sound file to the app’s res/raw/ folder.
Create a notification channel for the audio file and configure it in the code using NotificationChannelIdProvider. This sample code creates a notification channel named myaudio, enables badges and lights, and sets a default importance level.
1/*2Create a notification channel for the audio file3*/4if(Build.VERSION.SDK_INT>= Build.VERSION_CODES.O){5 androidNotificationManager.createNotificationChannel(6 NotificationChannel(7 "myaudio", "myaudio",8 AndroidNotificationManager.IMPORTANCE_DEFAULT9).apply{10 setShowBadge(true)11 enableLights(true)12 setSound(13 Uri.parse("android.resource://${context.packageName}/${context.resources.getIdentifier("custom","raw", context.packageName)}"),14 AudioAttributes.Builder().setUsage(15 AudioAttributes.USAGE_NOTIFICATION_EVENT16).build()17)18})19}
In the Engagement UI, set the sound file name (including the extension) under the Custom option in Sound settings.
This sample code configures the MobilePush SDK for an Android application. It sets up notification customization options, including the small icon, launch intent, and notification channel ID.
1SFMCSdk.configure(applicationContext as Application, SFMCSdkModuleConfig.build{2 pushModuleConfig = MarketingCloudConfig.builder().apply{3 // Other configuration values4 setNotificationCustomizationOptions(5 // Set small icon via NotificationCustomizationOptions6 NotificationCustomizationOptions.create(R.drawable.ic_notification_icon,7 NotificationManager.NotificationLaunchIntentProvider{ context, notificationMessage ->8 val requestCode = Random().nextInt()9 val url = notificationMessage.url10 when{11 url.isNullOrEmpty() ->12 PendingIntent.getActivity(13 context,14 requestCode,15 Intent(context, MainActivity::class.java),16 PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE17)18 else ->19 PendingIntent.getActivity(20 context,21 requestCode,22 Intent(Intent.ACTION_VIEW, Uri.parse(url)),23 PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE24)25}26},27 NotificationManager.NotificationChannelIdProvider{ context, notificationMessage ->28 if(TextUtils.isEmpty(notificationMessage.url)){29 NotificationManager.createDefaultNotificationChannel(context)30}else if(notificationMessage.sound == NotificationMessage.Sound.CUSTOM){31 notificationMessage.soundName // This will be myaudio if sound sent with push is myaudio.mp332}else{33 "UrlNotification"34}35}36)37)38}.build(applicationContext)39}){40 // TODO handle initialization status41}
Full Control Customization
When providing a builder to the NotificationCustomizationOptions class, you’re responsible for managing all aspects of the notification’s display properties and tap actions, including Notification Channel creation, Launch Intent action, and so on.
You can access the NotificationCompat.Builder that would have been used by the SDK and use it as a baseline for modifications. Additionally, the SDK can create a default NotificationChannel for your application.
If you wish to have Marketing Cloud Engagement collect notification open analytics for your notifications, you must wrap your PendingIntent in the SDK’s analytics helper method NotificationManager.redirectForAnalytics().
1SFMCSdk.configure(applicationContext as Application, SFMCSdkModuleConfig.build{2 pushModuleConfig = MarketingCloudConfig.builder().apply{3 // Other configuration values4 setNotificationCustomizationOptions(5 NotificationCustomizationOptions.create {context, notificationMessage ->6 val builder = NotificationManager.getDefaultNotificationBuilder(7 context,8 notificationMessage,9 NotificationManager.createDefaultNotificationChannel(context),10 R.drawable.ic_notification_icon11)12 builder.setContentIntent(13 NotificationManager.redirectIntentForAnalytics(14 context,15 PendingIntent.getActivity(16 context,17 Random().nextInt(),18 Intent(context, MainActivity::class.java),19 PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE20),21 notificationMessage,22 true23)24)25}26)27}.build(applicationContext)28}){29 // TODO handle initialization status30}
7.x
1MarketingCloudSdk.init(applicationContext as Application, MarketingCloudConfig.builder().apply{2 // Other configuration values3 setNotificationCustomizationOptions(4 NotificationCustomizationOptions.create {context, notificationMessage ->5 val builder = NotificationManager.getDefaultNotificationBuilder(6 context,7 notificationMessage,8 NotificationManager.createDefaultNotificationChannel(context),9 R.drawable.ic_notification_icon10)11 builder.setContentIntent(12 NotificationManager.redirectIntentForAnalytics(13 context,14 PendingIntent.getActivity(15 context,16 Random().nextInt(),17 Intent(context, MainActivity::class.java),18 PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE19),20 notificationMessage,21 true22)23)24}25)26}.build(applicationContext)){status ->27 // TODO Handle initialization status28}
Configure Button and Carousel Actions
Marketers can configure the action when an end user taps a button or a carousel image in a push notification. The actions for Web URL and App URL require that you implement UrlHandler as a new SDK initialization method.
This example shows how to configure the SDK to handle button and carousel clicks in push messages.
9.x
1SFMCSdk.configure(applicationContext as Application, SFMCSdkModuleConfig.build{2 pushModuleConfig = MarketingCloudConfig.builder().apply{3 setApplicationId("{mc_application_id}")4 setAccessToken("{mc_access_token}")5 setSenderId("{fcm_sender_id}")6 setMarketingCloudServerUrl("{marketing_cloud_url}")7 setMid("{mid}")8 setNotificationCustomizationOptions("{your instance of NotificationCustomizationOptions}")910 // Tell the SDK how to handle button & Carousel clicks in a Push Notification11 setUrlHandler(UrlHandler{context, url, _ ->12 PendingIntent.getActivity(13 context,14 Random().nextInt(),15 Intent(Intent.ACTION_VIEW, Uri.parse(url)),16 PendingIntent.FLAG_UPDATE_CURRENT17)18})19 // Other configuration options20}.build(applicationContext)21}){22 // TODO handle initialization status23}
Implement Default and Custom Notification Channels
On devices that run Android 8.0 or later, the SDK creates a default notification channel called marketing to assign all notifications to it. To change the name of the default channel, set a string resource value for mcsdk_default_notification_channel_name.
You can create custom notification channels and assign channels to each notification, as depicted by the following example configuration.
8.x
1val channelId = "my_custom_channel"23if(Build.VERSION.SDK_INT>= Build.VERSION_CODES.O){4(getSystemService(Context.NOTIFICATION_SERVICE)as android.app.NotificationManager).createNotificationChannel(5 NotificationChannel(6 channelId,7 "Marketing Messages",8 android.app.NotificationManager.IMPORTANCE_DEFAULT9)10)11}1213SFMCSdk.configure(applicationContext as Application, SFMCSdkModuleConfig.build{14 pushModuleConfig = MarketingCloudConfig.builder().apply{15 // Other configuration options16 setNotificationCustomizationOptions(17 NotificationCustomizationOptions.create(18 R.drawable.ic_notification_icon,19 null,20 NotificationManager.NotificationChannelIdProvider {context, notificationMessage ->21 // Whatever custom logic required to determine which channel should be used for the message.22 channelId23}24)25)26}.build(applicationContext)27}){28 // TODO handle initialization status29}
7.x
1val channelId = "my_custom_channel"23if(Build.VERSION.SDK_INT>= Build.VERSION_CODES.O){4(getSystemService(Context.NOTIFICATION_SERVICE)as android.app.NotificationManager).createNotificationChannel(5 NotificationChannel(6 channelId,7 "Marketing Messages",8 android.app.NotificationManager.IMPORTANCE_DEFAULT9)10)11}1213MarketingCloudSdk.init(applicationContext as Application, MarketingCloudConfig.builder().apply{14 // Other configuration options15 setNotificationCustomizationOptions(16 NotificationCustomizationOptions.create(17 R.drawable.ic_notification_icon,18 null,19 NotificationManager.NotificationChannelIdProvider {context, notificationMessage ->20 // Whatever custom logic required to determine which channel should be used for the message.21 channelId22}23)24)25}.build(applicationContext)){26 // TODO handle initialization status27}
To assign a notification to a channel, implement the SDK NotificationChannelIdProvider interface. Ensure that you include a channel with your message. Otherwise, the app doesn’t display the message to the recipient.
You can customize channel priority, colors, and sounds. To use custom sounds, give each channel its own sound configuration while creating it. You can’t use sounds with the SDK default channel option.
Note
Notification Segmentation
You can deliver location messages to a subset of your MobilePush audience by using the Android SDK. For example, when a mobile device breaches a geofence or enters the vicinity of a Bluetooth beacon, the SDK can prompt a callback to your mobile app for assessing whether to display a message.
Your app can apply criteria, including information within the MobilePush message itself, to determine whether to show a push notification, geofence message, or beacon message. Here are some use cases.
Show the message if the user’s preferred store location is within the geofence region.
Show the message if the user has items in the app shopping cart and if the message has an “abandonedCart”:”true” custom key.
Show the message only when the store is open based on the app’s store location list and the region and local time.
Don’t show messages if the user isn’t logged in to the app.
Show specific messages based on the user’s customer profile. For example, customers who are coffee lovers get messages about coffee, but customers who prefer pastry receive a message to “buy coffee” when they’re in the shop.
In this example, to target only Gold loyalty-level customers for message delivery, the marketer sets the custom key loyaltyLevel to gold while creating the location message. Then, the message is shown only if the customer’s contact attribute is also set to gold.
8.x
1SFMCSdk.requestSdk{sdk ->2 sdk.mp{3 it.notificationManager.setShouldShowNotificationListener{message ->4 val messageLoyaltyLevel = message.customKeys["loyaltyLevel"]5 val customerLoyaltyLevel = it.registrationManager.attributes["loyaltyLevel"]67 messageLoyaltyLevel == "gold" && customerLoyaltyLevel == "gold"8}9}10}
7.x
1MarketingCloudSdk.requestSdk{sdk ->2 sdk.notificationManager.setShouldShowNotificationListener{message ->3 val messageLoyaltyLevel = message.customKeys()["loyaltyLevel"]4 val customerLoyaltyLevel = sdk.registrationManager.attributes["loyaltyLevel"]56 messageLoyaltyLevel == "gold" && customerLoyaltyLevel == "gold"7}8}
Push Delivery Analytics
Starting with version 9.0.0, the MobilePush Android SDK tracks successful delivery of push notifications to the SDK. To enable this feature, contact your Marketing Cloud admin.