Onboarding patterns

This section describes SAPFiori framework controls for implementing the Onboarding flows outlined in the Fiori Design Guidelines Onboarding patterns.

FUIWelcomeScreen

UIViewController is used to display a welcome/launch screen to the application for onboarding. The screen displays the application name, instructions on how to start the activation process, and an option to trigger the demo mode of the application. There are two versions of the launch screen. Version 1 does not have sign in. Version 2 has a sign in with an additional Activate button for the activation process.

The application can conform to protocol OnboardingDelegate to present the demo mode of the application by adopting with the didSelectDemoMode function and to proceed to sign in by implementing the didSelectSignIn function.

Image

FUIWelcomeScreen is implemented in FUIWelcomeScreen.storyboard. There are two ways to launch the screen:

  • Use another storyboard and use a Present Modally segue to the FUIWelcomeScreen storyboard in SAPFiori framework with com.sap.cp.sdk.ios.SAPFiori as Bundle.

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let vc = segue.destination as! FUIWelcomeScreen
vc.state = .isConfigured    //shows version2 of the launch screen
//without calling vc.view.layoutSubviews(), components are not initialized. For example, vc.welcomeDetailLabel is still nil.
vc.view.layoutSubviews()
vc.detailLabel.text = "Thank you for downloading SAP Project Companion for Managers."
vc.delegate = self
}

  • Load view controller programmatically:

let vc = FUIWelcomeScreen.createInstanceFromStoryboard()
vc.state = .isConfigured    //shows version2 of the launch screen
vc.detailLabel.text = "Thank you for downloading SAP Project Companion for Managers."
self.navigationController?.pushViewController(vc, animated: true)

The FUIWelcomeScreen is supported for iPad portrait and landscape orientation and iPhone portrait orientation only. Since the screens are not supported in iPhone landscape orientation, the application installed on iPhone must switch to portrait mode before presenting these screens. The AppDelegate must lock the screen orientation when these screens display, as demonstrated in the following code snippet.

Usage of FUIWelcomeScreen

In app’s AppDelegate:


public var inFUIWelcomeScreen: Bool = false

// implement this function to support only portrait orientation when FUIWelcomeScreen is displayed.
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
if !inFUIWelcomeScreen {
return .allButUpsideDown
} else {
return .portrait
}
}

Before presenting FUIWelcomeScreen:


// Let AppDelegate know that we are entering the screen
(UIApplication.shared.delegate as! AppDelegate).inFUIWelcomeScreen = true

// Make sure we rotate to portrait mode
let value = UIInterfaceOrientation.portrait.rawValue
UIDevice.current.setValue(value, forKey: "orientation")

// Present the screen
let vc = FUIWelcomeScreen.createInstanceFromStoryboard()
vc.detailLabel.text = "Thank you for downloading SAP Project Companion for Managers."
self.navigationController?.pushViewController(vc, animated: true)

To dismiss the screen:


vc.dismiss(animated: true, completion: nil)

// Let AppDelegate know that we are exiting the view
(UIApplication.shared.delegate as! AppDelegate).inFUIWelcomeScreen = false

FUIPasscodeController

FUIPasscodeCreateController, FUIPasscodeInputController and FUIPasscodeChangeController provide passcode and Touch ID screens with UI components for a typical modal window used for setting up a passcode and enabling iPhone native Touch ID for application authentication.

The strings used in FUIPasscodeSetupView, FUIPasscodeView, and FUITouchIDView are from localized Onboarding.strings file. The application can override these strings by setting the corresponding static variables in the FUIPasscodeController class at runtime.

Interface

FUIPasscodeCreateController

This UIViewController is to be used by the app to set up the passcode and enable Touch ID screen flows.

FUIPasscodeInputController

This UIViewController is to be used by the app to authenticate the user either by Touch ID or Passcode.

FUIPasscodeChangeController

This UINavigationController is to be used by app to change the passcode.

Changing the passcode does not affect existing Touch ID preferences. There are no additional screens to display to enable touchID in the change passcode flow.

Usage of FUIPasscodeController

Usage of FUIPasscodeCreateController

Before the navigation controller presents this FUIPasscodeCreateController, the following property needs to be set:

The application can also set this property for more passcode validation checks:

Here is the screen flow:

  • The first screen prompts the user to enter the passcode. After the user enters the passcode, which is validated with the FUIPasscodePolicy, the FUIPasscodeValidationDelegate provided function “validate” of validationDelegate is invoked for additional validation. The next screen displays upon successful validation. Image
  • The second screen prompts the user to enter the passcode again to verify it against what was entered in the first screen. The third screen displays when the passcodes match and touch ID is allowed in FUIPasscodePolicy. Image
  • The third screen prompts the user to enable or disable Touch ID authentication. If the user chooses “Enable”, the passcode is saved as a Touch ID protected keychain item so that the passcode can be retrieved by FUIPasscodeInputController later with Touch ID. Image

After the setup is complete, either with or without the third screen, the function shouldTryPasscode of the FUIPasscodeControllerDelegate is invoked. The delegate should either create a secure store with the passcode, or save the passcode in a secure manner.

This passcode create flow is implemented in FUIPasscodeCreateController.storyboard. There are two ways to invoke it:

  • Use another storyboard and add a Present Modally segue to the FUIPasscodeCreateController storyboard in SAPFiori‘s framework bundle “com.sap.cp.sdk.ios.SAPFiori”. The application programmer needs to provide the properties needed in UIController’s prepare for segue function:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let destination = segue.destination as! UINavigationController
let vc0 = destination.viewControllers[0]
let vc = vc0 as! FUIPasscodeCreateController
vc.delegate = passcodeControllerDelegate
}

  • Load it programmatically:

let storyboard = UIStoryboard(name: "FUIPasscodeCreateController", bundle: bundle)
let vc = storyboard.instantiateViewController(withIdentifier: "PasscodeCreateFirstViewController")
let passcodeVC = vc as! FUIPasscodeCreateController
// present the passcode view
let navController = UINavigationController(rootViewController: passcodeVC)
self.navigationController?.present(navController, animated: true, completion: nil)

Usage of FUIPasscodeInputController

Before the navigation controller presents this FUIPasscodeInputController, the following properties must be set up:

This controller tries to determine if Touch ID is enabled by retrieving the value from the keychain. If Touch ID is enabled, a Touch ID authentication popup prompts the user to authenticate with Touch ID.

If Touch ID authentication succeeds, the saved passcode is retrieved and the function shouldTryPasscode of the FUIPasscodeControllerDelegate implementation is invoked.

If Touch ID authentication is canceled or fails, the passcode view is shown to prompt the user to enter a passcode. After entering the passcode, the function shouldTryPasscode of the FUIPasscodeControllerDelegate implementation is invoked. Image

The delegate should dismiss this controller after the passcode is verified. isToShowCancelBarItem is false by default. When it is set to true, the cancel button displays on the navigation bar and can be used to dismiss the controller.

This passcode input flow is implemented in FUIPasscodeInputController.storyboard. There are two ways to invoke it:

  • Use another storyboard and add a Present Modally segue to the FUIPasscodeInputController storyboard in the SAPFiori framework bundle. The app programmer needs to provide the properties needed in UIController’s prepare for segue function:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let destination = segue.destination as! UINavigationController
let vc0 = destination.viewControllers[0]
let vc = vc0 as! FUIPasscodeInputController
vc.delegate = passcodeControllerDelegate
}

  • Load it programmatically:

let storyboard = UIStoryboard(name: "FUIPasscodeInputController", bundle: bundle)
let vc = storyboard.instantiateViewController(withIdentifier: "PasscodeInputViewController")
let passcodeVC = vc as! FUIPasscodeInputController

// present the passcode view
let navController = UINavigationController(rootViewController: passcodeVC)
self.navigationController?.present(navController, animated: true, completion: nil)

Usage of FUIPasscodeChangeController

Set up the following properties before presenting this FUIPasscodeChangeController:

Here is the screen flow:

  • The first screen prompts the user to enter the current passcode using FUIPasscodeInputController. This controller always uses the passcode for authentication only.
    Note: Even if touchID is enabled, the controller does not use touchID for authentication. After a passcode is entered, function shouldTryPasscode of the FUIPasscodeControllerDelegate implementation is invoked. The application should not dismiss the controller in the shouldTryPasscode implementation.

  • The second screen prompts the user to enter a new passcode, which is validated by the FUIPasscodePolicy. The FUIPasscodeControllerDelegate provided function validate of validationDelegate is invoked for additional validation. Upon validation success, the next screen displays.

  • The third screen prompts the user to enter the passcode again to verify the passcode entered in the second screen. After the setup is complete, the function shouldTryPasscode of the FUIPasscodeControllerDelegate is invoked. The delegate should either create a secure store with the passcode, or save the passcode in a secure manner.
    Note: Changing the passcode does not affect the existing Touch ID preferences. No additional screens display to enable touchID to change the passcode flow. If touchID was previously disabled before triggering the passcode change, touchID remains disabled. However, if touchID was previously enabled, the internal touchID-related data is automatically updated after the passcode is changed.

This passcode flow change is implemented in FUIPasscodeChangeController.storyboard. There are two ways to invoke it:

  • Use another storyboard and add a “Present Modally” segue to the FUIPasscodeChangeController storyboard in the SAPFiori framework bundle. The app developer must provide the required properties in the UIController’s prepare for segue function:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let changeController = segue.destination as! FUIPasscodeChangeController
changeController.passcodeControllerDelegate = passcodeControllerDelegate
changeController.validationDelegate = validationDelegate
}

  • Load it programmatically:
if let changeController = FUIPasscodeChangeController.createInstanceFromStoryboard() {
changeController.passcodeControllerDelegate = passcodeControllerDelegate
changeController.validationDelegate = validationDelegate
self.present(changeController, animated: true, completion: nil)
}

Both Passcode and Touch ID screens are supported for iPad portrait and landscape orientation and iPhone portrait orientation only. Since the screens are not supported in iPhone landscape orientation, the app installed on iPhone must switch to portrait mode before presenting these screens. The AppDelegate must lock the screen orientation when these screens display, as demonstrated in the following code snippet.

In app’s AppDelegate:


public var inPasscodeView: Bool = false

// implement this function to support only portrait orientation when FUIPasscodeView is displayed.
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
if !inPasscodeView {
return .allButUpsideDown
} else {
return .portrait
}
}

Before presenting the Passcode or Touch ID screen:


// Let AppDelegate know that we are entering FUIPasscodeView
(UIApplication.shared.delegate as! AppDelegate).inPasscodeView = true

// Make sure we rotate to portrait mode
let value = UIInterfaceOrientation.portrait.rawValue
UIDevice.current.setValue(value, forKey: "orientation")
// Present the passcode view
self.navigationController?.present(navController, animated: true, completion: nil)

After dismissing the Passcode or Touch ID screen:


passcodeController.dismiss(animated: true, completion: nil)
// Let AppDelegate know that we are exiting FUIPasscodeView
(UIApplication.shared.delegate as! AppDelegate).inPasscodeView = false

  • This UIViewController is base controller class to display a welcome/launch screen to the application for onboarding. *

    See more

    Declaration

    Swift

    open class FUIWelcomeController : UIViewController
  • This UIViewController is used to display a welcome/launch screen to the application for onboarding. The screen mainly displays the application name, instructions on how to start the activation process and an option to trigger the demo mode of the application.

    Welcome Screen

    Welcome Screen

    Application can implement the FUIWelcomeControllerDelegate protocol, to present the demo mode of the application by adopting with the didSelectDemoMode(_:) function, to proceed sign in by implementing the shouldContinueUserOnboarding(_:) function, to proceed configuration based on the configuration options by implementing the welcomeController(_:willNavigateToActivationScreen:), welcomeController(_:shouldTryUserEmail:), or welcomeController(_:willNavigateToScannerScreen:) functions.

    FUIWelcomeScreen is implemented in FUIWelcomeScreen.storyboard. There are two ways to launch the screen:

    • Use another story board and use a Present Modally segue to FUIWelcomeScreen storyboard in SAPFiori framework with com.sap.cp.sdk.ios.SAPFiori as Bundle. App programmer needs to provide the properties needed in UIController‘s prepare for segue function:
    
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    let vc = segue.destination as! FUIWelcomeScreen
    vc.state = .isConfigured
    vc.detailLabel.text = "Thank you for downloading SAP Project Companion for Managers."
    vc.delegate = self
    }
    
    
    • Programmatically loads it:
    
    let vc = FUIWelcomeScreen.createInstanceFromStoryboard()
    vc.state = .isConfigured
    vc.detailLabel.text = "Thank you for downloading SAP Project Companion for Managers."
    self.navigationController?.pushViewController(vc, animated: true)
    
    

    Settings for possible welcome screens being launched:

    • Launch with Standard: Application contains the necessary configurations to connect to mobile services, and should prompt user to Start.
    • state property: .isConfigured
    • configurationOptions property: not required. Value would be ignored.
    • delegate function(s) to be implemented: shouldContinueUserOnboarding(_:), didSelectDemoMode(_:) if isDemoAvailable is true.

    • Welcome Screen Launched with Link: Application has not been configured, and does not use FUIWelcomeScreen flow to obtain configuration.

    • state property: .notConfigured

    • configurationOptions property: empty value

    • delegate function(s) to be implemented: didSelectDemoMode(_:) if isDemoAvailable is true

    • Welcome Screen Launched with Discovery Service: Application has not been configured, and should prompt the end user for their email address.

    • state property: .notConfigured

    • configurationOptions property: .discoveryService

    • delegate function(s) to be implemented: welcomeController(_:shouldTryUserEmail:), didSelectDemoMode(_:) if isDemoAvailable is true

    • Welcome Screen Launched with Scanner: Application has not been configured, and should prompt the end user to launch the Barcode Scanner to obtain connection settings.

    • state property: .notConfigured

    • configurationOptions property: .barcodeScanner

    • delegate function(s) to be implemented: welcomeController(_:willNavigateToScannerScreen:), didSelectDemoMode(_:) if isDemoAvailable is true

    • Welcome Screen Launched with Activation: Application has not been configured, and should prompt the end user to pick between email address entry, or the Barcode Scanner, to obtain connection settings.

    • state property: .notConfigured

    • configurationOptions property: [.discoveryService, .barcodeScanner]

    • delegate function(s) to be implemented: welcomeController(_:willNavigateToActivationScreen:), didSelectDemoMode(_:) if isDemoAvailable is true

    Note that the FUIWelcomeScreen is supported for iPad portrait and landscape orientation and iPhone portrait orientation only. Since the screen is not supported in iPhone landscape orientation, the app needs to switch to portrait mode before presenting the screen. And AppDelegate needs to lock the screen orientation when these screens are shown, similar to the following code snippet.

    In app’s AppDelegate:

    
    public var inFUIWelcomeScreen: Bool = false
    
    // implement this function to support only portrait orientation when FUIWelcomeScreen is displayed in iPhone.
    func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
       if !inFUIWelcomeScreen {
           return .allButUpsideDown
       } else {
           return .portrait
       }
    }
    
    

    Before presenting the FUIWelcomeScreen:

    
    // Let `AppDelegate` know that we are entering the screen
    (UIApplication.shared.delegate as! AppDelegate).inFUIWelcomeScreen = true
    
    // Make sure we rotate to portrait mode
    let value = UIInterfaceOrientation.portrait.rawValue
    UIDevice.current.setValue(value, forKey: "orientation")
    
    // Present the screen
    let vc = FUIWelcomeScreen.createInstanceFromStoryboard()
    vc.detailLabel.text = "Thank you for downloading SAP Project Companion for Managers."
    self.navigationController?.pushViewController(vc, animated: true)
    
    

    After dismissing the Passcode or Touch ID screen:

    
    onboardingScreen.dismiss(animated: true, completion: nil)
    
    // Let `AppDelegate` know that we are exiting the view
    (UIApplication.shared.delegate as! AppDelegate).inFUIWelcomeScreen = false
    
    

    Theming

    Supported style classes

    fdlFUIWelcomeScreen
    fdlFUIWelcomeScreen_headlineImageView
    fdlFUIWelcomeScreen_headlineLabel
    fdlFUIWelcomeScreen_detailLabel
    fdlFUIWelcomeScreen_emailTextField
    fdlFUIWelcomeScreen_primaryActionButton
    fdlFUIWelcomeScreen_footnoteLabel
    fdlFUIWelcomeScreen_footnoteActionButton
    fdlFUIWelcomeScreen_logoImageView
    fdlFUIWelcomeScreen_navigationBar
    fdlFUIWelcomeScreen_cancelButton
    fdlFUIWelcomeScreen_loadingIndicatorView
    fdlFUIWelcomeScreen_loadingIndicatorView_activityIndicator
    fdlFUIWelcomeScreen_loadingIndicatorView_textLabel
    

    Attention

    • The delegate object with type FUIWelcomeControllerDelegate is declared as a weak reference. On deallocation it will be automatically set to nil. To keep it alive as expected, developer should retain the delegate object during its whole execution scope.

    • Developer can replace the logo image in the FUIWelcomeScreen using theming nss file. For example:

      fdlFUIWelcomeScreen_logoImageView {
      image-name: MyCompanyLogo.png;
      }
      

      Or, developer could use the logoImageView property to set the logo image directly.

    See more

    Declaration

    Swift

    open class FUIWelcomeScreen : FUIWelcomeController, UITextFieldDelegate, FUISolidNavigationBarProtocol, UIScrollViewDelegate
  • The Activation Screen is presented after the Welcome Screen in the case of an onboarding scenario where the application has not been configured, and should prompt the end user to pick between email address entry or the barcode scanner, to obtain connection settings. The screen displays a headline Label with the title and a detailLabel with instructions on how to start the activation process and options to enter the email address or click the Scan button to proceed to the next step in the onboarding process.

    Theming

    Supported style classes

    fdlFUIActivationScreen
    fdlFUIActivationScreen_headlineLabel
    fdlFUIActivationScreen_detailLabel
    fdlFUIActivationScreen_primaryActionButton
    fdlFUIActivationScreen.subheadlineLabel
    fdlFUIActivationScreen_secondaryActionButton
    fdlFUIActivationScreen_navigationBar
    

    Attention

    The delegate object with type FUIWelcomeControllerDelegate is declared as a weak reference. On deallocation it will be automatically set to nil. To keep it alive as expected, developer should retain the delegate object during its whole execution scope.

    See more

    Declaration

    Swift

    open class FUIActivationScreen : FUIWelcomeController, UITextFieldDelegate, FUISolidNavigationBarProtocol, UIScrollViewDelegate
  • This protocol provides method for handling button actions on a FUIWelcomeScreen view.

    See more

    Declaration

    Swift

    @objc
    public protocol FUIWelcomeControllerDelegate
  • Describes different onboarding states in onboarding process flow.

    See more

    Declaration

    Swift

    public enum FUIWelcomeControllerState : Int
  • Describes different onboarding configuration options in onboarding process flow.

    Note

    Note The property would be ignored if state is isConfigured

    Note

    Note The property should be set to [.discoveryService, .barcodeScanner] for the following user case: When application has not been configured, and should prompt the end user to pick between email address entry, or the Barcode Scanner, to obtain connection settings.

    See more

    Declaration

    Swift

    public struct FUIWelcomeControllerConfigurationOption : OptionSet
  • This controller is to display the scanner view to scan a QR code for app activation. It is also displaying the image thumbnails from camera roll and a button to start photo picker that user may choose the QR code image directly.

    Theming

    Supported style classes

    fdlFUIOnboardingScanViewController
    fdlFUIOnboardingScanViewController_cancelButton
    fdlFUIOnboardingScanViewController_flashButton
    fdlFUIOnboardingScanViewController_choosePhotoButton
    fdlFUIOnboardingScanViewController_arrowButton
    fdlFUIOnboardingScanViewController_scanGuidesImageView
    fdlFUIOnboardingScanViewController_photoPicker_navigationBar
    

    Attention

    The delegate object with type FUIOnboardingScanViewControllerDelegate is declared as a weak reference. On deallocation it will be automatically set to nil. To keep it alive as expected, developer should retain the delegate object during its whole execution scope.

    See more

    Declaration

    Swift

    public class FUIOnboardingScanViewController : UIViewController, FUIBarcodeScannerDelegate, UICollectionViewDataSource, UICollectionViewDelegate, FUIBlurNavigationBarViewController
    extension FUIOnboardingScanViewController: PHPhotoLibraryChangeObserver
  • Delegate protocol for FUIOnboardingScanViewController.

    See more

    Declaration

    Swift

    @objc
    public protocol FUIOnboardingScanViewControllerDelegate
  • This is the view that will be displayed when the scanner got a QR code from either scanner or a photo image. And this QR code is validated by the delegate of the FUIOnboardingScanViewController.

    This view includes the following components:

    • Title label: with default text “Confirmation”
    • Check image: a green circle with white check mark in the middle
    • Success message label: with default text “Scan succeeded. You will be connected to:”
    • SAP BTP server label: the text should be the SAP BTP server name that the implementation of the following function of FUIWelcomeControllerDelegate should provide.

      func welcomeController(_ welcomeController: FUIWelcomeController, willNavigateToScannerScreen scanController: FUIOnboardingScanViewController)
      
    • Continue button: when this is tapped, the app will continue rest of the onboarding tasks.

    Theming

    Supported style classes

    fdlFUIOnboardingScanConfirmView
    fdlFUIOnboardingScanConfirmView_titleLabel
    fdlFUIOnboardingScanConfirmView_successMessageLabel
    fdlFUIOnboardingScanConfirmView_hcpServerLabel
    fdlFUIOnboardingScanConfirmView_continueButton
    fdlFUIOnboardingScanConfirmView_continueButton_touchDown
    
    See more

    Declaration

    Swift

    open class FUIOnboardingScanConfirmView : NibDesignable
  • This passcode controller is for login to an app that supports multiple users.

    The following properties needs to be set Before the navigation controller presents this FUIMultiUserPasscodeController:

    • logoImageView.image
    • logoImageViewSize
    • titleLabel.text
    • dataSource
    • delegate

    A typical usage is as the sample code below:

            let passcodeController = FUIMultiUserPasscodeController()
    
            passcodeController.logoImageView.image = UIImage(named: "CompanyLogo", in: bundle, with: nil)
            passcodeController.logoImageView.contentMode = .scaleAspectFit
            passcodeController.logoImageViewSize = CGSize(width: 54, height: 27)
            passcodeController.titleLabel.text = "Company App"
            passcodeController.dataSource = self
            passcodeController.delegate = self
    
            let navigationController = UINavigationController(rootViewController: passcodeController)
            navigationController.modalPresentationStyle = .fullScreen
            navigationController.modalTransitionStyle = .coverVertical
            self.present(navigationController, animated: true, completion: nil)
    

    Theming

    Supported fixed font UILabel class paths:

    fdlFUIMultiUserPasscodeController_titleLabel
    fdlFUIMultiUserPasscodeController_userNameLabel
    fdlFUIMultiUserPasscodeController_userInfoLabel
    fdlFUIMultiUserPasscodeController_errorMessageLabel
    fdlFUIMultiUserPasscodeController_forgotPasscodeLabel
    

    Supported fixed font UILabel properties:

    font-size: (Size)
    font-name: (Font Name)
    font-color: (Color)
    

    Supported UITextField class paths:

    fdlFUIMultiUserPasscodeController_passcodeInputField
    

    Supported UITextField properties:

    border-color: (Color)
    border-width: (Width)
    corner-radius: (Radius)
    font-color: (Color)
    

    Supported UIButton class paths:

    fdlFUIMultiUserPasscodeController_logInButton
    fdlFUIMultiUserPasscodeController_switchUserButton
    

    Supported UIButton properties:

    background-color { -normal | -disabled }: (Color)
    font-size: (Size)
    font-name: (Font Name)
    font-color { -disabled }: (Color)
    

    Supported UIBarButtonItem class paths:

    fdlFUIMultiUserPasscodeController_addNewUserBarButtonItem
    

    Supported UIBarButtonItem properties:

    image: (Image Name)
    background-tint-color: (Color)
    

    Supported ImagePlaceholder class paths:

    fdlFUIMultiUserPasscodeController_userImagePlaceholder
    fdlFUIMultiUserPasscodeControllerUserCell_imagePlaceholder
    

    Supported ImagePlaceholder properties:

    font-size: (Size)
    font-name: (Font Name)
    font-color: (Color)
    

    Supported ImagePlaceholderView class paths:

    fdlFUIMultiUserPasscodeController_userImagePlaceholderView
    fdlFUIMultiUserPasscodeControllerUserCell_imagePlaceholderView
    

    Supported ImagePlaceholderView properties:

    background-color: (Color)
    

    Supported dynamic font UILabel class paths:

    fdlFUIMultiUserPasscodeControllerUserCell_titleLabeldlFUIMultiUserPasscodeController_titleLabel
    fdlFUIMultiUserPasscodeControllerUserCell_subtitleLabel
    

    Supported dynamic font UILabel properties:

    font-style: (Font Style)
    font-color: (Color)
    
    See more

    Declaration

    Swift

    open class FUIMultiUserPasscodeController : FUIPasscodeController
    extension FUIMultiUserPasscodeController: FUIListPickerDataSource
    extension FUIMultiUserPasscodeController: FUIListPickerSearchResultsUpdating
    extension FUIMultiUserPasscodeController: UITextFieldDelegate
  • This is the data source for providing the onboarded user list for the app on the device.

    This data source is to be used in FUIMultiUserPasscodeController.

    See more

    Declaration

    Swift

    public protocol FUIMultiUserPasscodeControllerDataSource : AnyObject
  • This UIViewController is to be used by app to setup the passcode and enabling Touch ID screen flows.

    Before the navigation controller presents this FUIPasscodeCreateController, the following property needs to be set:

    Application can also set this property for more passcode validation checks:

    Here is the screen flow:

    • The first screen is the Touch ID or Face ID screen, depends on the device capability, which prompts user to decide if enable Touch ID/Face ID authentication or not.

    When there are fingerprints or Face ID enrolled, there will be one “Enable” button only. When user tapped this button, a passcode is generated and saved in a biometric ID protected keychain item. The shouldTryPasscode function of the delegate will be invoked with the generated passcode. User will then need to use Touch ID or Face ID in the FUIPasscodeInputController for the login flow.

    When there is no fingerprints or Face ID enrolled, there will be one “Not Now” button, in addition to the “Enable” button. When “Not Now” is tapped, the second screen is shown to let user enter passcode. If “Enable” is tapped, in this case, an alert pop-up screen will be shown with two options, “Not Now” or “Settings”. Tapping “Not Now” will dismiss the pop-up alert, while tapping “Settings” will open the Settings app to let user enroll fingerprints or Face ID.

    • The second screen prompts user to enter passcode. After user entered the passcode which is validated with the FUIPasscodePolicy. The FUIPasscodeValidationDelegate provided function validate of validationDelegate is invoked for additional validation. If validation success, the next screen will be displayed; otherwise, the function throws FUIPasscodeControllerError when validation fails.

    • The third screen prompts user to enter passcode again to verify with the passcode entered in the first screen. The function shouldTryPasscode of the FUIPasscodeControllerDelegate is invoked when passcode is verified.

    When the function shouldTryPasscode of the FUIPasscodeControllerDelegate is invoked, the delegate should either create a secure store with the passcode, or save the passcode in a secure manner.

    This passcode create flow is implemented in FUIPasscodeCreateController.storyboard. There are two ways to invoke it:

    • Use another story board and using a “Present Modally” segue to FUIPasscodeCreateController storyboard in SAPFiori‘s framework bundle. App programmer needs to provide the properties needed in UIController’s prepare for segue function:
    
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    let destination = segue.destination as! UINavigationController
    let vc0 = destination.viewControllers[0]
    let vc = vc0 as! FUIPasscodeCreateController
    //assigning a `FUIPasscodeControllerDelegate` delegate is a must
    vc.delegate = passcodeControllerDelegate
    }
    
    
    • Programmatically loads it:
    let passcodeVC = FUIPasscodeCreateController.createInstanceFromStoryboard()
    
    //assigning a `FUIPasscodeControllerDelegate` delegate is a must
    passcodeVC.delegate = passcodeControllerDelegate
    
    // present the passcode view
    let navController = UINavigationController(rootViewController: passcodeVC)
    self.navigationController?.present(navController, animated: true, completion: nil)
    
    
    

    Theming

    Supported style classes

    fdlFUIPasscodeCreateController
    fdlFUIPasscodeCreateController_navigationBar
    fdlFUIPasscodeCreateController_cancelItem
    fdlFUIPasscodeCreateController_nextItem
    fdlFUIPasscodeCreateController_doneItem
    fdlFUIPasscodeCreateController_changeMode_cancelItem
    fdlFUIPasscodeCreateController_changeMode_nextItem
    fdlFUIPasscodeCreateController_changeMode_doneItem
    
    See more

    Declaration

    Swift

    public class FUIPasscodeCreateController : FUIPasscodeController, FUIPasscodeViewDelegate, FUITouchIDViewDelegate
    extension FUIPasscodeCreateController: UITextFieldDelegate
  • This UIViewController is to be used by app to authenticate user by either Touch ID or Passcode.

    Before the navigation controller presents this FUIPasscodeInputController, the following properties needs to be setup:

    This controller will try to determine if Touch ID is enabled by retrieving the value from keychain. If Touch ID is enabled, there will be Touch ID authentication popup to prompt user authenticate with Touch ID.

    If Touch ID authentication succeeded, the saved passcode will be retrieved and function shouldTryPasscode of the FUIPasscodeControllerDelegate implementation will be invoked.

    If Touch ID authentication is canceled or failed, the passcode view will be shown to prompt user enter passcode. After user entered the passcode, function shouldTryPasscode of the FUIPasscodeControllerDelegate implementation will be invoked.

    The delegate should dismiss this controller after the passcode is verified.

    This passcode input flow is implemented in FUIPasscodeInputController.storyboard. There are two ways to invoke it:

    • Use another story board and using a “Present Modally” segue to FUIPasscodeInputController storyboard in SAPFioriUI framework bundle. App programmer needs to provide the properties needed in UIController‘s prepare for segue function:
    
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    let destination = segue.destination as! UINavigationController
    let vc0 = destination.viewControllers[0]
    let vc = vc0 as! FUIPasscodeInputController
    vc.delegate = passcodeControllerDelegate
    }
    
    
    • Programmatically loads it:
    
    let storyboard = UIStoryboard(name: "FUIPasscodeInputController", bundle: bundle)
    let vc = storyboard.instantiateViewController(withIdentifier: "PasscodeInputViewController")
    let passcodeVC = vc as! FUIPasscodeInputController
    
    // present the passcode view
    let navController = UINavigationController(rootViewController: passcodeVC)
    self.navigationController?.present(navController, animated: true, completion: nil)
    
    

    Theming

    Supported style classes

    fdlFUIPasscodeInputController
    fdlFUIPasscodeInputController_doneItem
    fdlFUIPasscodeInputController_cancelItem
    fdlFUIPasscodeInputController_navigationBar
    
    See more

    Declaration

    Swift

    public class FUIPasscodeInputController : FUIPasscodeController, FUIPasscodeViewDelegate
    extension FUIPasscodeInputController: UITextFieldDelegate
  • Use this UINavigationController to change the passcode screen flows in the application.

    Set up the following properties before presenting this FUIPasscodeChangeController:

    Note that the properties hashUserPasscode and userIdentifier need to be the same as the FUIPasscodeCreateController in order for the change to be successful.

    Here is the screen flow:

    • The first screen prompts the user to enter the current passcode using FUIPasscodeInputController. This controller always uses the passcode for authentication only. Note: If Touch ID is enabled, there will be Touch ID authentication popup to prompt user authenticate with Touch ID. Once user enters fingerprint or device passcode, the stored passcode in the keychain is retrieved and the delegate’s shouldTryPasscode is invoked to validate the old passcode. And a new passcode is generated and shouldTryPasscode is invoked again to validate the new passcode. The new passcode is then saved in the keychain without other user actions.

    • The second screen prompts the user to enter a new passcode, which is validated by the FUIPasscodePolicy. The FUIPasscodeControllerDelegate provided function validate of validationDelegate is invoked for additional validation. Upon validation success, the next screen displays.

    • The third screen prompts the user to enter the passcode again to verify the passcode entered in the second screen. After the setup is complete, the function shouldTryPasscode of the FUIPasscodeControllerDelegate is invoked. The delegate should either create a secure store with the passcode, or save the passcode in a secure manner. Note: Changing the passcode does not affect the existing Touch ID preferences. No additional screens display to enable touchID to change the passcode flow. If touchID was previously disabled before triggering the passcode change, touchID remains disabled. However, if touchID was previously enabled, the internal touchID-related data is automatically updated after the passcode is changed.

    This passcode flow change is implemented in FUIPasscodeChangeController.storyboard. There are two ways to invoke it:

    • Use another storyboard and add a “Present Modally” segue to the FUIPasscodeChangeController storyboard in the SAPFiori framework bundle. The app developer must provide the required properties in the UIController‘s prepare for segue function:
    
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
       let changeController = segue.destination as! FUIPasscodeChangeController
       changeController.passcodeControllerDelegate = passcodeControllerDelegate
       changeController.validationDelegate = validationDelegate
    }
    
    
    • Programmatically load it:
       let changeController = FUIPasscodeChangeController.createInstanceFromStoryboard()
       changeController.passcodeControllerDelegate = passcodeControllerDelegate
       changeController.validationDelegate = validationDelegate
       self.present(changeController, animated: true, completion: nil)
    
    
    See more

    Declaration

    Swift

    public class FUIPasscodeChangeController : UINavigationController
  • This is the base class of FUIPasscodeCreateController and FUIPasscodeInputController. It has the common codes for those two view controllers.

    Note that both Passcode screen and Touch ID screen are supported for iPad portrait and landscape orientation and iPhone portrait orientation only. Since the screens are not supported in iPhone landscape orientation, the app installed in iPhone needs to switch to portrait mode before presenting these screens. And AppDelegate needs to lock the screen orientation when these screens are shown, similar to the following code snippet.

    In app’s AppDelegate:

    
    public var inPasscodeView: Bool = false
    
    // implement this function to support only portrait orientation when FUPasscodeView is displayed in iPhone.
    func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
    if !inPasscodeView {
    return .allButUpsideDown
    } else {
    return .portrait
    }
    }
    
    

    Before presenting the Passcode or Touch ID screen:

    
    // Let `AppDelegate` know that we are entering FUIPasscodeView
    (UIApplication.shared.delegate as! AppDelegate).inPasscodeView = true
    
    // Make sure we rotate to portrait mode
    let value = UIInterfaceOrientation.portrait.rawValue
    UIDevice.current.setValue(value, forKey: "orientation")
    // Present the passcode view
    self.navigationController?.present(navController, animated: true, completion: nil)
    
    

    After dismissing the Passcode or Touch ID screen:

    
    passcodeController.dismiss(animated: true, completion: nil)
    // Let `AppDelegate` know that we are exiting FUIPasscodeView
    (UIApplication.shared.delegate as! AppDelegate).inPasscodeView = false
    
    

    The strings used in FUIPasscodeSetupView, FUIPasscodeView, and FUITouchIDView are from localized Onboarding.strings file. Application can override these strings by setting the corresponding static variables in this FUIPasscodeController class at runtime.

    Theming

    Supported style classes

    fdlFUIPasscodeController
    fdlFUIPasscodeController_navigationController_navigationBar
    

    Attention

    The delegate object with type FUIPasscodeControllerDelegate is declared as a weak reference. On deallocation it will be automatically set to nil. To keep it alive as expected, developer should retain the delegate object during its whole execution scope.

    See more

    Declaration

    Swift

    open class FUIPasscodeController : UIViewController, FUIPrivateEncryptionKeyGenerator, FUISolidNavigationBarProtocol, UIScrollViewDelegate
  • This protocol defines the functions needed for FUIPasscodeController to notify the app about passcode and TouchID events.

    See more

    Declaration

    Swift

    public protocol FUIPasscodeControllerDelegate : AnyObject
  • This error is to be thrown by FUIPasscodeControllerDelegate implementation when function shouldTryPasscode is called with a passcode that failed to open the secure store or match the saved passcode.

    See more

    Declaration

    Swift

    public enum FUIPasscodeControllerError : Error
  • Protocol to allow to create a private encryption key

    See more

    Declaration

    Swift

    public protocol FUIPrivateEncryptionKeyGenerator : AnyObject
  • Passcode input mode. Typically used in shouldTryPasscode function as one of the arguments to indicate the current mode. When the shouldTryPasscode function is triggered by FUIPasscodeInputController, the mode can be either match or matchForChange. when the function is triggered by FUIPasscodeCreateController, the mode is either create or change.

    See more

    Declaration

    Swift

    public enum FUIPasscodeInputMode : Int
  • The passcode policy structure.

    See more

    Declaration

    Swift

    public struct FUIPasscodePolicy
  • The passcode rule structure used to add a user defined passcode rule to the passcode policy.

    See more

    Declaration

    Swift

    public struct FUIPasscodeRule
  • This delegate is responsible to do additional validations to the passcode user entered. FUIPasscodeCreateController will validate the passcode user entered with the FUIPasscodePolicy internally.

    See more

    Declaration

    Swift

    public protocol FUIPasscodeValidationDelegate : AnyObject
  • This is a ‘UIViewController’ to display the error view when Touch ID or Face ID authentication is cancelled.

    Developer could set the static string properties in this class to override the default text displayed in this view.

    Theming

    fdlFUITouchIDErrorViewController_errorTitleLabel {
    font-color: @primary1;
    }
    
    fdlFUITouchIDErrorViewController_errorMessageLabel {
    font-color: @primary1;
    }
    
    fdlFUITouchIDErrorViewController_actionButton {
    font-size: 16;
    font-name: system;
    font-color: @primary6;
    background-color: @tintColorDark;
    corner-radius: 8;
    border-width: 1;
    border-color: @tintColorDark;
    /* order (with whitespace as separator): [top] [right] [bottom] [left]
    
    See more

    Declaration

    Swift

    public class FUITouchIDErrorViewController : UIViewController
  • This FUIBasicAuthenticationScreen is an UIViewController to display the screen to prompt user to enter username and password to do basic authentication.

    It has a headline label and a detail label to display the title and a detail message for this screen. There are two input fields for user input username and password. And one primary action button. The button will be enabled when both the username and password are not empty.

    There is also a cancel button on the navigation bar for user to cancel the basic authentication process.

    Developer should implement FUIBasicAuthenticationDelegate and set it to the delegate property to handle user responses.

    func presentDynamicAuthenticationScreen() {
        let controllers = FUIBasicAuthenticationScreen.createInstanceFromStoryboard()
    
        let basicAuthController = controllers.basicAuthenticationScreen
        basicAuthController.loadViewIfNeeded()
        basicAuthController.delegate = self
    
        self.navigationController?.present(controllers.navigationController, animated: true, completion: nil)
    }
    
    
    func didSignIn(_ controller: FUIBasicAuthenticationScreen, username: String, password: String, completion: @escaping ((_ errorMessage: String?) -> Void)) {
        var signInErrorMessage: String? = nil
    
        // Send username and password to server for verification here
    
        // Simulate callback from verification process
        DispatchQueue.main.asyncAfter(deadline: .now() + 5.0) {
            // This is for testing purposes only.
            if !self.signInOk || username == password {
                signInErrorMessage = "Sign In Failed"
            }
    
            completion(signInErrorMessage)
            if signInErrorMessage == nil {
                controller.dismiss(animated: true, completion: nil)
            }
        }
    }
    
    func didCancel(_ controller: FUIBasicAuthenticationScreen) {
        print("User Cancelled Basic Authentication")
        controller.dismiss(animated: true, completion: nil)
    }
    
    

    Theming

    fdlFUIBasicAuthenticationScreen_headlineLabel {
       font-size: 28;
       font-name: thinSystem;
       font-color: @primary1;
    }
    
    fdlFUIBasicAuthenticationScreen_detailLabel {
       font-style: body;
       font-color: @primary1;
    }
    
    fdlFUIBasicAuthenticationScreen_primaryActionButton {
       font-style: callout;
       font-color: @primary6;
       corner-radius: 8;
       background-color-normal: @tintColorDark;
       background-color-highlighted: @backgroundGradientTop;
    
       background-color-disabled: @line;
       font-color-disabled:  #28666666; /*primary2 with 0.4 alpha; "28" is the hex value of 20% for alpha; "666666" is primary2
    
    See more

    Declaration

    Swift

    open class FUIBasicAuthenticationScreen : FUIWelcomeController, FUISolidNavigationBarProtocol, UIScrollViewDelegate
    extension FUIBasicAuthenticationScreen: UITextFieldDelegate
  • The delegate protocol for the basic authentication screen.

    See more

    Declaration

    Swift

    public protocol FUIBasicAuthenticationDelegate : AnyObject
  • The FUIDynamicAuthenticationScreen is an UIViewController to display the screen to prompt user to enter information needed for authentication.

    It has a message label and a number of the input fields for user to enter information needed. The input fields are configured using the informationFields property.

    There is a ‘Cancel’ button on the navigation bar for user to cancel the authentication process. There is also a ‘Done’ button on the navigation bar for user to submit the information. The Done button is disabled until all the input fields are not empty.

    Developer should implement FUIDynamicAuthenticationDelegate and set it to the delegate property to handle user responses.

    
    var dynamicAuthenticationScreen: FUIDynamicAuthenticationScreen?
    var completionBlock: ((_ errorMessage: String?) -> Void)?
    
    func presentDynamicAuthenticationScreen() {
        let controllers = FUIDynamicAuthenticationScreen.createInstanceFromStoryboard()
        let dynamicAuthController = controllers.dynamicAuthenticationScreen
    
        dynamicAuthController.informationFields = [
            FUIAuthenticationInformationField(placeholder: "username", isSecureText: false, informationString: "Admin"),
            FUIAuthenticationInformationField(placeholder: "password", isSecureText: true, informationString: nil),
            FUIAuthenticationInformationField(placeholder: "url", isSecureText: false, informationString: nil),
            FUIAuthenticationInformationField(placeholder: "test field", isSecureText: false, informationString: nil)
        ]
        dynamicAuthController.delegate = self
    
        self.navigationController?.present(controllers.navigationController, animated: true, completion: nil)
    }
    
    func verify(_ controller: FUIDynamicAuthenticationScreen, informationStrings: [String], completion: @escaping ((_ errorMessage: String?) -> Void)) {
        dynamicAuthenticationScreen = controller
        completionBlock = completion
    
        // Send information to server for verification here
    
        // Simulate callback from verification process
        DispatchQueue.main.asyncAfter(deadline: .now() + 5.0) {
            self.verificationDone()
        }
    }
    
    func verificationDone() {
        completionBlock?(verificationErrorMessage)
        if verificationErrorMessage == nil {
            dynamicAuthenticationScreen?.dismiss(animated: true, completion: nil)
        }
    }
    
    func didCancel(_ controller: FUIBasicAuthenticationScreen) {
       print("User Cancelled Basic Authentication")
       controller.dismiss(animated: true, completion: nil)
    }
    
    

    Theming

    fdlFUIDynamicAuthenticationScreen_detailLabel {
       font-color: @primary1;
    }
    
    fdlFUIDynamicAuthenticationScreen_cancelButton {
       background-tint-color: @tintColorDark;
    }
    
    fdlFUIDynamicAuthenticationScreen_doneButton {
       background-tint-color: @tintColorDark;
    }
    
    fdlFUIDynamicAuthenticationScreen_messageBannerTitleLabel {
       font-color: @primary7;
    }
    
    fdlFUIDynamicAuthenticationScreen_messageBannerDividerTop {
       background-color: @line;
    }
    
    fdlFUIDynamicAuthenticationScreen_errorMessageBannerTitleLabel {
       font-color: @negative;
    }
    
    fdlFUIDynamicAuthenticationScreen_errorMessageBannerDividerTop {
       background-color: @negative;
    }
    
    fdlFUIDynamicAuthenticationScreen_navigationBar {
       background-color: clear;
       background-tint-color: @tintColor;
       bar-style: default;
    }
    
    

    Attention

    The delegate object with type FUIDynamicAuthenticationDelegate is declared as a weak reference. On deallocation it will be automatically set to nil. To keep it alive as expected, developer should retain the delegate object during its whole execution scope.

    See more

    Declaration

    Swift

    open class FUIDynamicAuthenticationScreen : FUIWelcomeController, FUISolidNavigationBarProtocol, UIScrollViewDelegate
    extension FUIDynamicAuthenticationScreen: UITextFieldDelegate
  • The delegate protocol for the authentication screen.

    See more

    Declaration

    Swift

    public protocol FUIDynamicAuthenticationDelegate : AnyObject
  • This UIViewController is used to display the End User License Agreement, EULA. There are two buttons on the tool bar at the bottom of the screen, “Agree” and “Disagree”, to choose to confirm or reject the agreement. In addition, there is a “Cancel” button at the left on the navigation bar.

    Developer should provide the text for the headlineLabel property, the attributed text for the eulaTextView property, and set the delegate property to handle user interactions.

    let eulaController = FUIEULAViewController.createInstanceFromStoryboard()
    
    eulaController.headlineLabel.text = "CUSTOM EULA"
    eulaController.eulaTextView.attributedText = NSAttributedString(string: "This is a legally binding agreement (\"Agreement\") between ...", attributes: [NSAttributedStringKey.font: UIFont(name: "Georgia", size: 24.0)!
    ])
    eulaController.delegate = self
    
    let navController = UINavigationController.init(rootViewController: eulaController)
    self.navigationController?.present(navController, animated: true, completion: nil)
    
    

    Theming

    
    fdlFUIEULAView_headlineLabel {
       font-size: 28;
       font-name: thinSystem;
       font-color: @primary1;
    }
    
    fdlFUIEULAView_confirmButton {
       background-tint-color: @tintColorDark;
    }
    
    fdlFUIEULAView_rejectButton {
       background-tint-color: @tintColorDark;
    }
    
    fdlFUIEULAView_cancelButton {
       background-tint-color: @tintColorDark;
    }
    
    fdlFUIEULAView_navigationBar {
       background-color: clear;
       background-tint-color: @tintColor;
       bar-style: default;
    }
    
    

    Attention

    The delegate object with type FUIEULADelegate is declared as a weak reference. On deallocation it will be automatically set to nil. To keep it alive as expected, developer should retain the delegate object during its whole execution scope.

    See more

    Declaration

    Swift

    open class FUIEULAViewController : FUIWelcomeController, FUISolidNavigationBarProtocol, UIScrollViewDelegate
  • This protocol defines a set of actions the user can initiate on the FUIEULAViewController.

    See more

    Declaration

    Swift

    public protocol FUIEULADelegate : AnyObject
  • Multifunctional view for displaying Information or Splash screen. The UI elements can be hidden or showed depending on functionality. The text properties must be set before displaying the view.

    Theming

    Example nss definitions

    fdlFUIInfoViewScreen_titleTextView {
       font-color:  @primary1;
       placeholder-color: green;
    }
    
    fdlFUIInfoViewScreen_informationTextView {
       font-color:  @primary1;
       placeholder-color: green;
    }
    
    fdlFUIInfoViewScreen_primaryButton {
       font-color: @primary1;
    }
    
    fdlFUIInfoViewScreen_secondaryButton {
       font-color: @primary1;
    }
    
    See more

    Declaration

    Swift

    open class FUIInfoViewController : UIViewController, ASWebAuthenticationPresentationContextProviding
  • This protocol defines the functions to be invoked with user actions on the FUIInfoViewController.

    See more

    Declaration

    Swift

    public protocol FUIInfoViewControllerDelegate : AnyObject
  • Protocol implemented by FUISinglePageUserConsentForm and FUIMultiPageUserConsentForm

    See more

    Declaration

    Swift

    public protocol FUIUserConsentForm
  • FUIUserConsentPage() represents a single page in a user consent form. An FUISinglePageUserConsentForm only contains one instance of the FUIUserConsentPage(). An FUIMultiPageUserConsentForm can contain many FUIUserConsentPage() instances which constitute the multiple pages of the form.

    let page1 = FUIUserConsentPage()
    page1.title.text = "Data Privacy"
    page1.body.text = "Detailed text about how data privacy pertains to this app and why it is important for the user to enable this functionality"
    page1.actionTitle.text = "Learn more about Data Privacy"
    page1.actionHandler = { controller in
        let alert = UIAlertController(title: "Data Privacy", message: "Alert for Data Privacy Page", preferredStyle: UIAlertControllerStyle.alert)
        alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: nil))
        controller.present(alert, animated: true, completion: nil)
    }
    
     let userconsentpages = [page1]
     let multipageform = FUIMultiPageUserConsentForm(pages: userconsentpages)
    
    See more

    Declaration

    Swift

    open class FUIUserConsentPage : FUIUserConsentPageComponent
  • This UIViewController is used to display a simple form to the user to obtain consent. The form contains a title property, body property containing the details and a link to more information, which when clicked invokes the actionHandler. The text of the link can be set with the actionTitle property. There are 2 buttons in the toolbar, “Deny” and “Agree”, if the form’s isMandatory property is true or “Not Now” and “Agree”, if it is false. The toolbar button titles can also be changed using the toolbarLeftItemTitle and toolbarRightItemTitle properties. The toolbar buttons invoke the FUIConsentPageViewControllerDelegate methods which can be used to handle the application logic based on the user input. Note that this class must only be used when displaying a simple form with information that fits in a single page (controller). While using modal presentation style, the controller must be embedded in a navigation controller to display the toolbar.To display a series of consent forms (where each form may span a single page or multiple pages), please refer to FUIUserConsentViewController.

    FUIUserConsentPageViewController

    The above image shows the form displayed using the push segue. Sample code to do that is provided below.

    
     // Sample code to create a controller as a subclass of FUIUserConsentPageViewController and display it using push segue
    
     import Foundation
     import SAPFiori
    
     class SimpleFormUsingPushSegue: FUIUserConsentPageViewController, FUIUserConsentPageViewControllerDelegate {
    
     override func viewDidLoad() {
     super.viewDidLoad()
    
     self.title = "Push Segue Example"
     }
    
     override func didReceiveMemoryWarning() {
     super.didReceiveMemoryWarning()
     // Dispose of any resources that can be recreated.
     }
    
     open override func viewDidLayoutSubviews(){
     super.viewDidLayoutSubviews()
     }
    
     func didAllow(_ controller: FUIUserConsentPageViewController) {
    
     print("Did Allow")
     self.navigationController?.popViewController(animated:true)
     }
    
     func didDeny(_ controller: FUIUserConsentPageViewController) {
     print("Did Deny")
     self.navigationController?.popViewController(animated:true)
     }
     }
    
    
     // Sample code to display the above form using push segue
    
     let ctrllr = SimpleFormUsingPushSegue()
     ctrllr.userConsentPageViewControllerDelegate = ctrllr
     ctrllr.title.text = "A Simple Form"
     ctrllr.body.text = " Use this controller to display a single page form to the user"
     ctrllr.actionTitle.text = "More Details"
     ctrllr.actionHandler = { controller in
     let alert = UIAlertController(title: "Details", message: "Visit sap.com", preferredStyle: UIAlertControllerStyle.alert)
     alert.addAction(UIAlertAction(title:"OK", style: UIAlertActionStyle.default, handler: nil))
     controller.present(alert, animated: true, completion: nil)
     }
    
     ctrllr.isMandatory = true
    
     self.navigationController?.pushViewController(ctrllr, animated: true)
    
    

    FUIUserConsentPageViewController

    The above image shows the form displayed using modal segue. Sample code to do that is provided below.

     // Sample code to create a controller as a subclass of FUIUserConsentPageViewController and display it modally
    
     import Foundation
     import SAPFiori
    
    
     class SimpleFormUsingModalSegue: FUIUserConsentPageViewController, FUIUserConsentPageViewControllerDelegate
    
     {
     override func viewDidLoad() {
     super.viewDidLoad()
     }
    
     override func didReceiveMemoryWarning() {
     super.didReceiveMemoryWarning()
     // Dispose of any resources that can be recreated.
     }
    
     open override func viewDidLayoutSubviews(){
     super.viewDidLayoutSubviews()
     }
    
     func didAllow(_ controller: FUIUserConsentPageViewController) {
     print("Did Allow")
     self.dismiss(animated: true, completion: nil)
     }
    
     func didDeny(_ controller: FUIUserConsentPageViewController) {
     print("Did Deny")
     self.dismiss(animated: true, completion: nil)
     }
    
    
     @objc func leftBarButtonClicked(sender: UIBarButtonItem) {
     let alert = UIAlertController(title: "Are you sure you want to cancel?", message:nil , preferredStyle: UIAlertControllerStyle.alert)
    
     alert.addAction(UIAlertAction(title: "No", style: .cancel, handler: nil))
     alert.addAction(UIAlertAction(title: "Quit", style: .default, handler: { action in
    
     self.navigationController?.dismiss(animated: true, completion:nil)}))
     self.navigationController?.topViewController?.present(alert, animated: true, completion: nil)
     }
    
     }
    
    
     // Sample Code to display the above controller modally
    
     var navController = UINavigationController()
    
     let ctrllr = SimpleFormUsingModalSegue()
     ctrllr.userConsentPageViewControllerDelegate = ctrllr
     ctrllr.title.text = "A Simple Form"
     ctrllr.body.text = " Use this controller to display a single page form to the user"
     ctrllr.actionTitle.text = "More Details"
    
     ctrllr.actionHandler = { controller in
     let alert = UIAlertController(title: "Details", message: "Visit sap.com", preferredStyle: UIAlertControllerStyle.alert)
     alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: nil))
     controller.present(alert, animated: true, completion: nil)
     }
     ctrllr.isMandatory = true
     ctrllr.toolbarLeftItemTitle = "Left"
     ctrllr.toolbarRightItemTitle = "Right"
    
     navController = UINavigationController(rootViewController: ctrllr)
     let cancelButton = UIBarButtonItem(title: "Cancel", style: .plain, target: self, action: #selector(leftBarButtonClicked))
     navController.topViewController?.navigationItem.leftBarButtonItem = cancelButton
    
     self.present(navController, animated: true, completion: nil)
    
    
     // Add a cancel button to the navigation controller when displaying the form modally.
     @objc func leftBarButtonClicked(sender: UIBarButtonItem) {
    
     let alert = UIAlertController(title: "Are you sure you want to cancel?", message:nil , preferredStyle: UIAlertControllerStyle.alert)
    
     alert.addAction(UIAlertAction(title: "No", style: .cancel, handler: nil))
     alert.addAction(UIAlertAction(title: "Quit", style: .default, handler: { action in
    
     self.navController.dismiss(animated: true, completion:nil)}))
     self.navController.topViewController?.present(alert, animated: true, completion: nil)
     }
    
    See more

    Declaration

    Swift

    open class FUIUserConsentPageViewController : FUIBaseDrawingViewController<FUIUserConsentPageView>, FUISolidNavigationBarProtocol, UIScrollViewDelegate
  • This UIViewController is used to display a series of user consent screens modally during the process of onboarding. The property forms must be supplied, which is an array of objects of the two classes that conform to the FUIUserConsentForm protocol, namely FUISinglePageUserConsentForm and FUIMultiPageUserConsentForm. The Fiori for iOS SDK takes these forms and displays them modally as single or multipage user consent screens using the FUIUserConsentViewController. A user consent screen contains a title, a brief information on the topic for which the user consent is required and a link to more details. There are 2 buttons in the toolbar, “Agree” and “Deny”, if the consent form is mandatory or “Agree” and “Not Now”, if the consent form is optional. In the case of a mandatory form, the user can proceed to the next step of onboarding only when they agree to the terms stated in the form. In the case of an optional form, the user can choose to click the “Not Now” button and proceed with the onboarding. In addition, there is a “Cancel” button in the navigation bar. The toolbar buttons and the cancel button invoke the FUIUserConsentViewControllerDelegate methods which can be used to handle the application logic based on the user input. If the form is a multi-page consent form, only the last page in the form displays the toolbar and cancel buttons. Each consent form has the title property,body containing the details, an actionTitle, which when tapped invokes the actionHandler. There are also the titleAttributedText, bodyAttributedText and actionTitleAttributedText properties, which when supplied take precedence over the title, body and actionTitle properties. For example, when both titleand titleAttributedText are supplied, only titleAttributedText is displayed.

    FUIUserConsentViewController

    
     let spForm = createSinglePageForm()
     spForm.isRequired = false
     let mpForm = createMultiPageForm()
     mpForm.isRequired = false
     let forms = [spForm,mpForm] as [Any]
    
     (UIApplication.shared.delegate as! AppDelegate).inUserConsentScreen = true
     let ctrller = FUIUserConsentViewController()
     ctrller.delegate = self
     ctrller.forms = forms as! [FUIUserConsentForm]
     self.navigationController?.present(ctrller, animated: true, completion: nil)
    
    
     func createSinglePageForm()->FUISinglePageUserConsentForm {
     let singlepageform = FUISinglePageUserConsentForm()
     singlepageform.title.text = "Data Privacy"
     singlepageform.body.text = "Detailed text about how data privacy pertains to this app and why it is important for the user to enable this functionality"
     singlepageform.actionTitle.text = "Learn more about Data Privacy"
     singlepageform.actionHandler = { controller in
     let alert = UIAlertController(title: "Want Data Privacy?", message: "Be wise about your data", preferredStyle: UIAlertControllerStyle.alert)
     alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: nil))
     controller.present(alert, animated: true, completion: nil)
     }
     return singlepageform
     }
    
     func createMultiPageForm()->FUIMultiPageUserConsentForm {
     let page1 = FUIUserConsentPage()
     page1.title.text = "Data Privacy"
     page1.body.text = "Detailed text about how data privacy pertains to this app and why it is important for the user to enable this functionality"
     page1.actionTitle.text = "Learn more about Data Privacy"
     page1.actionHandler = { controller in
     let alert = UIAlertController(title: "Data Privacy", message: "Alert for Data Privacy Page", preferredStyle: UIAlertControllerStyle.alert)
     alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: nil))
     controller.present(alert, animated: true, completion: nil)
     }
    
     let page2 = FUIUserConsentPage()
     page2.title.text = "Security"
     page2.body.text = "Detailed text about how data privacy pertains to this app and why it is important for the user to enable this functionality. "
     page2.actionTitle.text = "Learn more about Data Privacy"
     page2.actionHandler = { controller in
     let alert = UIAlertController(title: "Security", message: "Alert for data security page", preferredStyle: UIAlertControllerStyle.alert)
     alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: nil))
     controller.present(alert, animated: true, completion: nil)
     }
    
     let page3 = FUIUserConsentPage()
     page3.title.text = "Consent"
     page3.body.text = "Detailed text about how data privacy pertains to this app and why it is important for the user to enable this functionality"
     page3.actionTitle.text = "Learn more about Data Privacy"
     page3.actionHandler = { controller in
     let alert = UIAlertController(title: "Consent", message: "Alert for consent page", preferredStyle: UIAlertControllerStyle.alert)
     alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: nil))
     controller.present(alert, animated: true, completion: nil)
     }
    
     let userconsentpages = [page1,page2,page3]
     let multipageform = FUIMultiPageUserConsentForm(pages: userconsentpages)
     return multipageform
     }
    
    

    Application should also implement the FUIUserConsentViewControllerDelegate protocol, which provides the delegate methods that handle the application flow based on whether the user agrees, disagrees or cancels the form. It is important that the FUIUserConsentViewController, passed in as the parameter viewController must be dismissed first as shown below, before proceeding with any other application logic based on the user response to the forms.

    
    func userConsentViewController( viewController: FUIUserConsentViewController, didCancelConsentForms forms: [FUIUserConsentForm]) {
    
        viewController.dismiss(animated: true, completion: nil)
    
        let alert = UIAlertController(title: "Cancelled", message: "User cancelled Onboarding", preferredStyle: UIAlertControllerStyle.alert)
        (UIApplication.shared.delegate as! AppDelegate).inUserConsentScreen = false
        alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: nil))
        self.present(alert, animated: true, completion: nil)
    
    }
    
    func userConsentViewController( viewController: FUIUserConsentViewController, didReceiveResponseToConsentForms forms: [FUIUserConsentForm]) {
    
        (UIApplication.shared.delegate as! AppDelegate).inUserConsentScreen = false
        var NumAccepted = 0
        for form in forms  {
            if (form.isUserAccepted) {
                NumAccepted = NumAccepted + 1
            }
        }
        viewController.dismiss(animated: true, completion: nil)
        if (NumAccepted > 0) {
            let alert = UIAlertController(title: "Status", message: "User accepted \(NumAccepted) form(s)", preferredStyle: UIAlertControllerStyle.alert)
            alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: nil))
            self.present(alert, animated: true, completion: nil)
        }
    }
    
    

    Note that the user consent screen orientations are supported for iPad portrait and landscape orientation and iPhone portrait orientation only. Since the screen is not supported in iPhone landscape orientation, the app needs to switch to portrait mode before presenting the screen and the AppDelegate needs to lock the screen orientation when these screens are shown, similar to the following code snippet.

    In app’s AppDelegate:

    
     public var inUserConsentScreen: Bool = false
    
     // Implement this function to support only portrait orientation when FUIUserConsentScreen is displayed in iPhone.
     func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
        if !inUserConsentScreen {
            return .allButUpsideDown
        } else {
            return .portrait
        }
     }
    
    

    Before presenting the FUIUserConsentViewController:

    
     // Let `AppDelegate` know that we are entering the screen
     (UIApplication.shared.delegate as! AppDelegate).inUserConsentScreen = true
    
     // Present the screen
     self.navigationController?.present(ctrller, animated: true, completion: nil)
    
    

    After dismissing the FUIUserConsentViewController screen:

    
     viewController.dismiss(animated: true, completion: nil)
    
     // Let `AppDelegate` know that we are exiting the view
     (UIApplication.shared.delegate as! AppDelegate).inUserConsentScreen = false
    
    

    ## Theming

    Supported class paths:

     fdlFUIUserConsentPageView_title {}
     fdlFUIUserConsentPageView_body {}
     fdlFUIUserConsentPageView_actionTitle {}
    

    Supported properties:

     font-color: Color;
     font-style: UIFontTextStyle;
     text-line-clamp: Integer;
     text-align: NSTextAlignment;
    

    Supported NavigationBar class paths:

     fdlFUIUserConsentViewController_navigationBar {}
    

    Supported NavigationBar properties:

     bar-tint-color: Color;
     background-color: Color;
    

    ## Attention

    The delegate object with type FUIUserConsentViewControllerDelegate is declared as a weak reference. On deallocation it will be automatically set to nil. To keep it alive as expected, developer should retain the delegate object during the whole execution scope.

    See more

    Declaration

    Swift

    open class FUIUserConsentViewController : UIViewController, FUIUserConsentPageViewControllerDelegate, ConsentPageDisplayDelegate
  • This protocol defines a set of methods invoked based on user response to the consent forms.

    See more

    Declaration

    Swift

    public protocol FUIUserConsentViewControllerDelegate : AnyObject
  • This class specifies a user consent form with a single page of content. For a single page form, it is not required to create the FUIUserConsentPage and then add it to the form, since it is created automatically as part of the init.

    let singlepageform = FUISinglePageUserConsentForm()
    singlepageform.title.text = "Data Privacy"
    singlepageform.body.text = "Detailed text about how data privacy pertains to this app and why it is important for the user to enable this functionality"
    singlepageform.actionTitle.text = "Learn more about Data Privacy"
    singlepageform.actionHandler = { controller in
    let alert = UIAlertController(title: "Want Data Privacy?", message: "Be wise about your data", preferredStyle: UIAlertControllerStyle.alert)
    alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: nil))
    controller.present(alert, animated: true, completion: nil)
    }
    
    
    See more

    Declaration

    Swift

    open class FUISinglePageUserConsentForm : FUIUserConsentForm, FUIUserConsentPageComponent
  • This class specifies a user consent form with multiple pages of content.

    
    let page1 = FUIUserConsentPage()
    page1.title.text = "Data Privacy"
    page1.body.text = "Detailed text about how data privacy pertains to this app and why it is important for the user to enable this functionality"
    page1.actionTitle.text = "Learn more about Data Privacy"
    page1.actionHandler = { controller in
    let alert = UIAlertController(title: "Data Privacy", message: "Alert for Data Privacy Page", preferredStyle: UIAlertControllerStyle.alert)
    alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: nil))
    controller.present(alert, animated: true, completion: nil)
    }
    
    let page2 = FUIUserConsentPage()
    page2.title.text = "Security"
    page2.body.text = "Detailed text about how data privacy pertains to this app and why it is important for the user to enable this functionality. "
    page2.actionTitle.text = "Learn more about Data Privacy"
    page2.actionHandler = { controller in
    let alert = UIAlertController(title: "Security", message: "Alert for data security page", preferredStyle: UIAlertControllerStyle.alert)
    alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: nil))
    controller.present(alert, animated: true, completion: nil)
    }
    
    let userconsentpages = [page1,page2]
    let multipageform = FUIMultiPageUserConsentForm(pages: userconsentpages)
    
    
    See more

    Declaration

    Swift

    open class FUIMultiPageUserConsentForm : FUIUserConsentForm
  • Theming

    Supported style classes

    fdlFUIWebViewContainer
    fdlFUIWebViewContainer_cancelButton
    fdlFUIWebViewContainer_navigationBar
    
    See more

    Declaration

    Swift

    open class FUIWebViewContainer : UIViewController
  • Delegate protocol for FUIWebViewContainer.

    See more

    Declaration

    Swift

    public protocol FUIWebViewContainerDelegate : AnyObject