- Notifications
You must be signed in to change notification settings - Fork0
MacPaw/growthbook-swift
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
- Lightweight and fast
- Supports native Apple platforms
- macOS version 10.15 & Above
- iOS version 12.0 & Above
- Apple tvOS version 12.0 & Above
- Apple watchOS version 5.0 & Above
- Apple visionOS version 1.0 & Above
- Adjust variation weights and targeting without deploying new code
- Latest spec version: 0.7.0View Changelog
CocoaPods is a dependency manager for Cocoa projects. For usage and installation instructions, visit their website. To integrate GrowthBook into your Xcode project using CocoaPods, specify it in yourPodfile
:
If you're using version 1.0.46 or above, it could be necessary to set "User Script Sandboxing" to "No" in your build settings.
Add below line in your podfile, if not there
source 'https://github.com/CocoaPods/Specs.git'
- Add below in podfile - in respective target block
pod 'GrowthBook-IOS'
- Execute below command in terminal
pod install
TheSwift Package Manager is a tool for automating the distribution of Swift code and is integrated into theswift
compiler.
Once you have your Swift package set up, adding GrowthBook as a dependency is as easy as adding it to thedependencies
value of yourPackage.swift
.
dependencies:[.package(url:"https://github.com/growthbook/growthbook-swift.git")]
Integration is super easy:
- Create a Growth Book with a few methods: with the API key and host URL, only host URL, only JSON
- At the start of your app, do SDK Initialization as per below
Now you can start/stop tests, adjust coverage and variation weights, and apply a winning variation to 100% of traffic, all within the Growth Book App without deploying code changes to your site.
varsdkInstance:GrowthBookSDK=GrowthBookBuilder(apiHost:<GrowthBook/API_HOST>, clientKey:<GrowthBook/Client_KEY>, attributes:<[String: Any]>, trackingCallback:{ experiment, experimentResultin}, backroundSync: Bool?).initializer()
You must also provide the encryption key if you intend to use data encryption.
varsdkInstance:GrowthBookSDK=GrowthBookBuilder(apiHost:<GrowthBook/API_HOST>, clientKey:<GrowthBook/Client_KEY>, attributes:<[String: Any]>, trackingCallback:{ experiment, experimentResultin}).initializer()
varsdkInstance:GrowthBookSDK=GrowthBookBuilder(apiHost:<GrowthBook/API_HOST>, clientKey:<GrowthBook/Client_KEY>, attributes:<[String: Any]>, trackingCallback:{ experiment, experimentResultin}).initializer()
There are additional properties which can be setup at the time of initialization
varsdkInstance:GrowthBookSDK=GrowthBookBuilder(apiHost:<GrowthBook/API_HOST>, clientKey:<GrowthBook/Client_KEY>, attributes:<[String: Any]>, trackingCallback:{ experiment, experimentResultin}).setRefreshHandler{ isRefreshedin} // Get Callbacks when SDK refreshed its cache.setNetworkDispatcher(networkDispatcher:<Network Dispatcher>) // Pass Network client to be used for API Calls.setEnabled(isEnabled:true) // Enable / Disable experiments.setQAMode(isEnabled:true) // Enable / Disable QA Mode.setForcedVariations(forcedVariations:<[String: Int]>) // Pass Forced Variations.setLogLevel(<LoggerLevel>) // Set log level for SDK Logger, by default log level is set to `info`.setCacheDirectory(<CacheDirectory>) // This function configures the cache directory used by the application to the designated directory type. Subsequent cache-related operations will target this directory..setStickyBucketService(stickyBucketService:StickyBucketService()) // This function creates a sticky bucket service..initializer()
Initialization returns SDK instance - GrowthBookSDK
The feature method takes a single string argument, which is the unique identifier for the feature and returns a FeatureResult object.
func evalFeature(id:String)->FeatureResult
- The run method takes an Experiment object and returns an experiment result
func run(experiment:Experiment)->ExperimentResult
- Manually Refresh Cache
func refreshCache()
- Get Context
func getGBContext()->Context
- Get Features
func getFeatures()->Features
- Get the value of the feature with a fallback
func getFeatureValue(feature id:String, defaultValue:JSON)->JSON
- The isOn method takes a single string argument, which is the unique identifier for the feature and returns the feature state on/off
func isOn(feature id:String)->Bool
- The setEncryptedFeatures method takes an encrypted string with an encryption key and then decrypts it with the default method of decrypting or with a method of decrypting from the user.
func setEncryptedFeatures(encryptedString:String, encryptionKey:String, subtle:CryptoProtocol?=nil)
/// Defines the GrowthBook context.classContext{ /// api hostpublicletapiHost:String? /// unique client keypublicletclientKey:String? /// Encryption key for encrypted features.letencryptionKey:String? /// Switch to globally disable all experiments. Default true.letisEnabled:Bool /// Map of user attributes that are used to assign variationsvarattributes:JSON /// Force specific experiments to always assign a specific variation (used for QA)letforcedVariations:JSON? /// If true, random assignment is disabled and only explicitly forced variations are used.letisQaMode:Bool /// A function that takes experiment and result as arguments.lettrackingCallback:(Experiment,ExperimentResult)->Void // Keys are unique identifiers for the features and the values are Feature objects. // Feature definitions - To be pulled from API / Cachevarfeatures:Features}
/// A Feature object consists of possible values plus rules for how to assign values to users.classFeature{ /// The default value (should use null if not specified)letdefaultValue:JSON? /// Array of Rule objects that determine when and how the defaultValue gets overriddenletrules:[FeatureRule]?}/// Rule object consists of various definitions to apply to calculate feature valuestructFeatureRule{ /// Optional targeting conditionletcondition:JSON? /// What percent of users should be included in the experiment (between 0 and 1, inclusive)letcoverage:Float? /// Immediately force a specific value (ignore every other option besides condition and coverage)letforce:JSON? /// Run an experiment (A/B test) and randomly choose between these variationsletvariations:[JSON]? /// The globally unique tracking key for the experiment (default to the feature key)letkey:String? /// How to weight traffic between variations. Must add to 1.letweights:[Float]? /// A tuple that contains the namespace identifier, plus a range of coverage for the experiment.letnamespace:[JSON]? /// What user attribute should be used to assign variations (defaults to id)lethashAttribute:String? /// Hash version of hash functionlethashVersion:Float? /// A more precise version of `coverage`letrange:BucketRange? /// Ranges for experiment variationsletranges:[BucketRange]? /// Meta info about the experiment variationsletmeta:[VariationMeta]? /// Array of filters to apply to the ruleletfilters:[Filter]? /// Seed to use for hashingletseed:String? /// Human-readable name for the experimentletname:String? /// The phase id of the experimentletphase:String? /// Array of tracking calls to firelettracks:[TrackData]?}/// Enum For defining feature value sourceenumFeatureSource:String{ /// Queried Feature doesn't exist in GrowthBookcase unknownFeature /// Default Value for the Feature is being processedcase defaultValue /// Forced Value for the Feature is being processedcase force /// Experiment Value for the Feature is being processedcase experiment} /// Result for FeatureclassFeatureResult{ /// The assigned value of the featureletvalue:JSON? /// The assigned value cast to a booleanpublicvarisOn:Bool=false /// The assigned value cast to a boolean and then negatedpublicvarisOff:Bool=true /// One of "unknownFeature", "defaultValue", "force", or "experiment"letsource:String /// When source is "experiment", this will be the Experiment object usedletexperiment:Experiment? /// When source is "experiment", this will be an ExperimentResult objectletexperimentResult:ExperimentResult?}
/// Defines a single experimentclassExperiment{ /// The globally unique tracking key for the experimentletkey:String /// The different variations to choose betweenletvariations:[JSON] /// A tuple that contains the namespace identifier, plus a range of coverage for the experimentletnamespace:[JSON]? /// All users included in the experiment will be forced into the specific variation indexlethashAttribute:String? /// How to weight traffic between variations. Must add to 1.varweights:[Float]? /// If set to false, always return the control (first variation)varisActive:Bool /// What percent of users should be included in the experiment (between 0 and 1, inclusive)varcoverage:Float? /// Optional targeting conditionvarcondition:JSON? /// All users included in the experiment will be forced into the specific variation indexvarforce:Int? /// Array of ranges, one per variationletranges:[BucketRange]? /// Meta info about the variationsletmeta:[VariationMeta]? /// Array of filters to applyletfilters:[Filter]? /// The hash seed to useletseed:String? /// Human-readable name for the experimentletname:String? /// Id of the current experiment phaseletphase:String?}/// The result of running an Experiment given a specific ContextclassExperimentResult{ /// Whether or not the user is part of the experimentletinExperiment:Bool /// The array index of the assigned variationletvariationId:Int /// The array value of the assigned variationletvalue:JSON /// The user attribute used to assign a variationlethashAttribute:String? /// The value of that attributeletvalueHash:String? /// The unique key for the assigned variationletkey:String /// The human-readable name of the assigned variationletname:String? /// The hash value used to assign a variation (float from `0` to `1`)letbucket:Float? /// Used for holdout groupsletpassthrough:Bool?}/// Meta info about the variationspublicstructVariationMeta{ /// Used to implement holdout groupsletpassthrough:Bool? /// A unique key for this variationletkey:String? /// A human-readable name for this variationletname:String?}///Used for remote feature evaluation to trigger the `TrackingCallback`publicstructTrackData{letexperiment:Experimentletresult:ExperimentResult}
To enable streaming updates set backgroundSync variable to "true"
var sdkInstance: GrowthBookSDK = GrowthBookBuilder(apiHost: <GrowthBook/API_KEY>, clientKey: <GrowthBook/ClientKey>, attributes: <[String: Any]>, trackingCallback: { experiment, experimentResult in}, refreshHandler: { isRefreshed in}, backgroundSync: true).initializer()
This mode brings the security benefits of a backend SDK to the front end by evaluating feature flags exclusively on a private server. Using Remote Evaluation ensures that any sensitive information within targeting rules or unused feature variations are never seen by the client. Note that Remote Evaluation should not be used in a backend context.
You must enable Remote Evaluation in your SDK Connection settings. Cloud customers are also required to self-host a GrowthBook Proxy Server or custom remote evaluation backend.
To use Remote Evaluation, add theremoteEval: true
property to your SDK instance. A new evaluation API call will be made any time a user attribute or other dependency changes. You may optionally limit these API calls to specific attribute changes by setting thecacheKeyAttributes
property (an array of attribute names that, when changed, trigger a new evaluation call).
var sdkInstance: GrowthBookSDK = GrowthBookBuilder(apiHost: <GrowthBook/API_KEY>, clientKey: <GrowthBook/ClientKey>, attributes: <[String: Any]>, trackingCallback: { experiment, experimentResult in}, refreshHandler: { isRefreshed in}, remoteEval: true).initializer()
note
If you would like to implement Sticky Bucketing while using Remote Evaluation, you must configure your remote evaluation backend to support Sticky Bucketing. You will not need to provide a StickyBucketService instance to the client side SDK.
Sticky bucketing ensures that users see the same experiment variant, even when user session, user login status, or experiment parameters change. See theSticky Bucketing docs for more information. If your organization and experiment supports sticky bucketing, you must implement an instance of theStickyBucketService
to use Sticky Bucketing. For simple bucket persistence using the browser's LocalStorage (can be polyfilled for other environments).
This project uses the MIT license. The core GrowthBook app will always remain open and free, although we may add some commercial enterprise add-ons in the future.
About
GrowthBook iOS (Swift) SDK
Topics
Resources
License
Stars
Watchers
Forks
Packages0
Languages
- Swift98.6%
- Other1.4%