Zone5 SDK for Swift

Unit Test Status

Installation

Swift Package Manager

The most straightforward method of installing the SDK is as a Swift Package, which can be done by adding it as a dependency in Package.swift, or by following Apple’s documentation on adding package dependencies in Xcode.

import PackageDescription

let package = Package(
    [...]
    dependencies: [
        .package(url: "https://github.com/Zone5-Cloud/z5-sdk-swift.git", from: "1.0.0"),
    ]
)

Carthage

Install the SDK via Carthage by adding the following line to your Cartfile:

github "Zone5-Cloud/z5-sdk-swift"

Getting Started

Once you’ve installed the SDK, getting started with using it in your app only takes a handful of steps. Before using it, you’ll need to configure it with the OAuth client details used to identify your app to the server:

import Zone5

let baseURL = URL(string: "https://your-zone5-server.com")!
let clientID = "YOUR-CLIENT-IDENTIFIER"
let clientSecret = "YOUR-CLIENT-SECRET"

// for an unauthenticated session (not yet logged in)
Zone5.shared.configure(for: baseURL, clientID: clientID, clientSecret: clientSecret)

// for persisting a logged in session across App restarts. 
let accessToken: OAuthToken? = <read json OAuthToken from a keystore>
Zone5.shared.configure(for: baseURL, clientID: clientID, clientSecret: clientSecret, accessToken: accessToken)

A saved OAuthToken only needs to be passed in at startup. The state of the token is automatically updated on login, logout, accessToken, refreshAccessToken and automatic token refresh. Token refresh is handled automatically before all authenticated calls and then token updated accordingly.

Whenever the accessToken is updated, either because you called login, logout, accessToken or refreshAccessToken or because of an automatic refresh, the Notification Zone5.authTokenChangedNotification is fired on the Zone5 instance with the updated OAuthToken in the userInfo.

Observe this Notification so that you can save the updated Token to persist logged in sessions across App restarts. e.g.

apiClient.notificationCenter.addObserver(forName: Zone5.authTokenChangedNotification, object: Zone5.shared, queue: nil) { notification in
    let token = notification.userInfo?["accessToken"] as? OAuthToken
    keyValueStore.oauthToken = token
}

If there are updated Terms and Conditions identified after a login or refresh, the Notification Zone5.updatedTermsNotification is fired with the list of updated terms in the userInfo. Observe this Notification so that you can prompt users to re-accept updated Terms and Conditions. e.g.

apiClient.notificationCenter.addObserver(forName: Zone5.updatedTermsNotification, object: Zone5.shared, queue: nil) { notification in
    let terms = notification.userInfo?["updatedTerms"] as? [UpdatedTerms]
    // do something with terms
}

Once configured, you’ll be able to authenticate users via the methods available through Zone5.shared.users.login and Zone5.shared.oAuth.accessToken:

let username = "EXAMPLE-USERNAME"
let password = "EXAMPLE-PASSWORD"

Zone5.shared.users.login(email: username, password: password, accept: []) { result in
    switch result {
    case .failure(let error):
        // An error occurred and needs to be handled

    case .success(let loginResponse):
        // The user was successfully authenticated. loginResponse contains some user data including roles, identities, updatedTerms etc
        // Your configured accessToken has automatically been updated and the `Zone5.authTokenChangedNotification` Notification fired
    }
}

or

Zone5.shared.oAuth.accessToken(username: username, password: password) { result in
    switch result {
    case .failure(let error):
        // An error occurred and needs to be handled

    case .success(let accessToken):
        // The user was successfully authenticated. 
        // Your configured accessToken has automatically been updated and the `Zone5.authTokenChangedNotification` Notification fired
    }
}

Once authenticated you can make authenticated calls such as:

Zone5.shared.users.me { result in
    switch result {
    case .failure(let error):
        // An error occurred and needs to be handled

    case .success(let user):
        // The user's information was successfully retrieved.
    }
}

Unauthenticated calls do not require the user to be logged in. These calls include things like Zone5.shared.terms.required, Zone5.shared.users.isEmailRegistered, Zone5.shared.users.register, Zone5.shared.users.resetPassword. See https://zone5-cloud.github.io/z5-sdk-swift/Classes/UsersView and https://zone5-cloud.github.io/z5-sdk-swift/Classes/TermsView for details on using these methods.

A basic usage for a registration screen may be:

  • Call Zone5.shared.terms.required to retrieve the required Terms and Conditions. If the Terms are hosted at an external URL (such as the Specialized Terms of Use), then the response will include the URL of the Terms Content.
  • Call Zone5.shared.users.isEmailRegistered once a user has entered a registration email so that the UI can provide feedback that this user already exists.
  • Offer an option for the user to reset their existing password that calls Zone5.shared.users.resetPassword
  • Call Zone5.shared.users.register to register a new user in the system. Don’t let the user register until they have accepted terms and conditions. Make sure you pass the list of accepted Terms and Conditions ids into register

A basic usahe for a login screen may be:

  • Offer an option for the user to reset their existing password that calls Zone5.shared.users.resetPassword
  • Call the above mentioned Zone5.shared.users.login with the user’s credentials
  • If the login fails due to there being new, unaccepted Terms and Conditions
    • call Zone5.shared.terms.required and present new terms (by URL or by calling Zone5.shared.terms.download (SBC terms are by URL)
    • retry Zone5.shared.users.login, passing in new accepted terms
  • If the login succeeds but the login response includes updated terms, present new terms (SBC terms are by URL)
    • call Zone5.shared.terms.accept to accept the updated terms

Unit Tests

Unit tests are included and can be run from both the Swift CLI and via Xcode. There may be some slight differences in how these two sources run tests, so if tests are failing in one, but not the other, this may be the cause. Tests are run automatically on push (of any branch) using the Swift CLI, via a GitHub Action, the result of which can be browsed via the Actions tab.

Running Tests via Swift CLI

Run swift test from the repo’s root directory. Test results will be logged directly to your terminal window.

Running Tests via Xcode

In the Product menu, select Test, or use the keyboard shortcut—typically ⌘U. Test results are available from the Test Navigator (⌘6). Additional details—such as a coverage report—can be found in the Report Navigator (⌘9), by selecting the relevant Test report.

Documentation

You can find documentation for this project here. This documentation is automatically generated with jazzy from a GitHub Action and hosted with GitHub Pages.

To generate documentation locally, run make documentation or sh ./scripts/prepare_docs.sh from the repo’s root directory. The output will be generated in the docs folder, and should not be included with commits (as the online documentation is automatically generated and updated).