Push Notifications¶
Setting up FCM Capability for an Application¶
The SAP BTP SDK for Android (6.0.0 and later) separates Firebase Push Service into an independent module, foundation-push-fcm
.
To enable FCM for your application, follow the Google documentation at Set Up a Firebase Cloud Messaging Client App on
Android
and add the foundation-push-fcm
module to your project.
Note
Firebase Cloud Messaging (FCM) is the new version of GCM. It inherits the reliable and scalable GCM infrastructure and provides new features. See the FAQ to learn more. If you are integrating messaging in a new app, start with FCM. GCM users are strongly recommended to upgrade to FCM in order to benefit from new FCM features today and in the future.
You can find how to set up GCM at Set up a Firebase Cloud Messaging client app on Android.
Setting up Baidu Push for an Application¶
The SAP BTP SDK for Android (5.1.0 and later) separates Baidu Push Service into an independent module, foundation-push-baidu
.
Before you use the Baidu Push Service you should familiarize yourself with the Baidu push development documentation.
Additionally, there are some prerequisites that need to be fulfilled:
- Download the Baidu push SDK from the Baidu website.
- Follow the tutorial and add the dependency to your project.
- Follow the tutorial and declare the customized receiver in
AndroidManifest.xml
. - Add the
foundation-push-baidu
module to your project. - Add the
BaiduPushService
instance withbaiduPushApiKey
from the Baidu push console.
val services = mutableListOf<MobileService>()
services.add(BaiduPushService().apply { baiduPushApiKey = "YourApiKey" })
Note
Note that the SDK implements FirebaseMessagingService
from FCM and PushMessageReceiver
from Baidu, so there is no need to implement them manually.
If needed, you can override them in AndroidManifest.xml
.
Handling Push Notifications Using FirebasePushService
and BaiduPushService
¶
The SAP BTP SDK for Android (4.0.0 and later) provides an abstract BasePushService
Class that simplifies push utilization.
FirebasePushService
and BaiduPushService
extend BasePushService
: FirebasePushService
is used for the Google Firebase push service, and BaiduPushService
is used for the Baidu push service.
To start the push service, add the FirebasePushService
or BaiduPushService
instance to the SDKInitializer.start
method. They will then handle the entire push process, including registration, unregistration, notification arrival, and so on.
//Firebase push service
SDKInitializer.INSTANCE.start(application, new MobileService[]{new FirebasePushService()}, null);
//Baidu push service
SDKInitializer.INSTANCE.start(application, new MobileService[]{new BaiduPushService()}, null);
//Firebase push service
SDKInitializer.start(application, FirebasePushService())
//Baidu push service
SDKInitializer.start(application, BaiduPushService())
Add a PushCallbackListener
to Display Notification Messages¶
Using FirebasePushService
and BaiduPushService
you can add listeners to receive messages sent from the server. You can also customize the content of the displayed notification messages.
FirebasePushService firebasePushService = new FirebasePushService();
firebasePushService.setPushCallbackListener((context, message) -> {
...
});
SDKInitializer.INSTANCE.start(application, new MobileService[]{firebasePushService}, null);
val firebasePushService = FirebasePushService().apply {
this.setPushCallbackListener { context, message ->
...
}
}
SDKInitializer.start(application, firebasePushService)
Handling Notifications From Foreground and Background¶
BasePushService
provides a new way to display notifications, providing ForegroundNotificationInterceptor
and BackgroundNotificationInterceptor
to handle notifications from the foreground and background. You need to set EnableAutoMessageHandling
to true when initializing FirebasePushService
and BaiduPushService
.
For the foreground notification, use a ForegroundPushNotificationReady
handler to decide when the notification should be displayed.
pushService.setEnableAutoMessageHandling(true);
pushService.setBackgroundNotificationInterceptor(pushNotificationEvent -> pushNotificationEvent.displayNotification(pushNotificationEvent.getPushRemoteMessage()));
pushService.setForegroundNotificationInterceptor(pushNotificationEvent -> {
pushNotificationEvent.displayNotificationWhen(pushNotificationEvent.getPushRemoteMessage(), ()->{
Activity activity = AppLifecycleCallbackHandler.getInstance().getActivity();
if (activity == null)
return false;
else
return !activity.getClass().getName().equals("packageName.app.WelcomeActivity");
});
});
services.add(PushService().apply {
setPushCallbackListener(FCMPushCallbackListener())
setPushServiceConfig(configPushServiceConfig())
isEnableAutoMessageHandling = true
setBackgroundNotificationInterceptor { pushEvent ->
pushEvent.displayNotification(pushEvent.pushRemoteMessage)
}
setForegroundNotificationInterceptor { pushEvent->
pushEvent.displayNotificationWhen(pushEvent.pushRemoteMessage, object: ForegroundPushNotificationReady{
override fun onConditionReady(): Boolean {
return AppLifecycleCallbackHandler.getInstance().activity?.let {
it.javaClass.name != "packageName.app.WelcomeActivity"
}?:false
}
})
}
})
BasePushService
has predefined some conditions, such as notifications not being displayed for activities that belong to the SDK. You can also add conditions using addForegroundPushNotificationConditions
. The following code sample adds the condition that notifications will not be displayed in the launcher activity, for example:
firebasePushService.addForegroundPushNotificationConditions(()->{
Intent packageIntent = getPackageManager().getLaunchIntentForPackage(getPackageName());
String actName = packageIntent.resolveActivity(getPackageManager()).getClassName();
return !actName.equals(AppLifecycleCallbackHandler.getInstance().getActivity().getClass().getName());
});
val service = getService(FirebasePushService::class.java.kotlin)
service!!.storeNotificationMessage(true, message, object : ForegroundPushNotificationReady {
override fun onConditionReady(): Boolean {
return !AppLifecycleCallbackHandler.getInstance().activity!!.javaClass.name.contains("WelcomeActivity")
}
})
You can also set customized ForegroundPushNotificationReady
for ForegroundNotificationInterceptor
. The following sample ensures that notifications from the foreground will not be displayed in packageName.app.WelcomeActivity
:
pushService.setForegroundNotificationInterceptor(pushNotificationEvent -> {
pushNotificationEvent.displayNotificationWhen(pushNotificationEvent.getPushRemoteMessage(), ()->{
Activity activity = AppLifecycleCallbackHandler.getInstance().getActivity();
if (activity == null)
return false;
else
return !activity.getClass().getName().equals("packageName.app.WelcomeActivity");
});
});
services.add(PushService().apply {
setForegroundNotificationInterceptor { pushEvent->
pushEvent.displayNotificationWhen(pushEvent.pushRemoteMessage, object: ForegroundPushNotificationReady{
override fun onConditionReady(): Boolean {
return AppLifecycleCallbackHandler.getInstance().activity?.let {
it.javaClass.name != "packageName.app.WelcomeActivity"
}?:false
}
})
}
})
In addition, BasePushService
can store the notification when it is not appropriate to display it. When ForegroundPushNotificationReady
is satisfied, BasePushService
will display the stored notification. For example, the following code shows the scenario where the notification will not be displayed in the activity whose name contains WelcomeActivity
. This will be useful when the user handles the notification message sent by the system.
FirebasePushService service = SDKInitializer.INSTANCE.getService(JvmClassMappingKt.getKotlinClass(FirebasePushService.class));
service.storeNotificationMessage(true, message, () -> !AppLifecycleCallbackHandler.getInstance().getActivity().getClass().getName().contains("WelcomeActivity"));
val service = getService(FirebasePushService::class.java.kotlin)
service!!.storeNotificationMessage(true, message, object : ForegroundPushNotificationReady {
override fun onConditionReady(): Boolean {
return !AppLifecycleCallbackHandler.getInstance().activity!!.javaClass.name.contains("WelcomeActivity")
}
})
For data messages that you do not want to be displayed, for example, update operations on certain entities, you can handle them using BackgroundNotificationInterceptor
and you do not have to invoke the displayNotification
method. BackgroundNotificationInterceptor
and ForegroundNotificationInterceptor
can be used independently of each other.
Update Badge Number¶
SAP BTP SDK for Android (5.1.0 and later) exposes a new property named isEnableBadgeMessage
in FirebasePushService
and BaiduPushService
to let end users use a unique notification ID to update the badge.
This property needs to be set during the initialization of FirebasePushService
and BaiduPushService
.
If the push request payload contains badge
property , then SAP BTP SDK for Android will recognize it as a badge message.
When SAP BTP SDK for Android inserts the notification into the system tray, the Android notification ID will always be -1.
This means that there will be only one badge message at a time.
For the isBadgeMessage
and Badge
properties of PushRemoteMessage
you can also change it in BackgroundNotificationInterceptor
and ForegroundNotificationInterceptor
, depending on your requirements, before the notification is sent to the system tray.
You can set your own badge channel badgeServiceChannel
when you initialize the push service.
If you do not set a badge channel, the SAP BTP SDK for Android will provide a default channel with the ID, Badge Message Channel
, which will only be used by badge messages.
Make Notifications Persistent¶
By default, notifications will be stored in the cache and will be cleaned when consumed or when the app crashes. In order to avoid lost notifications or collection goals, you can call setPersistedNotification
with true then notification will be stored in local database which is provided by SDK. The database is located at: "/data/data/{packagename}/databases/".
Initialize Remote Notification Client Parameters And Update Registration With Parameters¶
By default, register for push to SAP Mobile Services does not contain remote notification parameters.
However, the SAP BTP SDK for Android (5.0.0 and later) provides a new method, initRemoteNotificationParameters
, to initialize the register for push parameters.
The first time this method is invoked, the SDK will save the parameters into the SharedPreference
XML file and also read these parameters from SharedPreference
if not null.
The purpose of this action is to save the last set of changes to the remote notification parameters.
To update the existing parameters stored in SharedPreference
, you invoke the updateRegistration
method.
This generates a new register for push request to mobile services and updates the parameter values in SharedPreference
.
Push To Topic¶
It is important to strive for the right balance of mobile notifications so that users maintain interest and don't ignore important notifications. One way to maintain interest is to group notifications into topics and allow device users to subscribe and unsubscribe to topics. Use the Push to Topic method to send a notification to either all users or a list of users that are subscribed to the topic. The SAP BTP SDK for Android (6.0.0 and later) exposes three push to topic methods:
subscribeTopic
unsubscribeTopic
getAllSubscribedTopics
Note the following:
- Both FCM and Baidu support push to topic.
- Push to topic methods only work after a successful onboarding.
- Push topics are removed after a user switch on a device.
Subscribe to a Topic¶
Use the BasePushService
subscribeTopic
method to subscribe to a topic.
FirebasePushService service = SDKInitializer.INSTANCE.getService(JvmClassMappingKt.getKotlinClass(FirebasePushService.class));
service.subscribeTopic("TopicName", new RemoteNotificationClient.CallbackListener() {
@Override
public void onSuccess() {
//TO-DO
}
@Override
public void onError(@NonNull Throwable e) {
//TO-DO
}
});
val service = getService(FirebasePushService::class.java.kotlin)
service.s.subscribeTopic("TopicName", object : RemoteNotificationClient.CallbackListener {
override fun onSuccess() {
//TO-DO
}
override fun onError(e: Throwable) {
//TO-DO
}
})
Unsubscribe From a Topic¶
Use the unsubscribeTopic
method to unsubscribe from a topic.
service.unsubscribeTopic("TopicName", new RemoteNotificationClient.CallbackListener() {
@Override
public void onSuccess() {
//TO-DO
}
@Override
public void onError(@NonNull Throwable e) {
//TO-DO
}
});
service.unsubscribeTopic("TopicName", object : RemoteNotificationClient.CallbackListener {
override fun onSuccess() {
//TO-DO
}
override fun onError(e: Throwable) {
//TO-DO
}
})
Get All Subscribed Topics¶
Use the getAllSubscribedTopics
method to get all subscribed topics.
service.getAllSubscribedTopics(new RemoteNotificationClient.CallbackListenerWithResult() {
@Override
public void onSuccess(@NonNull ServiceResult.SUCCESS<String[]> result) {
//TO-DO
}
@Override
public void onError(@NonNull Throwable e) {
//TO-DO
}
});
service.getAllSubscribedTopics(object : RemoteNotificationClient.CallbackListenerWithResult {
override fun onSuccess(result: ServiceResult.SUCCESS<Array<String?>>) {
//TO-DO
}
override fun onError(e: Throwable) {
//TO-DO
}
})
Legacy Register For Push¶
Registering a Device Token¶
If you choose to override your own FirebaseMessagingService
from FCM or PushMessageReceiver
from Baidu, mobile services provides APIs for registering and unregistering device tokens. Device tokens are the UUID codes generated by the push provider. The device token obtained from push infrastructures such as FCM (or Baidu) should be registered with mobile services using the registerDeviceToken
method of the RemoteNotificationClient
class. The default push provider is FCM. For Baidu push you need to call setPushProvider
before registering the token.
This method must be invoked from the UI thread. It takes the device token and RemoteNotificationParameters
as parameters.
The callback methods are invoked on the UI thread.
RemoteNotificationParameters parameters = new RemoteNotificationParameters.Builder()
.build();
RemoteNotificationClient remoteNotificationClient = new RemoteNotificationClient();
remoteNotificationClient.registerDeviceToken(token,parameters,
new RemoteNotificationClient.CallbackListener() {
@Override
public void onSuccess() {
//Code for processing a successful response...
}
@Override
public void onError(Throwable result) {
//Handle failure here...
if (result instanceof HttpException) {
//HttpException type com.sap.cloud.mobile.foundation.networking.HttpException
HttpException ne = (HttpException)result;
Log.e("Http Exception: " , ne.message() + ", with Error code: " + ne.code());
} else {
Log.e("Exception occurred: ", result.getMessage());
}
}
}
);
val parameters = RemoteNotificationParameters.Builder()
.build()
val remoteNotificationClient = RemoteNotificationClient()
remoteNotificationClient.registerDeviceToken(token, parameters,
object : RemoteNotificationClient.CallbackListener {
override fun onSuccess() {
//Code for processing a successful response...
}
override fun onError(result: Throwable) {
//Handle failure here...
if (result is HttpException) {
//HttpException type com.sap.cloud.mobile.foundation.networking.HttpException
Log.e("Http Exception: ", result.message() + ", with Error code: " + result.code())
} else {
Log.e("Exception occurred: ", result.message)
}
}
}
)
Unregistering a Device Token¶
To disable notifications for mobile applications, delete the device token from the mobile service using the
unregisterDeviceToken
method. Once the unregistration is done, the server will not be
able to send a push notification to the device.
This method must be invoked from the UI thread. The callback methods are invoked on the UI thread.
RemoteNotificationClient remoteNotificationClient = new RemoteNotificationClient();
remoteNotificationClient.unregisterDeviceToken(
new RemoteNotificationClient.CallbackListener() {
@Override
public void onSuccess() {
//Code for processing successful response...
}
@Override
public void onError(Throwable result) {
//Handle error here...
if (result instanceof HttpException) {
//HttpException type com.sap.cloud.mobile.foundation.networking.HttpException
HttpException ne = (HttpException)result;
Log.e("Http Exception: " , ne.message() + ", with Error code: " + ne.code());
} else {
Log.e("Exception occurred: ", result.getMessage());
}
}
}
);
val remoteNotificationClient = RemoteNotificationClient()
remoteNotificationClient.unregisterDeviceToken(
object : RemoteNotificationClient.CallbackListener {
override fun onSuccess() {
//Code for processing successful response...
}
override fun onError(result: Throwable) {
//Handle error here...
if (result is HttpException) {
//HttpException type com.sap.cloud.mobile.foundation.networking.HttpException
Log.e("Http Exception: ", result.message() + ", with Error code: " + result.code())
} else {
Log.e("Exception occurred: ", result.message)
}
}
}
)
Notification Feedback¶
SAP Mobile Services provides a feedback service that a mobile application can use to acknowledge the
notification. Every notification message from the service carries a notificationid
that uniquely identifies the
notification. Using this unique identification value, the updateNotificationStatus
method can be used to update the
notification status.
The mobile service supports two statuses for feedback: NOTIFICATIONSTATUS.RECEIVED
and NOTIFICATIONSTATUS.CONSUMED
. The code sample below shows how to provide received feedback.
This method must be invoked from the UI thread. It takes the device notification ID and SettingsParameters
as parameters.
The callback methods are invoked on the UI thread.
RemoteNotificationClient remoteNotificationClient = new RemoteNotificationClient();
remoteNotificationClient.updateNotificationStatus(notificationId, RemoteNotificationClient.NOTIFICATIONSTATUS.RECEIVED,
new RemoteNotificationClient.CallbackListener() {
@Override
public void onSuccess() {
//Code for processing successful response...
}
@Override
public void onError(Throwable result) {
//Handle error here...
if (result instanceof HttpException) {
//HttpException type com.sap.cloud.mobile.foundation.networking.HttpException
HttpException ne = (HttpException)result;
Log.e("Http Exception: " , ne.message() + ", with Error code: " + ne.code());
} else {
Log.e("Exception occurred: ", result.getMessage());
}
}
}
);
val remoteNotificationClient = RemoteNotificationClient()
remoteNotificationClient.updateNotificationStatus(notificationId, RemoteNotificationClient.NOTIFICATIONSTATUS.RECEIVED,
object : RemoteNotificationClient.CallbackListener {
override fun onSuccess() {
//Code for processing successful response...
}
override fun onError(result: Throwable) {
//Handle error here...
if (result is HttpException) {
//HttpException type com.sap.cloud.mobile.foundation.networking.HttpException
Log.e("Http Exception: ", result.message() + ", with Error code: " + result.code())
} else {
Log.e("Exception occurred: ", result.message)
}
}
}
)