Remote configuration and A/B Testing framework for iOS

Overview

MSActiveConfig v1.0.1

Remote configuration and A/B Testing framework for iOS. Documentation available online.

Build Status

MSActiveConfig at a glance

One of the big challenges when making iOS apps is a consequence of the fact that pushing an app update takes a long time. Sometimes we want to be able to change something in one of our apps remotely as quickly as possible.

const BOOL isThisFeatureEnabled = [activeConfig[@"AppFeatures"] boolForKey:@"SomeFeatureEnabled"];

with this one-liner, MSActiveConfig would tell us if that particular feature has been enabled by us, but we can also react to changes on the configuration in real time:

[activeConfig registerListener:self
        		forSectionName:@"AppFeatures"];

- (void)activeConfig:(MSActiveConfig *)activeConfig
didReceiveConfigSection:(MSActiveConfigSection *)configSection
        forSectionName:(NSString *)sectionName
{
	[self changeFeatureEnabledStatus:configSection[@"SomeFeatureEnabled"]];
}

Use cases

  • Enabling and disabling features. This allows you to test features with only a subset of users before you roll it out to everyone, or to control the load that feature creates on on your backend, for example.
  • Delaying making decisions after submitting the app. E.g.: how often should this request happen?, How many times should this be retried? With Active Config you no longer need to know the answer to those questions before you send your app to Apple, since you can change those values later easily.
  • A/B Testing! If you can serve a configuration to your users, you can serve different configurations to different users.

A/B Testing

The A/B Testing frameworks out there give most of the responsibility to the app: they assume the app is going to know all the possible values that you are going to want to test for a specific feature. This is incredibly restrictive, since it will force you to update your app to try new values. Active Config encourages you to leave the knowledge on the backend, giving your more control.

For example, if you were to A/B test some text on some part of your app, traditional A/B test frameworks would tell the app to choose option A, or option B. This way, the app must know before hand what those strings are. With Active Config, you would put the string inside the configuration, so you can change them at any point.

Of course there's a lot more to A/B testing than what MSActiveConfig does, but it provides the foundation for you to implement it in your apps with a lot of flexibility. More specific tools for A/B testing are coming in future releases.

Installation

Using CocoaPods:

  • Add pod 'MSActiveConfig', '~> 1.0.1' to your Podfile.
  • You're done!

Using submodules:

git submodule add [email protected]:mindsnacks/MSActiveConfig.git <path/to/your/submodule>

There are two ways you can integrate MSActiveConfig into your project:

  • If you already have a workspace or don't mind creating one:

    • Add the MSActiveConfig.xcodeproj file into your project by dragging and dropping it.
    • Select your project on Xcode, and then your target and navigate to "Build Phases".
    • Tap on the "+" button on "Target Dependencies" and add MSActiveConfig.
    • Tap on the "+" button on "Link Binary with Libraries" and select libMSActiveConfig.a.
  • By simply adding the source files inside MSActiveConfig/Classes into your project and compiling them with the rest of your source.

Usage

Start by importing MSActiveConfig.h. A typical app would have one MSActiveConfig object that you create like this:

id<MSActiveConfigDownloader> configDownloader = ...
id<MSActiveConfigStore> configStore = ...

MSActiveConfig *activeConfig = [[MSActiveConfig alloc] initWithConfigDownloader:configDownloader
																	configStore:configStore];

For a complete code snippet on how to instantiate the MSActiveConfig object, check the wiki.

MSActiveConfigDownloader

A class must conform to this protocol to allow MSActiveConfig to retrieve updates from the network. The given class needs to implement this method.

- (NSDictionary *)requestActiveConfigForUserWithID:(NSString *)userID
                                             error:(NSError **)error;

For most applications, the provided MSJSONURLRequestActiveConfigDownloader class will suffice, it allows you to create a downloader object like this:

downloader = [[MSJSONURLRequestActiveConfigDownloader alloc] initWithCreateRequestBlock:^NSURLRequest *(NSString *userID) {
	return [NSURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"http://myserver.com/activeconfig/user/%@", userID]]];
}];

Note: MSActiveConfig will never start a download on its own, you must use the public method -downloadNewConfig to tell it to download.

MSActiveConfigStore

This protocol defines a series of methods that allows MSActiveConfig to persist downloaded configuration to be able to retrieve it on subsequent app launches in order to always use the most up to date configuration.

- (MSActiveConfigConfigurationState *)lastKnownActiveConfigurationForUserID:(NSString *)userID;
- (void)persistConfiguration:(MSActiveConfigConfigurationState *)configuration forUserID:(NSString *)userID;

MSActiveConfig provides one implementation of this protocol that uses NSUserDefault as its backing store: MSUserDefaultsActiveConfigStore. This class also allows you to provide an initial or bootstrapped configuration that will be use until the app successfully downloads a more recent configuration from the server.

- (id)initWithInitialSharedConfiguration:(MSActiveConfigConfigurationState *)initialSharedConfiguration;

MSActiveConfigConfigurationState

This class represents a given configuration set that Active Config can use to provide setting values. It can be instantiated from an NSDictionary for example to create the initial configuration for MSUserDefaultsActiveConfigStore by parsing a JSON file in the app bundle.

MSActiveConfigSection

This is the type of object that you get when you ask MSActiveConfig for configuration. It's a wrapper around all the setting keys and values in the specified ConfigSection (See Configuration Exchange Format below). It has methods to retrieve a value expecting a specific type, and returns a form of nil in case the setting key isn't present or it has a different type.

Configuration Exchange Format

MSActiveConfig is built to be extremely flexible. The only rules that you need to follow are imposed by the configuration exchange format that MSActiveConfig understands. The configuration is represented in a dictionary object that must look like this:

{
    "meta":
    {
        "format_version_string": "1.0",
        "creation_time": "2012-08-20T19:36Z",
        "other_meta_key": "arbitrary objects with other relevant information"
    },
    "config_sections":
    {
        "ConfigSection1":
        {
            "settings":
            {
                "SettingKey1":
                {
                    "value": "This can be a a string, number, boolean, array or object"
                }
            }
        },
    }
}

When you ask MSActiveConfig to download an update of the configuration, it will expect a dictionary with this format. If the provided dictionary can't be parsed, the problem will be logged to the console and the configuration will be ignored.

Meta

The meta section of the configuration must contain the format version (for future use) and the creation time (for debug purposes). All other added values are optional but can be used to give context to the configuration.

For example, if you're using MSActiveConfig to do some kind of A/B Testing, you can add some information to the meta dictionary to later on identify what group of the test that user belongs to when sending events to your analytics service. You can access the meta dictionary in two ways:

  • When a new configuration finishes downloading, MSActiveConfig posts an NSNotification (MSActiveConfigDownloadUpdateFinishedNotification) that contains the meta dictionary in one of the userInfo keys (MSActiveConfigDownloadUpdateFinishedNotificationMetaKey).
  • At any time, by calling the -currentConfigurationMetaDictionary method on MSActiveConfig.

Config Section

This is the top level group of settings. A section groups a series of settings that are relevant to a specific component of your app. When using the -registerListener:forSectionName: API, you can be notified when any of the settings of a section changes. They're represented with the MSActiveConfigSection class.

Setting Key

This is a particular setting contained within a section. These are the ones that you'll ask MSActiveConfigSection for.

User ID Support

MSActiveConfig provides APIs to allow you to have different configurations for different users on your app. This is designed for apps that allow you to log-out and log-in with a different user. If this is not your case, all these APIs allow you to simply use nil as a userID.

Sample app

Run the target MSActiveConfig-SampleApp on the Xcode project for a sample implementation of MSActiveConfig on an app. This sample app uses this backend to get its configuration.

Roadmap

MSActiveConfig is a solid framework that has been shipping in a handful of apps with millions of users for > 6 months. Future work is captured in the issues page.

Requirements

MSActiveConfig requires iOS6 or higher, but it would be easy to make it support iOS5 if you really need it for your project.

License

MSActiveConfig is available under the MIT license. See the LICENSE file for more info.

You might also like...
I built this application with unit testing and test-driven development to understand TDD theory and practice
I built this application with unit testing and test-driven development to understand TDD theory and practice

TestDrivenDevelopment Description I built this application with unit testing and test-driven development to understand TDD theory and practice, to wri

Snapshot testing tool for iOS and tvOS
Snapshot testing tool for iOS and tvOS

SnapshotTest is a simple view testing tool written completely in Swift to aid with development for Apple platforms. It's like unit testing for views.

A Mac and iOS Playgrounds Unit Testing library based on Nimble.
A Mac and iOS Playgrounds Unit Testing library based on Nimble.

Spry Spry is a Swift Playgrounds Unit Testing library based on Nimble. The best thing about Spry is that the API matches Nimble perfectly. Which means

Multivariate & A/B Testing for iOS and Mac

This library is no longer being maintained. You can continue to use SkyLab in your projects, but we recommend switching another solution whenever you

Sample project for testing out focus in SwiftUI and iOS 15

This project was to test out different ways of enabling focus in a SwiftUI app.

UI Testing Cheat Sheet and Examples.

UI Testing Cheat Sheet This repository is complementary code for my post, UI Testing Cheat Sheet and Examples. The post goes into more detail with exa

Runtime introspection and unit testing of SwiftUI views

ViewInspector 🕵️‍♂️ for SwiftUI ViewInspector is a library for unit testing SwiftUI views. It allows for traversing a view hierarchy at runtime provi

Swifty tool for visual testing iPhone and iPad apps. Every pixel counts.

Cribble Cribble - a tool for visual testing iPhone and iPad apps. Every pixel counts. Getting Started An example app is included demonstrating Cribble

An understated approach to iOS integration testing.
An understated approach to iOS integration testing.

Subliminal is a framework for writing iOS integration tests. Subliminal provides a familiar OCUnit/XCTest-like interface to Apple's UIAutomation frame

Comments
  • Xcode-6 build failure

    Xcode-6 build failure

    Auto property synthesis will not synthesize property 'foo' because it is 'readwrite' but it will be synthesized 'readonly' via another property. I have a patch and I can push it if you want ?

    opened by ajitsinghmalra 1
  • Unable to run

    Unable to run

    This sample i cant able to run in Xcode4.5. This is showing following errors. Please update it. And both XIB's (MSSettingsViewController.xib & MSSampleViewController.xib) are showing error when i am trying to open in xcode 4.5.

    Error: The document "MSSampleViewController.xib" could not be opened. Could not read archive.Please use a newer version of Xcode. Consider changing the document's Development Target to preserve compatibility.

    screen shot 2013-08-01 at 11 05 05 am

    opened by govindaraokondala 1
Releases(v1.0.1)
SwiftCheck is a testing library that automatically generates random data for testing of program properties

SwiftCheck QuickCheck for Swift. For those already familiar with the Haskell library, check out the source. For everybody else, see the Tutorial Playg

TypeLift 1.4k Dec 21, 2022
Testing the UI without UI Testing, a Swift experiment.

UI tests without UI Testing experiment This repo is a small experiment to see if there's an "in-between" for testing iOS applications. More feature-le

Joe Masilotti 20 Sep 26, 2022
The Swift (and Objective-C) testing framework.

Quick is a behavior-driven development framework for Swift and Objective-C. Inspired by RSpec, Specta, and Ginkgo. // Swift import Quick import Nimbl

Quick 9.6k Dec 31, 2022
T - A simple testing framework using closures and errors

t Quickly test expectations What is t? t is a simple testing framework using clo

OpenBytes 6 Nov 7, 2022
AB testing framework for iOS

ABKit Split Testing for Swift. ABKit is a library for implementing a simple Split Test that: Doesn't require an HTTP client written in Pure Swift Inst

Recruit Marketing Partners Co.,Ltd 113 Nov 11, 2022
Keep It Functional - An iOS Functional Testing Framework

IMPORTANT! Even though KIF is used to test your UI, you need to add it to your Unit Test target, not your UI Test target. The magic of KIF is that it

KIF Framework 6.2k Dec 29, 2022
Genything is a framework for random testing of a program properties.

Genything is a framework for random testing of a program properties. It provides way to random data based on simple and complex types.

Just Eat Takeaway.com 25 Jun 13, 2022
Automatic testing of your Pull Requests on GitHub and BitBucket using Xcode Server. Keep your team productive and safe. Get up and running in minutes. @buildasaur

Buildasaur Automatic testing of your Pull Requests on GitHub and BitBucket using Xcode Server. Keep your team productive and safe. Get up and running

Buildasaurs 774 Dec 11, 2022
Implementing and testing In-App Purchases with StoreKit2 in Xcode 13, Swift 5.5 and iOS 15.

StoreHelper Demo Implementing and testing In-App Purchases with StoreKit2 in Xcode 13, Swift 5.5, iOS 15. See also In-App Purchases with Xcode 12 and

Russell Archer 192 Dec 17, 2022
A flexible mock server for automated and regression testing of iOS, Android and other apps.

Note: This document is intended as a quick introduction to Voodoo. As Voodoo has a large number of features, please refer to Voodoo's Github Wiki for

Derek Clarkson 7 Nov 23, 2022