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


The Flows component of SAP BTP SDK for Android is to make the SAP Mobile Services onboarding process easier for the mobile developers. We released the view-based version 3 years ago, and many teams are using it now.

Now the Jetpack Compose version of the Flows Component of SAP BTP SDK for Android is released in version 6.0. We enhanced it a lot and make it more flexible and easy to use. Here are some screenshots of the demo app.



The Same


Comparing to the view-based version of Flows, the Compose version has the same concept, so your current project structure does not need any change, for example:

  • 'FlowContext' to host your flow configuration.

  • 'FlowOptions' to configure your flows.

  • 'FlowActionHandler' to insert your logic into the predefined flow execution.

  • 'FlowStateListener' to get notified by various states during onboarding and restore flows.


Differences and Enhancements


We also made many enhancements in the Compose version of Flows.

Start Flow


fun startFlow(
context: Context,
flowContext: FlowContext,
updateIntent: ((Intent) -> Unit)? = null,
callback: FlowActivityResultCallback = { _, _ -> }
) { ... }

This is the API to start a flow, it has 2 differences comparing to the view-based Flows.

  1. 'callback' has only 2 arguments, not 3 as in the view-based Flows. The first one is the result code, which could be either RESULT_OK or RESULT_CANCEL, the 2nd one is a 'data' intent.

  2. 'updateIntent' is a new argument, it enables the client code pass in different task flags as needed. For example, if the client code wants to start a flow outside an activity, 'FLAG_ACTIVITY_NEW_TASK' intent flag might be needed. It can also be used to pass in custom data. For example, the code below is trying to start a restore flow and do a logout during the restore flow.


FlowUtil.startFlow(
this,
flowContext = DemoApplication.getOnboardingFlowContext(this),
updateIntent = { intent ->
intent.addFlags(
Intent.FLAG_ACTIVITY_NEW_TASK
)
FlowUtil.prepareCustomBundle(intent) {
forceLogoutWhenRestore(true)
}
}
) { resultCode, _ ->
logger.debug("Back from restore flow to DeviceAuthorizationGrantActivity.")
if (resultCode == Activity.RESULT_OK) {
val intent = Intent(this, MainActivity::class.java).apply {
addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)
}
startActivity(intent)
}
finishAffinity()
}

Please be aware that the task manage of an Android app could be tricky, please be careful when using this to add intent flags.

Simplified FlowOptions


data class FlowOptions(
val fullScreen: Boolean = false,
val activationOption: ActivationOption = ActivationOption.QR_ONLY,
val useDefaultEulaScreen: Boolean = true,
val requireQRCodeConfirmScreen: Boolean = true,
val orientation: OnboardingOrientation = OnboardingOrientation.UNSPECIFIED,
val oAuthOption: OAuthOption = OAuthOption(),
val screenSettings: CustomScreenSettings = CustomScreenSettings(),
val qrCodeSecureOption: QRCodeSecureOption = QRCodeSecureOption.UNSPECIFIED,
val customStyles: CustomStyles = CustomStyles(),
val skipRestoreFlowScreens: Boolean = false,
val resetOnTimeoutSignInScreen: Boolean = false
) { ... }

This is the new 'FlowOptions' class, it's much simple than that in the view-based version. With the help of the 'copy' function of Kotlin data classes, it's much easier to be used. And we also removed some duplicated fields in the view-based Flows without impacting the extensibility and the existing features.

Suspend Functions in 'FlowStateListener'


The callback functions in 'FlowStateListener' and the execution sequences are the same as before, but all of them are marked 'suspend' in the Compose version of Flows. This will make the client code more easy to execute logic in different Dispatchers, and also make the execution sequence more easier to manage.

 
class DemoFlowStateListener(private val context: Context) : FlowStateListener() {
override suspend fun onHostTokenRenewed() {
super.onHostTokenRenewed()
UserSecureStoreDelegate.getInstance().getOAuthToken()?.also { token ->
logger.debug("Sending OAuth2 token to wearable...")
dataClientSender.sendOAuth2TokenToWearable(token.toString())
}
}
...
}

For example, the above code will send the OAuth token to the companion wearable app when a new token is retrieved in the phone app.

Known Issue Solved


In the view-based flows component, there is one known issue, the problem is solved in the compose version.

Migration


Migrating to the Jetpack Compose version of Flows component from the view-based version will NOT impact the existing app. After migration, the app can be accessed by doing a normal sign in, all the existing data will be still there. But for the development process, there are some changes you need to make:

  • Your project needs to depend on the new artifacts.
    implementation "com.sap.cloud.android:flows-compose:<sdk_version>"
    implementation "com.sap.cloud.android:onboarding-compose:<sdk_version>"​


  • Your project may also need other Fiori compose artifacts, like:
    implementation "com.sap.cloud.android:fiori-composable-theme:${version}",
    implementation "com.sap.cloud.android:fiori-compose-customization:${version}"​
    implementation "com.sap.cloud.android:fiori-compose-ui:${version}"


  • If you have 'CoroutineScope.launch' in your FlowStateListener callbacks, you can remove them if the logic inside must be available for the logic after the callback.

  • The way to customize the onboarding screen is different, you will need provide the 'CustomScreenSettings' in your 'FlowOptions'.


Summary


The Jetpack Compose version of Flows component is a whole new module to make your onboarding experience much more seamless and efficient. It's also more elegant, flexible and easy to use. If you want to know more about this new module, please see the document here.