An easy way to fine-tune, and adjust parameters for iOS apps in development.

Related tags

Tools Tweaks
Overview

Tweaks

Tweaks is an easy way to fine-tune an iOS app. Build Status

Tweaks

Why

The best way to improve an app is to use it every day. Even when ideas can be tested out in advance — for example, with Origami — it can still take some time with the app to see how it works in practice.

Occasionally, it's perfect the first try. Sometimes, the idea doesn't work at all. But often, it just needs a few minor adjustments. That last case is where Tweaks fits in. Tweaks makes those small adjustments easy: with no code changes and no computer, you can try out different options and decide which works best.

Some of the most useful parameters to adjust are animation timings, velocity thresholds, colors, and physics constants. At Facebook, we also use tweaks to temporarily disable new features during development. That way, the designers and engineers involved can enable it on just their devices, without getting in the way of others testing the app.

Tweaks was invaluable for building Paper. We hope it can be useful for your app too.

Usage

Each configurable value is called a tweak. There's a few ways to set them up, found in FBTweakInline.h.

Value

The simplest way to create a tweak is to replace a constant with FBTweakValue:

CGFloat animationDuration = FBTweakValue(@"Category", @"Group", @"Duration", 0.5);

The first three parameters are where the tweak is listed and what it's called, and the last one is the default value. You can pass in many types of values for the default: booleans, numbers, or strings.

if (FBTweakValue(@"Category", @"Feature", @"Enabled", YES)) {
  label.text = FBTweakValue(@"Category", @"Group", @"Text", @"Tweaks example.");
}

In release builds, the FBTweakValue macro expands to just the default value, so there's no performance impact. In debug builds, though, it fetches the latest value of the tweak.

You can also pass a fifth parameter, which will constrain the possible values for a tweak. The fifth parameter can be an array, dictionary, or an FBTweakNumericRange. If it's a dictionary, the values should be strings to show in the list of choices. Arrays will show the values' description as choices. (Note that you have to surround array and dictionary literals with an extra set of parentheses.)

self.initialMode = FBTweakValue(@"Header", @"Initial", @"Mode", @(FBSimpleMode), (@{ @(FBSimpleMode) : @"Simple", @(FBAdvancedMode) : @"Advanced" }));

For numeric tweaks (NSInteger, CGFloat, and others), you can instead pass two parameters, which constrain the value to a FBTweakNumericRange:

self.red = FBTweakValue(@"Header", @"Colors", @"Red", 0.5, 0.0, 1.0);

Bind

To make tweaks update live, you can use FBTweakBind:

FBTweakBind(self.headerView, alpha, @"Main Screen", @"Header", @"Alpha", 0.85);

The first parameter is the object to bind to, and the second is the property. Whenever the tweak is changed, self.headerView's alpha property is updated to match. A few more examples:

FBTweakBind(audioPlayer, volume, @"Player", @"Audio", @"Volume", 0.9);
FBTweakBind(webView.scrollView, scrollEnabled, @"Browser", @"Scrolling", @"Enabled", YES);

As with FBTweakValue, in release builds FBTweakBind expands to just setting the property to the default value.

Action

Actions let you run a (global) block when a tweak is selected. To make one, use FBTweakAction:

FBTweakAction(@"Player", @"Audio", @"Volume", ^{
  NSLog(@"Action selected.");
});

The first three parameters are the standard tweak listing information, and the last is a block to call. You can use FBTweakAction in any scope, but the block must be global: it can't depend on any local or instance variables (it wouldn't know which object to adjust).

Actions are useful for things like launching debug UIs, checking for updates, or (if you make one that intentionally crashes) testing crash reporting.

Tweaks UI

To configure your tweaks, you need a way to show the configuration UI. There's two options for that:

  • Traditionally, tweaks is activated by shaking your phone. To use that, just replace your root UIWindow with a FBTweakShakeWindow. If you're using Storyboards, you can override -window on your app delegate:
- (UIWindow *)window
{
  if (!_window) {
    _window = [[FBTweakShakeWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
  }

  return _window;
}
  • You can present a FBTweakViewController from anywhere in your app. Be sure to restrict the activation UI to debug builds!
- (void)showTweaks {
   FBTweakViewController *tweakVC = [[FBTweakViewController alloc] initWithStore:[FBTweakStore sharedInstance]];
   tweakVC.tweaksDelegate = self;
   // Assuming this is in the app delegate
   [self.window.rootViewController presentViewController:tweakVC animated:YES completion:nil];
}

- (void)tweakViewControllerPressedDone:(FBTweakViewController *)tweakViewController {
   [tweakViewController dismissViewControllerAnimated:YES completion:NULL];
}

Tweaks UI Dismiss Notification

Alternatively, when the Tweaks UI is dismissed, you can register your notification center to listen to FBTweakShakeViewControllerDidDismissNotification, which can be used after importing FBTweakViewController.h

Advanced

You can also access the objects that make up the macros mentioned above. That can be useful for more complex scenarios, like adjusting members of a C structure.

For example, to manually create a tweak:

FBTweak *tweak = [[FBTweak alloc] initWithIdentifier:@"com.tweaks.example.advanced"];
tweak.name = @"Advanced Settings";
tweak.defaultValue = @NO;

FBTweakStore *store = [FBTweakStore sharedInstance];
FBTweakCategory *category = [[FBTweakCategory alloc] initWithName:@"Settings"];
[store addTweakCategory:category];
FBTweakCollection *collection = [[FBTweakCollection alloc] initWithName:@"Enable"];
[category addTweakCollection:collection];
[collection addTweak:tweak];

[tweak addObserver:self];

Then, you can watch for when the tweak changes:

- (void)tweakDidChange:(FBTweak *)tweak
{
  self.advancedSettingsEnabled = ![tweak.currentValue boolValue];
}

Also you have de ability to implement the optional method tweakWillChange: in order to handle the previous value of your tweak:

- (void)tweakWillChange:(FBTweak *)tweak
{
  NSLog(@"%@", tweak.currentValue); // Here current value is the previous value of the tweak
}

To override when tweaks are enabled, you can define the FB_TWEAK_ENABLED macro. It's suggested to avoid including them when submitting to the App Store.

Using from a Swift Project

Khan Academy's project SwiftTweaks is designed for Swift, and might be a better choice for Swift projects.

Tweaks can be used from Swift projects. In this case the handy shortcut macros defined in FBTweakInline.h are not available, meaning tweaks need to be created programmatically, similar to this example:

let tweak = FBTweak(identifier: "com.tweaks.example.advanced")
tweak.name = "Advanced settings"
tweak.defaultValue = false

let collection = FBTweakCollection(name: "Enable");
collection.addTweak(tweak)
        
let category = FBTweakCategory(name: "Settings")
category.addTweakCollection(collection);
        
let store = FBTweakStore.sharedInstance()
store.addTweakCategory(category)

tweak.addObserver(self)

After setting up a tweak you can watch for when it changes:

func tweakDidChange(tweak: FBTweak!)
{
    self.advancedSettingsEnabled = tweak.currentValue as Bool;
}

How it works

In debug builds, the tweak macros use __attribute__((section)) to statically store data about each tweak in the __FBTweak section of the mach-o. Tweaks loads that data at startup and loads the latest values from NSUserDefaults.

In release builds, the macros just expand to the default value. Nothing extra is included in the binary.

Installation

There are two options:

  1. Tweaks is available as Tweaks in CocoaPods. (If you have issues with custom Xcode configurations, this comment might help.)
  2. Manually add the files from FBTweak/ into your Xcode project. Slightly simpler, but updates are also manual.

Tweaks requires iOS 6 or later.

There's also a demo project available. To use it, make sure to open FBTweakExample.xcworkspace (rather than the .xcodeproj) so the dependencies build correctly.

Contributing

See the CONTRIBUTING file for how to help out.

License

Tweaks is BSD-licensed. We also provide an additional patent grant.

Comments
  • Add an example for showing/dismissing the FBTweakViewController manually

    Add an example for showing/dismissing the FBTweakViewController manually

    Adds this missing example to the README. (I was inspired to add this after a lot of confusion setting the delegate instead of tweaksDelegate!)

    • You can present a FBTweakViewController from anywhere in your app. Be sure to restrict the activation UI to debug builds!
    - (void) showTweaks {
       FBTweakViewController *tweakVC = [[FBTweakViewController alloc] initWithStore:[FBTweakStore sharedInstance]];
       tweakVC.tweaksDelegate = self;
       [[[[UIApplication sharedApplication] keyWindow] rootViewController] presentViewController:tweakVC animated:YES completion:nil];
    }
    
    - (void) tweakViewControllerPressedDone:(FBTweakViewController *)tweakViewController {
       [tweakViewController dismissViewControllerAnimated:YES completion:NULL];
    }
    CLA Signed 
    opened by warpling 12
  • Cocoapods Link Error: __FBTweakIdentifier (with custom build configuration)

    Cocoapods Link Error: __FBTweakIdentifier (with custom build configuration)

    Trying to get set up with Tweaks, added the pod to my podfile:

    pod 'Tweaks'

    Got the FBTweakShakeWindow integrated and displaying 0 items (as expected), went to add my first tweak as such:

    self.alpha = FBTweakValue(@"Category", @"Thing", @"Alpha", .6, 0.1, 1.0);

    When I went to build I got a Linker Error:

    Undefined symbols for architecture i386: "__FBTweakIdentifier"

    I see the externs defined in FBTweakInline.m and FBTweakinlineInternal.h, but I can't get this resolved.

    Any suggestions on what I might have missed or what the problem might be?

    Many thanks.

    opened by LeffelMania 10
  • Bump version

    Bump version

    Looks like the latest tag, 2.0.0, is ~10 months old. Might be worth bumping the version number so people can easily get the latest fixes (such as #85 which fixes framework support) via Cocoapods without having to reference the git repo like this:

    pod 'Tweaks', :git => 'https://github.com/facebook/Tweaks.git',
    
    opened by johnboiles 9
  • Dictionary and array support

    Dictionary and array support

    This PR adds support for dictionaries and arrays to Tweaks. The idea for how to go about the implementation came from PR #46 and is similar to #64 which I just came across while posting. We've been using this successfully in a production app so hopefully there shouldn't any bugs, but let me know if you see anything and I'll be happy to address it. Also, this will hopefully take case of issue #22.

    The implementation adds the ability to tap on a dictionary or array tweak in the Tweaks UI, and present a drill-down list of values to choose from.

    For array tweaks, the values are displayed by calling description of each item in the array. Therefore the items don't have to be string values and can be chosen based on their description.

    For dictionary tweaks, the dictionary's keys are displayed in the Tweaks UI and the values are never shown. It is expected that the keys will be strings.

    Here's a screenshot of the addition to the sample app showing these two in use. "Rotation (radians)" is an example of an array tweak, and "Color" is an example of a dictionary tweak. (EDIT: Updated screenshot to reflect using UITableViewCellAccessoryDisclosureIndicator) screen shot 2015-01-24 at 1 53 17 pm

    Each item in the array (shown below) does not have to be a string value. In this example, the array items are instances of NSNumber and the value presented in the UI is the output of -[NSNumber description] screen shot 2015-01-24 at 12 40 43 pm

    Each item in the dictionary (shown below) has a string key that is displayed in the UI. In this example, there are UIColor instances associated with each of the string keys. screen shot 2015-01-24 at 12 41 53 pm

    opened by johntmcintosh 9
  • Updating documentation on using Tweaks from Swift

    Updating documentation on using Tweaks from Swift

    Updated the documentation with details on how to use the project from Swift.

    Main things included:

    • Noting how the macros cannot be used in Swift
    • Example code on creating tweaks programmatically (following the same example as listed in the Advanced section)
    CLA Signed 
    opened by gergelyorosz 8
  • Emit error when trying to compile for C++ (use of _Generic())

    Emit error when trying to compile for C++ (use of _Generic())

    Resolves https://github.com/facebook/Tweaks/issues/84

    It would seem that Tweaks can't compile for C++ due to implementing _FBTweakValueInternal() with _Generic(). In lieu of creating a C++ compatible implementation, perhaps it would be better to instead provide a clear error, with the suggestion to expose Tweaks values to C++ from ObjC/C methods defined elsewhere?

    Please let me know what you think. Thanks!

    CLA Signed 
    opened by itsthejb 7
  • Fix header search paths while archiving

    Fix header search paths while archiving

    There's a portion of Apple's "Using Static Libraries in iOS" guide that describes this problem with the "Headers" build phase when using static libraries (emphasis added):

    Your library will have one or more header files that clients of that library need to import. To configure which headers are exported to clients, select your library project to open the project editor, select the library target to open the target editor, and select the build phases tab. If your library target has a “Copy Headers” build phase, you should delete it; copy headers build phases do not work correctly with static library targets when performing the “Archive” action in Xcode.

    When trying to integrate Tweaks into our workspace, we found the same issue: archiving our app was broken.

    We've updated FBTweak.xcodeproj to use a custom "Copy Files" build phase that places the public headers into include/FBTweak/, relative to the built products directory. This location is automatically added to the header search paths by Xcode, and thus it is no longer necessary to add $(SYMROOT)/Headers to the header search paths when building Tweaks from a workspace.

    To test this, we've updated .travis.yml to perform an archive action in addition to running the tests.

    CLA Signed 
    opened by sharplet 6
  • Multiple values (e.g. arrays)

    Multiple values (e.g. arrays)

    Has anyone considered the ability to set more than one value for a tweak?

    Edit: My original question was about setting more than one value at a time, like a multi-select chooser. Could have been worded more clearly.

    For example, if you wanted to be able to select multiple NS_OPTIONS values from a list, then you could write code to "or" them together.

    opened by peterjenkins 6
  • FBTweakBind lazily initialized objects

    FBTweakBind lazily initialized objects

    In my app, I extend NSParargraphStyle with my own custom style that I make accessible through a lazily instantiated property.

    static NSMutableParagraphStyle *style;
    
    @implementation NSParagraphStyle (Styling)
    
    + (instancetype)abc_authoringParagraphStyle {
        if (style == nil) {
            style = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
            FBTweakBind(style, paragraphSpacing, ABCAuthoringModeTweakName, ABCAuthoringModeTextTweakName, @"Paragraph Spacing", 20.f, 0.f, 50.f);
        }
        return style;
    }
    
    @end
    

    I try to use tweak bind such that value updates are set directly on the underlying object. However, I get a EXC_i386_IVOP exception.

    opened by fatuhoku 6
  • Network Tweaks

    Network Tweaks

    Right now it is a bit clumsy to have to open the Tweaks UI from inside of the app, make changes, and then close the UI to see them - so I created a Mac app that pairs with Tweaks in order to make changes from your desktop and have them take effect on the device over the network.

    Is this something you would be interested in integrating?

    Below are just some screenshots of a fully functional prototype that is paired with the test Tweaks project.

    tweaks tweaks-2

    opened by Noeski 6
  • Fix FBTweakActions being called multiple times or on appearance.

    Fix FBTweakActions being called multiple times or on appearance.

    Moved FBTweakAction block execution from _FBTweakTableViewCell's setSelected: to _FBTweakCollectionViewController's didSelectRowAtIndexPath:.

    setSelected: is a poor choice as it's intended for UI updates, and UITableView calls setSelected: multiple times and when the cell is being reused.

    This fixes #55 and #83 .

    CLA Signed 
    opened by rayray 5
  • Set autocapitalization based on the first letter of default value

    Set autocapitalization based on the first letter of default value

    Currently all text fields have autocapitalizationType set to default which is UITextAutocapitalizationTypeSentences. It's a bit annoying if someone wants to have first letter lowercase. One has to type something like 'Vvalue' and remove 'V'. The idea is to set autocapitalizationType based on the first letter of the value. If it's lowercase then we set UITextAutocapitalizationTypeNone, otherwise we keep current behaviour - UITextAutocapitalizationTypeSentences.

    | BEFORE | AFTER | | ------------- |:-------------:| | before | after |

    CLA Signed 
    opened by krzysztofpawski 3
  • how to create FBTweakAction without using macro

    how to create FBTweakAction without using macro

    Hi, I am trying to add tweaks in swift, so cant use macros. I am able to add text and switch type tweaks but not able to add action. Although in swift, there are more option with SwiftTweaks, I dont want to add another pod. This is how I am trying, can somebody please tell what I am doing wrong?

    let tweak = FBTweak(identifier: key)
    tweak.name = key
    tweak.defaultValue = {
                            debugPrint("hello value")            
      UIApplication.topViewController()?.navigationController?.pushViewController(AnalyticsLogTableViewController(), animated: true)
                        }
    
    opened by vishundayal 0
  • iOS 11 - motionBegan not being called on FBTweakShakeWindow

    iOS 11 - motionBegan not being called on FBTweakShakeWindow

    After upgrading iOS to Beta 11 (15A5328g), the - (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event method on FBTweakShakeWindow is never called.

    opened by joelmarquez90 2
  • Allowed shake enablement for simulator too.

    Allowed shake enablement for simulator too.

    Allow the shake to be disabled in the simulator too.

    This is useful especially if you want to show the React Native Developer menu in the simulator with a shake gesture while also using Tweaks.

    _shakeEnabled is already defaulted to YES.

    CLA Signed 
    opened by manhluong 3
Owner
Meta Archive
These projects have been archived and are generally unsupported, but are still available to view and use
Meta Archive
AVXCAssets Generator takes path for your assets images and creates appiconset and imageset for you in just one click

AVXCAssets Generator Often while developing an app, We ran into a condition when we need to scale images to each and every aspect ratios for icons and

Angel Vasa 339 Dec 6, 2022
Swift CLI for strong-typing images, colors, storyboards, fonts and localizations

Shark Shark is a Swift command line tool that generates type safe enums for your images, colors, storyboards, fonts and localizations. Because Shark r

Kaan Dedeoglu 377 Dec 1, 2022
Strong typed, autocompleted resources like images, fonts and segues in Swift projects

R.swift Get strong typed, autocompleted resources like images, fonts and segues in Swift projects Why use this? It makes your code that uses resources

Mathijs Kadijk 8.9k Jan 6, 2023
Xcode storyboards diff and merge tool.

StoryboardMerge Storyboard diff and merge tool which: compares and merges two storyboard files, provides an automatic merge-facility, The storyboardin

null 238 Sep 12, 2022
swiftenv allows you to easily install, and switch between multiple versions of Swift.

Swift Version Manager swiftenv allows you to easily install, and switch between multiple versions of Swift. This project was heavily inspired by pyenv

Kyle Fuller 1.9k Dec 27, 2022
An adorable little framework and command line tool for interacting with SourceKit.

SourceKitten An adorable little framework and command line tool for interacting with SourceKit. SourceKitten links and communicates with sourcekitd.fr

JP Simard 2.1k Jan 5, 2023
Command line program that detects unused resource strings in an iOS or OS X application.

Abandoned Resource String Detection This command line program detects unused resource strings in an iOS or OS X application. Updated to Swift 3, thank

Josh Smith 360 Nov 26, 2022
Shows your current framerate (fps) in the status bar of your iOS app

WatchdogInspector Shows your current framerate (fps) in the status bar of your iOS app Be a good citizen! Don't block your main thread! WatchdogInspec

Christian Menschel 510 Nov 24, 2022
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

Shaps 2.6k Dec 17, 2022
An iOS app decrypter, full static using fouldecrypt.

Iridium An iOS app decrypter, full static using fouldecrypt. Supporting iOS 13+ Note We have built everything into the package, you can install and fl

Lakr Aream 234 Jan 9, 2023
An iOS app decrypter, full static using fouldecrypt.

Iridium An iOS app decrypter, full static using fouldecrypt. Supporting iOS 13+ Note We have built everything into the package, you can install and fl

Lakr Aream 226 Dec 24, 2022
An autolayout library for the damn fine citizens of San Diego.

Anchorman Do you think autolayout has to be hard? Nah. NSLayoutAnchor is pretty neat! But it's still a bit tedious of an API. Try writing .translatesA

Joe Fabisevich 79 May 25, 2022
UILabel replacement with fine-grain appear/disappear animation

ZCAnimatedLabel UILabel-like view with easy to extend appear/disappear animation Features Rich text support (with NSAttributedString) Group aniamtion

Chen 2.3k Dec 5, 2022
The first non-jailbroken iOS (and macOS) application to adjust the screen temperature, brightness, and color!

GoodNight Project name thanks to @Emu4iOS. Based off of Thomas Finch's GammaThingy. GoodNight is an app that allows you to directly access the screen'

Anthony Agatiello 558 Nov 3, 2022
Adjust the volume from the command line on macOS.

volume Adjust the volume from the command line on macOS. Installation Using Mint: mint install meowmeowmeowcat/[email protected] Usage USAGE: volume <numb

meowmeowcat 3 Sep 28, 2022
iOS routing done right. Handles both URL recognition and controller displaying with parsed parameters. All in one line, controller stack preserved automatically!

Developed and Maintained by Ipodishima Founder & CTO at Wasappli Inc. (If you need to develop an app, get in touch with our team!) So what is this lib

null 589 Dec 24, 2022
A powerful Circular Slider. It's written in Swift, it's 100% IBDesignable and all parameters are IBInspectable.

CircularSlider A powerful Circular Slider. It's written in Swift, it's 100% IBDesignable and all parameters are IBInspectable. Demo Installation Circu

Matteo Tagliafico 253 Sep 19, 2022
🔻 Dropdown Menu for iOS with many customizable parameters to suit any needs

MKDropdownMenu Dropdown Menu for iOS with many customizable parameters to suit any needs. Inspired by UIPickerView. Installation CocoaPods MKDropdownM

Max Konovalov 531 Dec 26, 2022
ParametersCloneSwiftUI - Parameters of iOS in iPhone

ParametersCloneSwiftUI Made by myself during the week-end, only made for light m

Harry Knight 0 Jan 28, 2022
Menubar app to remove link tracking parameters automatically

TrackerZapper Website and more info TrackerZapper is a Mac app that sits in your menubar and silently removes tracking parameters from any links you c

Robb Knight 280 Jan 2, 2023