Skip to content

Latest commit

 

History

History
157 lines (105 loc) · 4.86 KB

File metadata and controls

157 lines (105 loc) · 4.86 KB

FeatureFlags

This package purpose is to helps fetch feature flags and manage feature flags comming from the new Unleash tool. It contains default implementations for instantiation component.

What

  • Unleash
  • Uses of Apple's new structured concurrency (Async/Await)
  • Local Storage

Getting Started

Installation

FeatureFlags is installed via the official Swift Package Manager.

Select Xcode>File> Swift Packages>Add Package Dependency...
and add https://git@github.com:ProtonMail/protoncore_ios.git.

Setup

Import the following:

import FeatureFlags
import ProtonCoreServices

In the startup sequence of your app, setup the FeatureFlagsRepository singleton:

// Set the API service
let apiService = YouAPIService()
FeatureFlagsRepository.shared.setApiService(apiService)

// Set the user ID as soon as you have it (likely in the session refresh steps on app start, and after login)
// Important: setting an empty-string for userId will fetch features flags for an unauthenticated session.
if !userID.isEmpty {
    FeatureFlagsRepository.shared.setUserId(userID)
}

// Fetch updated feature flag values for the logged-in user (or unauthenticated session)
Task {
    try await FeatureFlagsRepository.shared.fetchFlags()
}

Alternatively, you can create you own implementation for the local data source of feature flags by implementing LocalFeatureFlagsDataSourceProtocol.

In this case, you can set your local data source with:

    let customLocalFeatureFlagsDataSource = MyDataSource()

    FeatureFlagsRepository.shared.updateLocalDataSource(customLocalFeatureFlagsDataSource)

You can now use the shared FeatureFlagsRepository to fetch and check the value of feature flags.

Defining you Feature Flag values

Get the Flag name from Unleash

Go to your project's Unleash dashboard and get the name of your desired feature ("MyFeature" in the example below).

Create an enum conforming to FeatureFlagTypeProtocol like:

public enum MyFlagType: String, FeatureFlagTypeProtocol {
    case myFeature = "MyFeature"
}

Actions

Fetch flags

This updates the local feature flag data source:

    try await FeatureFlagsRepository.shared.fetchFlags()

fetchFlags() uses the userId and apiService set with setUserId(_:) and setApiService(_:) respectively.

Check the value of a feature flag

To check the value of a given feature flag, use:

    let isMyFeatureEnabled: Bool = FeatureFlagRepository.shared.isEnabled(MyFlagType.myFeature)

isEnabled() implicitly uses the userId and apiService set with setUserId(_:) and setApiService(_:) respectively.

To check the value for a given user, call:

    let isMyFeatureEnabled: Bool = FeatureFlagRepository.shared.isEnabled(MyFlagType.myFeature, for: userId)

where userId is the user ID of the logged-in user (useful in multi-user contexts).

IMPORTANT: by default, calls to isEnabled() will return the same value for a given user for the duration of the app lifecycle. That is, subsequent calls to update the local data source (fetchFlags()) will by default not change the value returned from isEnabled(). This is by design to protect against internal inconsistency.

If you wish to read the latest value fetched for a given feature flag and user, call

    let isMyFeatureEnabled: Bool = FeatureFlagRepository.shared.isEnabled(MyFlagType.myFeature, 
                                                                          for: userId,
                                                                          reloadValue: true)

Override Flag

If you need to override a flag, or set a local override one, you can do so invoking:

    FeatureFlagsRepository.shared.setFlagOverride(flagName, overrideWithValue: value)

in the same way, to remove an overridden flag:

    FeatureFlagsRepository.shared.resetFlagOverride(flagName)

To remove any override

    FeatureFlagsRepository.shared.resetOverrides()

Where feature flags returned by Unleash are bound to the user session, overridden flags are not. This will allow to set overrides before a session is initated (i.e. sign up flow).

When checking for the status of a flag using:

    FeatureFlagRepository.shared.isEnabled(MyFlagType.myFeature)

We first check for any overridden flag with the same name, if no overridden flag is found we then look in the list of flags returned by Unleash

Logout

On logout, clear the feature flags for that user, and also the user ID set on the shared FeatureFlagsRepository.

    FeatureFlagsRepository.shared.resetFlags(for: userId)
    FeatureFlagsRepository.shared.clearUserId(userId)