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:
- Generate the required keys -
SPAK Auxiliary
for the widget,SPAK Primary
for the containing app. - 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.