JustTweak is a framework for feature flagging and A/B testing for iOS apps.
JustTweak is a framework for feature flagging and A/B testing for iOS apps. It provides a simple facade interface interacting with multiple providers that are queried respecting a given priority. Tweaks represent flags used to drive decisions in the client code.
With JustTweak you can achieve the following:
JustTweak is available through CocoaPods. To install it, simply add the following line to your Podfile:
pod "JustTweak"
ExampleConfiguration.jsonas a template)
static let tweakManager: TweakManager = { // mutable configuration (to override tweaks from other configurations) let userDefaultsConfiguration = UserDefaultsConfiguration(userDefaults: UserDefaults.standard)// remote configurations (optional) let optimizelyConfiguration = OptimizelyConfiguration() optimizelyConfiguration.userId = let firebaseConfiguration = FirebaseConfiguration() // local JSON configuration (default tweaks) let jsonFileURL = Bundle.main.url(forResource: "ExampleConfiguration", withExtension: "json")! let localConfiguration = LocalConfiguration(jsonURL: jsonFileURL) // priority is defined by the order in the configurations array (from highest to lowest) let configurations: [Configuration] = [userDefaultsConfiguration, optimizelyConfiguration, firebaseConfiguration, localConfiguration] return TweakManager(configurations: configurations)
}()
The order of the objects in the
configurationsarray defines the priority of the configurations.
The
MutableConfigurationwith the highest priority, such as
UserDefaultsConfigurationin the example above, will be used to reflect the changes made in the UI (
TweakViewController). The
LocalConfigurationshould have the lowest priority as it provides the default values from a local configuration and it's the one used by the
TweakViewControllerto populate the UI.
The three main features of JustTweak can be accessed from the
TweakManagerinstance to drive code path decisions.
// check for a feature to be enabled let enabled = tweakManager.isFeatureEnabled("some_feature") if enabled { // enable the feature } else { // default behaviour }
TweakManagerwill return the value from the configuration with the highest priority and automatically fallback to the others if no set value is found.
Use either
tweakWith(feature:variable:)or the provided property wrappers.
// check for a tweak value let tweak = tweakManager.tweakWith(feature: "some_feature", variable: "some_flag") if let tweak = tweak { // tweak was found in some configuration, use tweak.value } else { // tweak was not found in any configuration }
@TweakPropertyand
@OptionalTweakPropertyproperty wrappers are available to mark properties representing feature flags. Mind that by using these property wrappers, a static instance of
TweakManageris needed.
@TweakProperty(fallbackValue: , feature: , variable: , tweakManager: ) var labelText: String
@OptionalTweakProperty(fallbackValue: , feature: , variable: , tweakManager: ) var meaningOfLife: Int?
// check for a tweak value let variation = tweakManager.activeVariation(for: "some_experiment") if let variation = variation { // act according to the kind of variation (e.g. "control", "variation_1") } else { // default behaviour }
The
TweakManagerprovides the option to cache the tweak values in order to improve performance. Caching is disabled by default but can be enabled via the
useCacheproperty. When enabled, there are two ways to reset the cache:
resetCachemethod on the
TweakManager
TweakConfigurationDidChangeNotificationnotification
JustTweak comes with a ViewController that allows the user to edit the
MutableConfigurationwith the highest priority.
func presentTweakViewController() { let tweakViewController = TweakViewController(style: .grouped, tweakManager: )// either present it modally let tweaksNavigationController = UINavigationController(rootViewController:tweakViewController) tweaksNavigationController.navigationBar.prefersLargeTitles = true present(tweaksNavigationController, animated: true, completion: nil) // or push it on an existing UINavigationController navigationController?.pushViewController(tweakViewController, animated: true)
}
When a value is modified in any
MutableConfiguration, a notification is fired to give the clients the opportunity to react and reflect changes in the UI.
override func viewDidLoad() { super.viewDidLoad() NotificationCenter.defaultCenter().addObserver(self, selector: #selector(updateUI), name: TweakConfigurationDidChangeNotification, object: nil) }@objc func updateUI() { // update the UI accordingly }
JustTweak comes with three configurations out-of-the-box:
UserDefaultsConfigurationwhich is mutable and uses
UserDefaultsas a key/value store
LocalConfigurationwhich is read-only and uses a JSON configuration file that is meant to be the default configuration
EphemeralConfigurationwhich is simply an instance of
NSMutableDictionary
In addition, JustTweak defines
Configurationand
MutableConfigurationprotocols you can implement to create your own configurations to fit your needs. In the example project you can find a few example configurations which you can use as a starting point.
JustTweak is available under the Apache 2.0 license. See the LICENSE file for more info.