Skip to content

How to Use an Application Theme From a Client Application

This section describes how to use an application theme from a client application before starting the onboarding or restore flows.

Changes for Android Client

The Application Themes module allows you to download custom theming files for an application at runtime. The application is then responsible for providing these files to the Fiori UI Theming component.

The Foundation framework’s ThemeDownloadService.downloadTheme() API can check for available themes on the server side for the application and download them. The application can automatically apply theming on the controls used from the Fiori library. This feature requires Android API Level 30 and above as it makes use of the ResourceProvider feature of the Android operating system. The following sample code provided is relevant for view-based applications built using Kotlin.

In order to apply a theme the application needs to use the Theme.Fiori.Custom theme to pick up custom colors. This can be changed in the styles.xml file in the res/values folder like this:

<style name="AppTheme" parent="Theme.Fiori.Custom"/>

The ThemeDownloadService then needs to be used within the application to download and apply the custom theme. If the theme should be applied before authentication is performed, the SDKInitializer must be passed the API Key copied earlier from the Anonymous Access section of the SAP mobile service cockpit. The resulting code can look like this:

//The variable represents the instance of application.
//Add the `apiKey` here to enable anonymous access.
SDKInitializer.start(this, * services.toTypedArray(), apiKey = "<App-key>")

The specific point in the lifecycle of the application where the download of the theme takes place is up to the application. But if you want the theme to take effect immediately on the onboarding or restore flows, the application should make sure it has been downloaded to the client side and apply it before starting the flows.

The downloadTheme function needs to be passed the SAP Mobile Services Endpoint URL as well as the App-ID. It returns an array of the downloaded files. Note that the downloadTheme function uses a delta token so that the function returns “304 Not Modified” if the theme has not been updated in SAP Mobile Services since the last download.

The resulting code then can look like this:

private fun updateTheme(launchScreen: LaunchScreen) {
    val serviceUrl = "<mobileServicesURL>”
    val app_id = "<App-ID>"

    MainScope().launch {
        when (val result = getService(ThemeDownloadService::class)?.downloadTheme(serviceUrl, app_id)) {
            is ServiceResult.SUCCESS -> {
                Log.i("Theme Download", "Theme is downloaded to the local.")
            is ServiceResult.FAILURE -> {
                if(!("THEME_DOWNLOAD_SERVICE_THEME_NOT_MODIFIED".equals(result?.code?.name)) {
                    val message: String = result.message
                        fragmentManager = fManager,
                        message = message
                    Log.e("Theme Download", "Theme download failed with error message: $message")

Applying a Custom Theme

ThemeDownloadService provides the APIs required to get a theme file and logos:

  • getThemeFile() to get the theme file in JSON format
  • getLightLogo() to get the logo image for a light theme
  • getDarkLogo() to get the logo image for a dark theme

Regarding custom logos, there is no SDK logic currently available to apply them to the application. Most of the screens currently in the SDK assume that the logo is in the application resources (i.e., bundled into the app at build time), so there is no easy way to apply it broadly in this case. It is up to the application to use them where appropriate.

The sample code assumes that you define a WelcomeActivity screen with

    private val logos: Pair<Bitmap?, Bitmap?> ? by lazy {
        var lightLogo:Bitmap? = null
        var darkLogo:Bitmap? = null
        var options = BitmapFactory.Options()
        options.inJustDecodeBounds = false
        getService(ThemeDownloadService::class)?.let { service ->
            service.getLightLogo()?.also { logo ->  lightLogo = BitmapFactory.decodeFile(logo.path, options)}
        getService(ThemeDownloadService::class)?.let { service ->
            service.getDarkLogo()?.also { logo ->  darkLogo = BitmapFactory.decodeFile(logo.path, options)}
        return@lazy Pair(lightLogo, darkLogo)
    private fun checkLogo(launchScreen: LaunchScreen) {
        var isDarkMode = (application.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES
        var logoFile : Bitmap?
        if (isDarkMode){
            logoFile = logos?.second
        } else {
            logoFile = logos?.first
        logoFile?.let {
            var launchScreenImages = launchScreen.findViewById<ImageView>(

    private fun checkTheme() {
        val themeFile = getService(ThemeDownloadService::class)?.let { it.getThemeFile()}
        themeFile?.let {
            if(it.exists()) {
                val colorMapper = CustomColorMapper(application.applicationContext)
                var inputStream = it.inputStream()


Please note that:

  1. Themes need to be created based on the SAP Horizon Morning or Horizon Evening themes.
  2. Not every control property that may be themed in the UI Theme Designer has a mobile control equivalent. That is why not all controls may have the correct theming applied. The mapping may be refined by the developer to add missing properties. The manually changed themes.json file may be uploaded to mobile services to update the respective theme.
  3. For Android API Level 30 or above is required.

Last update: March 10, 2023