Support a scene-based life cycle

The BlackBerry Dynamics SDK supports a scene-based life cycle for iOS apps. In a scene-based app, the UIApplicationDelegate and UISceneDelegate objects manage the app life cycle using events. You decide how to implement the life cycle of events. The steps below provide an example that is based on the Apple Breadcrumbs sample app, with modifications made to declarations and other key areas. Several of the sample apps included in the SDK package demonstrate the event handling life cycle.
  1. Configure the UISceneDelegate to own the UIWindow when the scene connects. Do not create a UIWindow in didFinishLaunchingWithOptions. Defer loading of the main UI until the user is authorized by the BlackBerry Dynamics SDK. Register the scene delegate with your GDiOSDelegate so the authorized UI can be installed later.

    Swift:

    import UIKit
    import BlackBerryDynamics.Runtime
    class AppSceneDelegate: UIResponder, UIWindowSceneDelegate {
        var window: UIWindow?
        func scene(_ scene: UIScene,
                   willConnectTo session: UISceneSession,
                   options connectionOptions: UIScene.ConnectionOptions) {
            guard let windowScene = scene as? UIWindowScene else { return }
            if let keyWin = windowScene.keyWindow {
                window = keyWin
            } else {
                window = UIWindow(windowScene: windowScene)
                window?.makeKeyAndVisible()
            }
            AppGDiOSDelegate.shared.sceneDelegate = self
        }
        func launchApplicationUI() {
            let storyboard = UIStoryboard(name: "Main", bundle: nil)
            window?.rootViewController = storyboard.instantiateInitialViewController()
        }
    }
  2. In AppDelegate, start authorization in didFinishLaunchingWithOptions and connect the scene delegate class to the system scene configuration. Do not create a UIWindow in didFinishLaunchingWithOptions.
    Swift:
    import UIKit
    import BlackBerryDynamics.Runtime
    
    @UIApplicationMain
    class AppDelegate: UIResponder, UIApplicationDelegate {
    
       func application(_ application: UIApplication,
                        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    
           // Call BlackBerry Dynamics to authorise the app.
           GDiOS.sharedInstance().authorize(AppGDiOSDelegate.shared)
    
           return true
       }
    
       func application(_ application: UIApplication,
                        configurationForConnecting connectingSceneSession: UISceneSession,
                        options: UIScene.ConnectionOptions) -> UISceneConfiguration {
           let sceneConfig = UISceneConfiguration(name: "Default Configuration",
                                                    sessionRole: connectingSceneSession.role)
           sceneConfig.delegateClass = AppSceneDelegate.self
           sceneConfig.sceneClass = UIWindowScene.self
           return sceneConfig
       }
    }
  3. Import BlackBerryDynamics.Runtime and implement a skeleton GDiOSDelegate protocol. The following Swift example relies on a boolean variable named started. Alternatively, you can declare the variable in your project's implementation file. Hold a weak reference to the scene delegate so that the main UI can be loaded after authorization.

    Swift:

    import UIKit
    import BlackBerryDynamics.Runtime
    class AppGDiOSDelegate: NSObject, GDiOSDelegate {
        static let shared = AppGDiOSDelegate()
        weak var sceneDelegate: AppSceneDelegate?
    	private var started = false
    }
  4. Use GDAppEvent to process events. Move the application launch code from didFinishLaunchingWithOptions to the GDAppEvent handler method. Add the following method to AppGDiOSDelegate. Handle each event type in the switch statement. The cases below are shown as a skeleton and can be filled in as your application requires.

    Swift:

    func handle(_ anEvent: GDAppEvent) {
           /* Called from GDiOS when events occur, such as system startup. */
           switch anEvent.type {
           case .authorized:
               onAuthorized(anEvent: anEvent)
               break
    
           case .notAuthorized:
               onNotAuthorized(anEvent: anEvent)
               break
    
           case .remoteSettingsUpdate:
               // A change to application configuration or other settings.
               break
    
           case .servicesUpdate:
               // A change to services-related configuration.
               break
    
           case .policyUpdate:
               // A change to application-specific policy settings.
               break
    
           case .entitlementsUpdate:
               // A change to the entitlements data of the end user.
               break
    
           case .backgroundAuthorized:
               // Authorized following background authorization processing.
               break
    
           case .backgroundNotAuthorized:
               // Not authorized following background authorization processing.
               break
    
           default:
               print("handleEvent \(anEvent.message)")
           }
       }
  5. Handle onNotAuthorized events. Verify that the app can handle authorization errors or functionality, including remote wipe, a lockout, or blocking events. Add the following method to AppGDiOSDelegate.

    Swift:

    func onNotAuthorized(anEvent: GDAppEvent) {
           /* Handle the BlackBerry Libraries not authorized event. */
           switch anEvent.code {
           case .errorActivationFailed: break
           case .errorProvisioningFailed: break
           case .errorPushConnectionTimeout: break
           case .errorSecurityError: break
           case .errorAppDenied: break
           case .errorAppVersionNotEntitled: break
           case .errorBlocked: break
           case .errorWiped: break
           case .errorRemoteLockout: break
           case .errorPasswordChangeRequired:
               // A condition has occurred denying authorization; an application may wish to log these events.
               print("onNotAuthorized \(anEvent.message)")
           case .errorIdleLockout:
               // Idle lockout is benign and informational.
               break
           default:
               assertionFailure("Unhandled not authorized event")
           }
       }
  6. On authorization, start the app. Initialize and start the UI with the onAuthorized function. Add the following method to AppGDiOSDelegate.The GDErrorNone event is returned by the BlackBerry Dynamics Runtime whenever a container is opened and no error occurs.

    Swift:

    func onAuthorized(anEvent: GDAppEvent) {
           /* Handle the BlackBerry Libraries authorized event. */
           switch anEvent.code {
           case .errorNone:
               // started was declared in step 3.
               if !started {
                   // Show the user UI.
                   started = true
                   sceneDelegate?.launchApplicationUI()
               }
           default:
               assertionFailure("Authorized startup with an error")
           }
       }