Skip to content

Widget Extensions

Widget extensions were introduced in iOS 14. To create a widget extension for an app that was built using the SAP BTP SDK for iOS, you must follow the standard procedure for widget creation.

Additionally, you need to incorporate certain aspects of security and data sharing between the widget and the containing app into the design.

Application Security

Apps built with the SDK can use security measures such as user authentication and app-specific passcodes to protect access to the app and the app data.

When SAPFioriFlows is used, the SDK persists authentication information (authentication tokens) and other sensitive information in a secure store as part of the app initialization. The authentication information is required to make secure requests to mobile services. For apps that set a passcode, the app passcode is used to protect the secure store.

A widget extension:

  • Cannot take a passcode or biometric ID input from the user and therefore it cannot access the secure store.
  • Cannot communicate with the containing app directly since the widget extension and the app are separate processes, and therefore it cannot place data requests directly to the app.

Secure Communication With the Containing App

The security layer of the SDK supports widget extensions such that that the widget extension (referred to as the auxiliary) can communicate securely with the containing app (referred to as the primary).

The SDK generates a Symmetric Paired Access Key (SPAK) as an additional key to protect the secure store. The SPAK is used to access the secure store when data is requested from a widget extension, while the app passcode is used to access the secure store from the containing app.

The SPAK is split into two shares:

  • SPAK Auxiliary meant for the app extension (or the auxiliary)
  • SPAK Primary meant for the containing app (or the primary)

All data requests made from the widget must contain the SPAK Auxiliary. This can be achieved using the AuxiliaryDataRequest class from SAPFoundation.

Procedure

To show the data within your widget extension:

  1. Generate the required keys - SPAK Auxiliary for the widget, SPAK Primary for the containing app.
  2. Set the SPAK Auxiliary in all data requests from the widget extension.

Important

If you have already released your app and wish to introduce widget extensions, follow the process for Adding Widgets for Released Apps.

Generate Required Keys

The StoreManagerStep takes care of generating and storing the SPAK, SPAK Auxiliary and SPAK Primary internally. Configure the StoreManagerStep with auxiliaryParameters as shown below.

private func configuredStoreManagerStep() -> StoreManagerStep {
        let step = StoreManagerStep()
        ...
        step.auxiliaryParameters = getAuxiliaryParameters()
        return step
    }

    func getAuxiliaryParameters() -> AuxiliaryParameters {
        let obfuscatedPrimaryKey: [UInt8] = [52, 93, 21, 7, 76, 88, 77, 11, 17, 91, 21, 20, 15, 54, 5, 16, 39, 13, 57, 35, 14, 27, 20, 11, 3, 74, 49, 20, 23, 9, 42, 24, 4, 42, 38, 13, 82, 71, 15, 69, 52, 41, 41, 73]
        let apiKeyAuthenticationConfig: APIKeyAuthenticationConfig? = getAPIKeyAuthenticationConfig()
        let dataStore = try! AuxiliaryConfiguration.getSharedStore()
        let auxDataRequestManager: AuxiliaryDataRequestManager? = try? AuxiliaryDataRequestManager(dataStore: dataStore)
        let dataContainer: DefaultAuxiliaryDataRequest<WidgetDataKey>? = try? auxDataRequestManager?.getDataRequest()
        let eSPAKAuxiliary: Data? = dataContainer?.eSPAKAuxiliary
        let onboardingStatusName: String = AuxiliaryConfiguration.onboardingStatusName
        return AuxiliaryParameters(sharedStoreName: AuxiliaryConfiguration.sharedStoreName, sharedAccessGroup: AuxiliaryConfiguration.sharedAccessGroup, obfuscatedPrimaryKey: obfuscatedPrimaryKey, eSPAKAuxiliary: eSPAKAuxiliary, apiKeyAuthenicationConfig: apiKeyAuthenticationConfig, onboardingStatusName: onboardingStatusName)
    }

Set the SPAK Auxiliary in All Data Requests

All data requests from the widget must be made using the AuxiliaryDataRequest class from SAPFoundation, passing in the SPAK Auxiliary to the eSPAKAux parameter.

public func initiateDataRequest(requestInfo: WidgetDataKey) throws {
        let eSPAKAuxiliary = //fetch the eSPAKAuxiliary
        let request = DefaultAuxiliaryDataRequest<YourAuxiliaryDataKey>(info: requestInfo, eSPAKAux: eSPAKAuxiliary, kind: AuxiliaryConfiguration.widgetKind)
        try self.dataRequestManager.putDataRequest(dataRequest: request)
    }

Adding Widgets for Released Apps

If you have already released your app with the app passcode enabled, then the app passcode needs to be changed. This can be done by triggering the change passcode flow.

This is required to generate a new set of keys to protect the secure store when accessed by both the app and the widget extension.

Configure Your App for Background Tasks

To refresh the widget data when the app is in the background, you can use the BackgroundTasks framework introduced in iOS 13. To configure your app for background tasks, refer to BGTaskScheduler | Apple Developer Documentation.

SAPFioriFlows supports a background flow that allows processing of OnboardingSteps in the background. All OnboardingSteps will receive a callback to process background requests. In the OnboardingFlowProvider, configure the steps that will triggered as part of the background flow.

public var backgroundSteps: [OnboardingStep] {
        return [
            self.configuredStoreManagerStep(),
            self.configuredWelcomeScreenStep(),
            CompositeStep(steps: SAPcpmsDefaultSteps.configuration),
            OAuth2AuthenticationStep(presenter: FioriASWebAuthenticationSessionPresenter()),
            AuxiliaryCommunicationStep(),
        ]
    }

open class AuxiliaryCommunicationStep: OnboardingStep {

public func background(context: OnboardingContext, completionHandler: @escaping (OnboardingResult) -> Void) {
        //load data for widget
    }

Note

If you use the SAP BTP SDK Assistant for iOS to create your project structure, then the necessary code for widget creation and secure communication is generated.


Last update: November 18, 2021