MMBarricade - Runtime configurable local server for iOS apps.

Overview

MMBarricade

Platform Version Build Status

Why Barricade?

MMBarricade is a framework for setting up a run-time configurable local server in iOS apps. This works by creating a NSURLProtocol "barricade" that blocks outgoing network traffic and redirects it to a custom, local response, without requiring any changes to existing networking code.

NSURLSession, NSURLConnection, AFNetworking, and all other networking that utilizes Foundation's URL Loading System are supported.

Most other local server implementations only support a single response per request, but Barricade supports multiple responses per request. This allows us to present the user with an interface for modifying which response will be returned for a request at runtime.

Example App

When to use

During development barricade is useful for easily exercising all edge cases of a feature while you are building it without needing to frequently adjust the live server state.

For unit tests and integration tests barricade allows you to easily toggle through each predefined response for a request so tests can cover edge cases thoroughly.

Similarly, UI tests, such as KIF, can programmatically update selected responses as well, which allows your test suite to cover failure cases as well as the "happy path".

Take a look at the unit tests in MMBarricadeTests.m of DevelopmentApp/Barricade.xcworkspace for several examples of how unit tests can be implemented utilizing Barricade.

##Installing MMBarricade
The easiest way to install MMBarricade is with CocoaPods:

pod 'MMBarricade', '~> 1.0.0'

Overview

Barricade's functionality is based around four primary classes: MMBarricade, MMBarricadeResponse, MMBarricadeResponseSet and <MMBarricadeResponseStore>.

MMBarricade

MMBarricade is a NSURLProtocol subclass and is the primary class to use when interacting with barricade.

MMBarricadeResponse

An instance of MMBarricadeResponse defines a single response to an HTTP request. For example, a response might consist of an HTTP status code of 200, a content-type of "application/json" and a JSON object for the response data.

MMBarricadeResponseSet

An instance of MMBarricadeResponseSet represents a collection of possible responses for a single request. For example, a response set for the /login API endpoint might be a set of three responses representing Success, Invalid Credentials and Server Error.

MMBarricadeResponseStore

A response store conforms to <MMBarricadeResponseStore> and is responsible for managing the selection of which response should be returned for a network request out of the set of possible responses. This selection can be modified programmatically, or through the Tweaks UI (as seen in the gif above).

Quick Start

First, import the library header file. If using Tweaks to manage user selections, import the Tweaks category to get access to the convenience initializer.

#import "MMBarricade.h"

Next, give the barricade a response store and enable it. Once enabled, the barricade will begin responding to network requests.

// Setup the barricade. This only needs to be done once.
[MMBarricade setupWithInMemoryResponseStore];
[MMBarricade enable];

In this example, we'll setup the barricade to be able to respond to the /login API endpoint with one of three possible responses. The "name" parameters for the response set and each individual response are user-facing strings used to identify the request and responses to the developer. They are displayed in the Tweaks UI, and can be used to programmatically udpate the selected response as well.

In this example, the response files are JSON-formatted text files stored on disk in a subdirectory of the app bundle named "LocalServer". There are no naming conventions that must be followed for file names.

// Create a response set for each API call that should be barricaded.
MMBarricadeResponseSet *responseSet = [MMBarricadeResponseSet responseSetForRequestName:@"Login" respondsToRequest:^BOOL(NSURLRequest *request, NSURLComponents *components) {
   return [components.path hasSuffix:@"/login"];
}];
    
// Add Successful response
[responseSet addResponseWithName:@"Success"
                           file:MMPathForFileInMainBundleDirectory(@"login.success.json", @"LocalServer")
                     statusCode:200
                    contentType:@"application/json"];
    
// Add Invalid Credentials response
[responseSet addResponseWithName:@"Invalid Credentials"
                           file:MMPathForFileInMainBundleDirectory(@"login.invalid.json", @"LocalServer")
                     statusCode:401
                    contentType:@"application/json"];

// Add No Network Connection response
[responseSet addResponseWithName:@"Offline"
                          error:[NSError errorWithDomain:NSURLErrorDomain
                                                    code:NSURLErrorNotConnectedToInternet
                                                userInfo:nil]];
    
// Register the response set
[MMBarricade registerResponseSet:responseSet];

By default, the first response added to a response set will be used to respond to the request. However, the selected response can be modified through the Tweaks interface or programmatically. In either case, the "name" parameters specified when creating the responses are used to identify the desired response.

[MMBarricade selectResponseForRequest:@"Login" withName:@"Offline"];

Selection Interface

Barricade comes with an in-app interface that can be presented to allow selection of network responses at runtime.

Example App

There are two approaches you can take for presenting the selection UI:

  • Automatically present the interface when the device is shaken. To do this, just replace your UIWindow with an instance of an MMBarricadeShakeWindow. If you're using storyboards, override - window in your app delegate:
- (UIWindow *)window {
    if (!_window) {
        _window = [[MMBarricadeShakeWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    }    
    return _window;
}

Note: By default the shake window is presented for Debug builds only. You can override the MMBARRICADE_SHAKE_ENABLED macro to adjust this behavior.

  • Manually present a MMBarricadeViewController at any time in your app, just be sure to limit the presetation to debug builds if you don't want it to ship to the App Store.

Tweaks

If you are using Facebook Tweaks in your app, you can use the Tweaks subspec of Barricade to integrate the in-app selection interface inside of Tweaks.

pod 'MMBarricade/Tweaks', '~> 1.0.0'

The only other change you need to make is to setup the barricade using a tweaks response store rather than the in-memory response store:

#import "MMBarricade+Tweaks.h"
...
[MMBarricade setupWithTweaksResponseStore];
[MMBarricade enable];

App Store Submission

MMBarricade is safe to include with App Store builds (and could be used to support things like a demo mode for your app), but most of the time you will probably want to ensure that the barricade is disabled for App Store builds. Here are a couple of approaches:

Conditionally enable

In your app, you can wrap the creation of the barricade inside a macro to limit the code execution to particular build configurations. For example:

#if DEBUG
[MMBarricade enable];
#endif

Disable through CocoaPods

When installing through CocoaPods, you can specify particular build configurations to limit the installation of the library. For example:

pod 'MMBarricade', '~> 1.0.0', :configurations => ['Debug']

Or, if you are only utilizing the library for unit tests, you may want to link the library with only your testing target:

target 'Tests', :exclusive => true do
  pod 'MMBarricade', '~> 1.0.0'
end

Advanced Configuration

Configuration consists of two steps:

  1. Setup a response store
  2. Enable the barricade

The barricade must be configured with an instance of an <MMBarricadeResponseStore> before it can be used. To use one of the included response stores, you can:

[MMBarricade setupWithTweaksResponseStore];
-or-
[MMBarricade setupWithInMemoryResponseStore];

Once the backing store for the barricade is setup, it should be enabled. Because the barricade works as a NSURLProtocol subclass, the way to enable it differs depending on how you will be making network requests in your app.

NSURLConnection

For networking based on the older networking style of NSURLConnection-based requests, simply calling [MMBarricade enable] will register the NSURLProtocol for you.

NSURLSession

For networking based on the newer NSURLSession-based APIs, you have two options:

If you are using [NSURLSession sharedSession], then you can enable with [MMBarricade enable].

If you are creating a custom session, for example [NSURLSession sessionWithConfiguration:configuration], then you should enable the barricade with your custom session configuration before creating the session.

NSURLSessionConfiguration *configuration = [self myCustomSessionConfiguration];
[MMBarricade enableForSessionConfiguration:configuration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration];
...

Changing the response

The response that will be returned by the barricade when a request is made is the "current response" that has been selected in the MMBarricadeResponseSet for the request. In addition to updating the current response through the tweaks UI, the response can also be updated programmatically:

[MMBarricade selectResponseForRequest:@"login" withName:@"offline"];

Requirements

MMBarricade requires iOS 7.0 or higher.

Credits

MMBarricade was created by John McIntosh at Mutual Mobile.

Credit also to Justin Kolb for pioneering the concept of run-time adjustable network responses and Conrad Stoll for feedback.

License

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

You might also like...
Declarative, configurable & highly reusable UI development as making Lego bricks.
Declarative, configurable & highly reusable UI development as making Lego bricks.

LeeGo is a lightweight Swift framework that helps you decouple & modularise your UI component into small pieces of LEGO style's bricks, to make UI dev

A fancy logger yet lightweight, and configurable. 🖨
A fancy logger yet lightweight, and configurable. 🖨

📣 📣 Important: Printer can only print console logs if you're running an app in the Simulator. If you're running in a real device it will not print a

SwiftUI Package for Configurable Confetti Animation 🎉
SwiftUI Package for Configurable Confetti Animation 🎉

🎊 ConfettiSwiftUI 🎊 Swift package for displaying configurable confetti animation. Find the demo project here. Installation: It requires iOS 14 and X

Custom & highly configurable seek slider with sliding intervals, disabled state and every possible setting to tackle!
Custom & highly configurable seek slider with sliding intervals, disabled state and every possible setting to tackle!

iLabeledSeekSlider Custom & highly configurable seek slider with sliding intervals, disabled state and every possible setting to tackle! Minimum iOS v

A Swift Recreation of Attach-Detach, with some configurable options

Attach-Detach-Sw A Swift Recreation of Attach-Detach, with some configurable options Usage To use, you'll need to specify if you are attaching or deta

A Swift Recreation of Attach-Detach, with some configurable options

Attach-Detach-Sw A Swift Recreation of Attach-Detach, with some configurable options Usage To use, you'll need to specify if you are attaching or deta

Configurable morphing transitions between text values of a label.
Configurable morphing transitions between text values of a label.

TOMSMorphingLabel Configurable morphing transitions between text values of a label. Triggering the animation is as easy as setting the labels text pro

A simple and configurable rating/favorite view.

ImageRating A simple and configurable rating/favorite view. ImageRating will display a sequence of SFSymbols from 0-maxImages in half or whole increme

A highly configurable and out-of-the-box-pretty UI library
A highly configurable and out-of-the-box-pretty UI library

We absolutely love beautiful interfaces! As an organization named Unicorn, we are obligated to be unique and majestic.

Card Decks is a small utility application for your iPhone, iPod touch and iPad which brings you simple, configurable, colored, multi-line text cards that are grouped into card decks

Card Decks is a small utility application for your iPhone, iPod touch and iPad which brings you simple, configurable, colored, multi-line text cards that are grouped into card decks.

Configurable animated onboarding screen written programmatically in Swift for UIKit
Configurable animated onboarding screen written programmatically in Swift for UIKit

Configurable animated onboarding screen written programmatically in Swift for UIKit – inspired by many Apple-designed user interfaces in iOS – with Insignia as an example.

GLWalkthrough is an easily configurable plug-and-play tool to add walkthrough or coachmarker functionality to your app with ease.
GLWalkthrough is an easily configurable plug-and-play tool to add walkthrough or coachmarker functionality to your app with ease.

GLWalkthrough Example To run the example project, clone the repo, and run pod install from the Example directory first. Requirements Installation GLWa

iOS library to help detecting retain cycles in runtime.

FBRetainCycleDetector An iOS library that finds retain cycles using runtime analysis. About Retain cycles are one of the most common ways of creating

JSPatch bridge Objective-C and Javascript using the Objective-C runtime. You can call any Objective-C class and method in JavaScript by just including a small engine. JSPatch is generally used to hotfix iOS App.

JSPatch 中文介绍 | 文档 | JSPatch平台 请大家不要自行接入 JSPatch,统一接入 JSPatch 平台,让热修复在一个安全和可控的环境下使用。原因详见 这里 JSPatch bridges Objective-C and JavaScript using the Object

All new design. Inspect your iOS application at runtime.
All new design. Inspect your iOS application at runtime.

Peek: All new design Peek 5 with an all new design and all new features. Whether you're a developer, designer or QA/tester, Peek can help you at all s

A GUI for dynamically creating NSPredicates at runtime to query data in your iOS app.
A GUI for dynamically creating NSPredicates at runtime to query data in your iOS app.

PredicateEditor PredicateEditor is a visual editor for creating and using NSPredicates for querying data in your app. PredicateEditor was inspired by

Grapefruit: Runtime Application Instruments for iOS
Grapefruit: Runtime Application Instruments for iOS

Grapefruit: Runtime Application Instruments for iOS Get Started Dependencies Grapefruit requires Node.js to be installed. If you can't install the fri

GCDWebServer is a modern and lightweight GCD based HTTP 1.1 server designed to be embedded in iOS, macOS & tvOS apps.

GCDWebServer is a modern and lightweight GCD based HTTP 1.1 server designed to be embedded in iOS, macOS & tvOS apps. It was written from scr

Server-driven SwiftUI - Maintain iOS apps without making app releases.

ServerDrivenSwiftUI Maintain ios apps without making app releases. Deploy changes to the server and users will receive changes within minutes. This pa

Comments
  • Barricade not working in iOS 9

    Barricade not working in iOS 9

    Enabling the barricade using the enableForSessionConfiguration: API is not working in iOS 9. The NSURLProtocol methods (canInitWithRequest, startLoading, etc) are not called by the operating system.

    I don't know if this is an iOS9 bug, but it's something worth to look at

    opened by piercifani 8
  • How can I enable MMBarricade for `AFHTTPSessionManager` in AFNetworking ?

    How can I enable MMBarricade for `AFHTTPSessionManager` in AFNetworking ?

    AFHTTPSessionManager is a subclass of AFURLSessionManager with convenience methods for making HTTP requests.

    It seems we can't get NSURLSessionConfiguration before creating the session.

    opened by zhugexiaobo 3
  • Issue: Every time the app starts the fbvalue is reset to the defaul va…

    Issue: Every time the app starts the fbvalue is reset to the defaul va…

    …lue.

    Cause: Creating a new instance of FBTweak and setting the current value to nil resets the UserDefaults value. FBTweak gets instantiated with an identifier which is therefore used as a key to get the value for UserDefaulst store so there is no need to set the current value to nil when instantiating a new FBTweak

    opened by monishsyed 1
Owner
Mutual Mobile
We build breakthrough products in partnership with the world's leading companies.
Mutual Mobile
Swift-compute-runtime - Swift runtime for Fastly Compute@Edge

swift-compute-runtime Swift runtime for Fastly Compute@Edge Getting Started Crea

Andrew Barba 57 Dec 24, 2022
Swift Server Implementation - RESTful APIs, AWS Lambda Serverless For Swift Runtime amazonlinux: AWS Lambda + API Gateway

Swift Server Implementation - RESTful APIs, AWS Lambda Serverless For Swift Runtime amazonlinux: AWS Lambda + API Gateway deployed on Graviton arm64 build swift:5.6.2-amazonlinux2-docker image

Furqan 2 Aug 16, 2022
Appfiguratesdk - Appfigurate provides the ability to change configuration properties in iOS and watchOS, apps and app extensions, securely, at runtime.

Appfigurate™ Appfigurate provides the ability to change configuration properties in iOS and watchOS, apps and app extensions, securely, at runtime. Do

Electric Bolt 21 Dec 14, 2022
Web server serving local files

swift-web A web server serving local static files. Installation Using Mint The easiest way to install swift-web is via mint. mint install adam-fowler/

Adam Fowler 10 Dec 10, 2022
Full configurable spreadsheet view user interfaces for iOS applications. With this framework, you can easily create complex layouts like schedule, gantt chart or timetable as if you are using Excel.

kishikawakatsumi/SpreadsheetView has moved! It is being actively maintained at bannzai/SpreadsheetView. This fork was created when the project was mov

Kishikawa Katsumi 34 Sep 26, 2022
TraceLog is a highly configurable, flexible, portable, and simple to use debug logging system for Swift and Objective-C applications running on Linux, macOS, iOS, watchOS, and tvOS.

Please star this github repository to stay up to date. TraceLog Introduction TraceLog is a highly configurable, flexible, portable, and simple to use

Tony Stone 52 Oct 28, 2022
It is a highly configurable iOS library which allows easy styling with built in styles as well as extra header and footer views so that you can make extremely unique alerts and action sheets.

 CFAlertViewController CFAlertViewController is a library that helps you display and customise Alerts, Action Sheets, and Notifications on iPad and i

Crowdfire Inc. 1.1k Dec 18, 2022
Highly configurable iOS Alert Views with custom content views

NYAlertViewController NYAlertViewController is a replacement for UIAlertController/UIAlertView with support for content views and UI customization. Fe

Nealon Young 609 Nov 20, 2022
A configurable api client based on Alamofire4 and RxSwift4 for iOS

SimpleApiClient A configurable api client based on Alamofire4 and RxSwift4 for iOS Requirements iOS 8.0+ Swift 4 Table of Contents Basic Usage Unwrap

Jay 67 Dec 7, 2020
Full configurable spreadsheet view user interfaces for iOS applications. With this framework, you can easily create complex layouts like schedule, gantt chart or timetable as if you are using Excel.

kishikawakatsumi/SpreadsheetView has moved! It is being actively maintained at bannzai/SpreadsheetView. This fork was created when the project was mov

Kishikawa Katsumi 34 Sep 26, 2022