Technology Blogs by SAP
Learn how to extend and personalize SAP applications. Follow the SAP technology blog for insights into SAP BTP, ABAP, SAP Analytics Cloud, SAP HANA, and more.
cancel
Showing results for 
Search instead for 
Did you mean: 
qiang_zhang3
Advisor
Advisor

Introduction


To develop a mobile app with SAP BTP SDK for Android, theming could be a big puzzle which contains many pieces. This document shows how to do this with the view-based flows component before SAP BTP SDK for Android version 5.1. After 'ThemeDownloadService' was introduced in 5.1, there are more pieces come into play. The following links provide information on how to do this with the 'foundation' and 'flows' components of SAP BTP SDK for Android.

This blog will try to put all the pieces together with the Jetpack Compose flows component introduced in SAP BTP SDK for Android version 6.0, to show how easy it would be to customize theme in your apps with SAP BTP SDK for Android.

'FioriHorizonTheme' and 'BaseAttributes'



'FioriHorizonTheme' would be the root container of your UI elements when developing an Android app with the Jetpack compose. and 'BaseAttributes' is where you can put your customized theming information. For example
val attributes: BaseAttributes = ...
CompositionLocalProvider(
LocalCustomizedFioriHorizonAttributes provides CustomizeAttributeHolder(attributes)
) {
FioriHorizonTheme {
//your composable
}
}

With this code, the colors, shapes and typography in 'attributes' would apply to the UI elements under the 'FioriHorizonTheme' tree. And the pieces of customizing theme are built on top of this.

'CustomStyle' in 'FlowOptions'


To let your code pass in your custom theming information, Jetpack compose-based flows component of SAP BTP SDK for Android has a property defined in 'FlowOptions', like this:
data class FlowOptions(
...
val customStyles: CustomStyles = CustomStyles(),
...
)

data class CustomStyles(
val lightThemeAttributes: BaseAttributes = BaseAttributes(baseColors = fioriHorizonMorningColors.duplicate()),
val darkThemeAttributes: BaseAttributes = BaseAttributes(baseColors = fioriHorizonEveningColors.duplicate()),
)

Implementing custom theme with code as above would be cumbersome, then Theme Designer could be the solution, and this blog has detailed information on how to use the designer and how to upload  to the cockpit.

ThemeDownloadService


After you design your theme with the theme designer, upload the file to the Mobile Service cockpit and set the 'current' theme, 'ThemeDownloadService' can be used to download the artifacts to the device. Here is the API reference.

'ThemeDownloadService' will unzip the downloaded file and save the files in a certain folder on the device. The files may contain the following things:

  • Customized colors

  • Light theme app logo image file

  • Dark theme app logo image file


Apply Custom Theme with Jetpack Compose-based Flows


If you don't have a screen before the onboarding and the restore flows, you can totally let the Jetpack Compose-based Flows component of SAP BTP SDK for Android apply the custom theme for you, then what you should do will be much easier:

  1. Before starting the onboarding or restore flow, 'ThemeDownloadService' needs to be initialized in 'SDKInitializer':
       //call this in onCreate of DemoApplication 
    private fun initServices() {
    val loggingService = LoggingService(autoUpload = false).apply {
    policy = LogPolicy(logLevel = "DEBUG", maxFileNumber = 2)
    logToConsole = true
    }
    val services = listOf(
    loggingService,
    ThemeDownloadService(applicationContext)
    )

    SDKInitializer.start(
    application = this,
    apiKey = "5f64ace3-0ba2-4ce3-92a9-08b49c3fe11c",
    services = services.toTypedArray()
    )
    }​


  2. After onboarding/restore flow, use 'FlowComposeTheme' as the root node of your UI element tree:
    class MainActivity : FragmentActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContent {
    FlowComposeTheme {
    MainNavHost()
    }
    }
    }
    ...
    }​



Internally, Jetpack compose-based Flows component would do the following for you:

  • During onboarding, after passcode creation step(passcode policy not enabled case is also supported), 'ThemeDownloadService' will be called to download the customized theme from Mobile Service.

  • The download process has a 'delta' check so the download would happen only for the very first time or theme updated at the server side.

  • If there are steps after the passcode creation stage, those screens will NOT apply the custom theme even it's already downloaded, this is to make sure the onboarding screens are all with the same look and feel.

  • Next time you start the app with the restore flow, the restore flow screens will apply the custom theme; after unlock the app with the passcode, flow will try to download the theme again to see if any updates were made.

  • Timeout flow will NOT do the download for the performance considerations.

  • If both 'ThemeDownloadService' and 'CustomStyles' in 'FlowOptions' are enabled, the final custom theme will merge the 2 sources together, for conflicts, the custom theme has higher priorities.


Anonymous Theme Download


If you have a screen before starting the onboarding or restore flows and you want to apply the custom theme on this screen. before the user being authenticated, then you have to glue to the above pieces by yourself.

  1. 'apikey' must be provided in SDKInitializer when initializing your services.
    SDKInitializer.start(
    application = this,
    apiKey = "5f64ace3-0ba2-4ce3-92a9-08b49c3fe11c",
    services = services.toTypedArray()
    )​


  2. After you call 'downloadTheme' API,  you can use the following API to get the custom colors from the downloaded artifacts:
    object CustomThemeHelper {
    suspend fun loadCustomColors(): CustomColors? = ...
    }​

    Please add the following dependency to use the API:
    implementation 'com.sap.cloud.android:flows-compose:$btpSdkVersion'


  3.  With the above 'CustomColors', call the following API to update the custom colors into your 'BaseAttributes':
    //'colors' is the 'CustomColors' get the from the above call
    updateColors(lightThemeAttributes, darkThemeAttributes, colors)​

    please add the following dependency to use the above API:
    implementation "com.sap.cloud.android:fiori-compose-customization:${version}"


  4.  Build your own composable 'Theme' and provide the above 'BaseAttributes' with 'LocalCustomizedFioriHorizonAttributes', then place your compose UIs under your 'Theme' tree:
    @Composable
    fun MyTheme(
    darkTheme: Boolean = isSystemInDarkTheme(),
    content: @Composable () -> Unit
    ) {
    val logoPainter = SDKInitializer.getService(ThemeDownloadService::class)?.let { service ->
    val logoPath =
    if (darkTheme) service.getDarkLogo()?.absolutePath
    else service.getLightLogo()?.absolutePath
    logoPath?.let {
    buildCustomLogo(
    customLogo = CustomLogo(
    imageType = ImageType.FILE,
    filePath = logoPath
    )
    )
    }
    } ?: painterResource(id = com.sap.cloud.mobile.fiori.compose.theme.R.drawable.ic_logo)
    CompositionLocalProvider(
    LocalFioriLogo provides FioriLogo(logoPainter),
    LocalCustomizedFioriHorizonAttributes provides CustomizeAttributeHolder(attributes)
    ) {
    FioriHorizonTheme {
    Surface(
    color = MaterialTheme.fioriHorizonAttributes.SapFioriColorS0,
    content = content
    )
    }
    }
    }​



Thanks for reading and looking forward to your feedback. If you have any questions, please leave them here:  https://answers.sap.com/tags/73555000100800001281