Skip to Content
Technical Articles

Multiple User Mode Offline Mobile App with SAP BTP SDK for Android

Introduction

In SAP BTP SDK for Android version 3.3, we released a new feature called multiple user mode, which is designed for the enterprise scenario where one employee gets a shared device in the morning, goes out to the field, and then returns the device when the shift ends. The next morning, the employee may get a different device and the device that they used yesterday may be assigned to another user (thus, “multiple user mode”). Usually, the mobile app for this scenario will be an offline mobile app. Note that the one user/one device scenario is now referred to as “single user mode.”

So, in this post, we’re going to talk about the multiple user mode feature, and how it works with an offline mobile app.

Multiple User Mode

For single user mode app development, we already have a lot of things to consider. To manage user data for multiple users, it’s even more challenging. Fortunately, with the Flows component of the SAP BTP SDK for Android, we only need to add one more property, multipleUserMode, into the FlowContext when starting the onboarding flows to enable the multiple user mode feature.

setPrimaryButtonOnClickListener {
    val flowContext = FlowContext(
        appConfig = AppConfig.Builder().applicationId("app_id").build(),
        flowRequestCode = 100,
        multipleUserMode = true,
        flowStateListener = MyFlowStateListener(),
        flowActionHandler = MyFlowActionHandler())
    Flow.start(this@WelcomeActivity, flowContext)
}

With multipleUserMode =true in FlowContext, the Onboarding flow is identical to that of single user mode. After the Onboarding flow finishes, the mutlipleUserMode value will be saved into a local secure database. Subsequently, when another flow is started with a different multipleUserMode value in the same mobile app, the value saved in the database will be used.

After the Onboarding flow, the Sign-In screen will be different from the single user mode mobile app in that there will now be a SWITCH OR ADD USER button at the bottom of the screen. When the user clicks the button a  list of locally onboarded users  is displayed where the user, if already onboarded, can search for themselves and switch to their user profile. If they have not yet onboarded with this device, they can also create a new user account by clicking the Add User button on the action bar.

sign-in%20screen

sign-in and local user list screen

If you’re developing a multiple user mode online mobile app, then this sequence may be sufficient to your needs. However, the Flows component can also handle many different scenarios for you automatically, such as:

  • When creating a new user account, if that user has already been onboarded, the Flows component will prompt the user with a dialog to return to the user’s Sign-In
  • Manage the secure store for each user, and switch between the secure stores at the right time.
  • Manage the usage database for each user.

However, for offline mobile apps, there are some other considerations when the onboarding/restore process completes:

  • How to encrypt the offline database to let all users be able to access it?
  • When to sync the user’s data from the server side?
  • How to upload the previous user’s data?

Offline Mobile App Development

Now let’s talk about the details about how to develop an offline mobile app using the Flows component of the SAP BTP SDK for Android. Because offline itself is a complex topic, here we only talk about the key points related to the multiple user mode feature.

Offline Database Encryption

The first thing to be considered is the offline encryption key. Because the offline database is shared by all of the users on this shared device, this encryption key must be the same for all users. For this purpose, SAP Mobile Services provides an API to retrieve an encryption key. To enable this API, you have to check the Allow Upload of Pending Changes from Previous User (Enable Multiple User Mode) checkbox in the Mobile Services cockpit.

Please note that for single user mode offline mobile apps, even if this feature is enabled, the Flows component will NOT call the API to get the key, and therefore the client code needs to generate the offline encryption key itself.

Initialize SharedDeviceService with SDKInitializer

When using the Flows component to develop an offline mobile app, SharedDeviceService must be initialized using SDKInitializer.

private fun initializeServices() {
    val services = mutableListOf<MobileService>()
    services.add(SharedDeviceService("app_constant"))
    SDKInitializer.start(
        this,
        services = services.toTypedArray()
    )
}

The string constant in SharedDeviceService enhances the strength of the offline encryption key algorithm, making the offline encryption key more secure.

With SharedDeviceService initialized using SDKInitializer, the Flows component knows that this app is an offline app. Therefore, after the passcode is created for the user during onboarding, the Flows component calls the API to retrieve the offline database encryption key from SAP Mobile Services, saves it into the user’s secure store, and notifies the client code.

For the restore flow, the Flows component will retrieve the offline encryption key from the user’s secure store and notify the client code again.

Prepare OfflineODataParameter and OfflineODataProvider

For an offline mobile app, you need to use OfflineODataProvider to interact with the offline library. You would normally call the following APIs:

  1. Create an instance of OfflineODataProvider and add definition queries:
    offlineODataProvider = OfflineODataProvider(
        url,
        offlineODataParameters,
        ClientProvider.get(),
        delegate
    ).apply {
        val customersQuery = OfflineODataDefiningQuery("Customers", "Customers", false)
        addDefiningQuery(customersQuery)
        …
    }
    ​

    The offlineODataParameter parameter in this code snippet has three arguments related to multiple user feature:

    • currentUser: The current user ID.
    • isForceUploadOnUserSwitch: This should be ‘true’ for multiple user mode, ‘false’ otherwise.
    • storeEncryptionKey: The encryption key shared by all users on this device.

    We should create a new instance of OfflineODataProvider when a user switch occurs. When developing mobile apps using the Flows component, the correct location for this is in the onOfflineEncryptionKeyReady callback of FlowStateListener.

    override fun onOfflineEncryptionKeyReady(key: String?) {
      …
    
      val offlineODataParameters = OfflineODataParameters().apply {
        timeout = 5
        isEnableRepeatableRequests = true
        storeName = OFFLINE_DATASTORE
        currentUser = FlowContextRegistry.flowContext.getCurrentUserId()
        isForceUploadOnUserSwitch = UserSecureStoreDelegate.getInstance().getRuntimeMultipleUserMode()
        storeEncryptionKey = key
      }.also {
        // Set the default application version
        val customHeaders = it.customHeaders
        customHeaders[APP_VERSION_HEADER] = appConfig.applicationVersion
        // In case of offlineODataParameters.customHeaders returning a new object if customHeaders from offlineODataParameters is null, set again as below
        it.setCustomHeaders(customHeaders)
      }
      …
    }
    

    In the onOfflineEncryptionKeyReady callback:

    • currentUser can be retrieved from FlowContextRegistry.flowContext.getCurrentUserId().
    • isForceUploadOnUserSwitch can be retrieved using getInstance().getRuntimeMultipleUserMode(), which is the same value as in FlowContext for the very first user onboarding.
    • storeEncryptionKey is in the callback argument. For a single user mode mobile app, the Flows component will pass in a ‘null’ key in this callback. If your mobile app is single user mode, you need to generate the offline encryption key in your client code.

    To detect whether a user switch happens or not, we can compare the current and the previous user ID saved inside FlowContextRegistry.flowContext.

    Please note that the current and previous user IDs in FlowContextRegistry.flowContext change when the callback function of FlowStateListener, onUserSwitched, is called.

  2. Open and download (sync) with OfflineODataProvider:
    provider.open(
    {
       //open success handler
       if(userSwitched) {
          provider.download(…)
       }
    },
    {
       //open failure handler
    }
    )
    ​

    The correct location for this code could be in an Activity after the onboarding/restore flow finishes. The download API should only be called when a user switch occurs. At that time, the offline library will upload the pending changes for the previous user and then download the current user’s data.

UserSecureStoreDelegate is the delegate to the current user’s secure store You can use it to retrieve/save data from/into the current user’s secure store. For example, if the uploading of the previous user’s pending changes fails for any reason, the previous user ID can be retrieved from the offline library, allowing you to determine who the previous user was. You can then use the following code to retrieve the information from the local user database.

val user = UserSecureStoreDelegate.getInstance().getUserInfoById(OfflineWorkerUtil.offlineODataProvider!!.previousUser)

Summary

In this article, we briefly talked about the key points for developing an offline mobile app using multiple user mode. To get a better understanding of the concepts and code, we recommend generating an offline app using the SAP BTP SDK for Android wizard. Basically, the generated app follows the same approach described above, but with more sophisticated implementations, such as:

  • Executing offline background tasks within a Worker.
  • Reporting the synchronization progress.
  • Reporting network errors and transaction errors.
  • Handling the user switch event for different flows: onboarding, restore, and timeout_unlock, for example.

Please see the following blogs if you’re not familiar with the Flows component of the SAP BTP SDK for Android:

Please leave your comments below, or your questions at: https://answers.sap.com/tags/73555000100800001281

Be the first to leave a comment
You must be Logged on to comment or reply to a post.