Skip to content

Push Notifications

Setting up FCM Capability for an Application

To enable FCM for your application, follow the Google documentation at Set Up a Firebase Cloud Messaging Client App on Android.

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

Before you use the Baidu Push Service you should familiarize yourself with the Baidu push development documentation and In addition, there are some prerequisites that need to be fulfilled:

  • Download the Baidu push SDK from the Baidu website.
  • Follow the tutorial and copy the SO files and JAR file to your project.
  • Follow the tutorial and declare the Provider element in manifest.xml. Before you start BaiduPushService, you need to get the Baidu Push API key from the Baidu push console cockpit and set it with setBaiduPushApiKey.
pushService.setBaiduPushApiKey("APIKeyFromBaidu");
pushService.setBaiduPushApiKey("APIKeyFromBaidu");

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 manifest.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 do not have to invoke the displayNotification method. BackgroundNotificationInterceptor and ForegroundNotificationInterceptor can be used independently of each other..

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.

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)
            }
        }
    }
)

Last update: May 19, 2022