HBPreferences

Objective-C

@interface HBPreferences : NSObject

Swift

class HBPreferences : NSObject

The HBPreferences class in Cephei provides an interface for managing user-defined preferences of a tweak, and the default values used when the user has not yet changed a value.

HBPreferences is very similar to NSUserDefaults, however it is specifically tailored to iOS tweak development, since tweaks may be loaded into a sandboxed process (most obviously, App Store apps, but also system apps like Safari), or one that runs as the root user (for instance, iFile, although these apps are slowly changing their model so they now run as mobile). In both of these cases, using NSUserDefaults will result in reading from preferences inside the sandbox, or inside root’s home directory; both of which are not what is expected.

Advantages HBPreferences has over NSUserDefaults are:

  • Directly reading the property list from the mobile user’s home directory, to support sandboxed apps and apps running as root.
  • Intuitive method of setting a default preference value.
  • Updating of the app/tweak’s variables when preferences are changed.
  • Keyed subscripting is allowed, which enables simple array syntax.
  • Values in the preferences plist are called preferences, not defaults, to avoid ambiguity - NSUserDefaults uses “defaults” to refer to both preferences themselves and the fallback values if a key doesn’t exist.

Ensure you read the discussion for -registerObject:default:forKey: before using the automatic updating mechanism. -objectForKey: does not update as another process updates the preferences on iOS 7 or older; if you need to support older iOS versions, use the registration methods instead.

As of Cephei 1.17, HBPreferences supports Key-Value Observation. As such, you may subscribe to changes made to preferences through observer callbacks. The -registerPreferenceChangeBlock: and -registerPreferenceChangeBlockForKey:block: methods are provided to subscribe to preference changes via a callback block since Cephei 1.3, and you can additionally observe HBPreferencesDidChangeNotification.

Example usage

In Objective-C/Logos:

HBPreferences *preferences;
BOOL doThing;

%ctor {
    preferences = [[HBPreferences alloc] initWithIdentifier:@"ws.hbang.common.demo"];
    [preferences registerDefaults:@{
        @"Enabled": @YES,
        @"AnotherSetting": @1.f
    }];

    [preferences registerBool:&doThing default:NO forKey:@"DoThing"];

    NSLog(@"Am I enabled? %i", [preferences boolForKey:@"Enabled"]);
    NSLog(@"Can I do thing? %i", doThing);
}

In Swift:

class Preferences {

    private let preferences = HBPreferences(identifier: "ws.hbang.common.demo")

    // Example using registration method
    private(set) var canDoThing: ObjCBool = false

    // Example using custom getter and setter
    var anotherSetting: Int {
        get { preferences["AnotherSetting"] as? Int ?? -1 }
        set { preferences["AnotherSetting"] = newValue }
    }

    // Example using KVO observation
    private var doThingObserver: NSKeyValueObserving?

    init() {
        preferences.register(defaults: [
            "Enabled": true,
            "AnotherSetting": 1
        ])

        preferences.register(&canDoThing, default: false, forKey: "DoThing")

        print("Am I enabled? \(preferences["Enabled"] as? Bool ?? false)")
        print("Can I do thing? \(canDoThing)")
    }

}

References

Security

As of Cephei 1.12, HBPreferences restricts most Apple preferences (identifiers starting with com.apple.…) from being read/written from a sandboxed process. This protects against a malicious app using HBPreferences as a way to gather sensitive information or change system preferences without the user’s knowledge. For instance, an App Store app could phish for the user’s Apple ID login, creating a very real-looking login prompt by pre-filling their email address in the username box, or gain access to the numbers/email addresses of people the user has recently contacted.

There is currently no way to avoid this restriction while still using HBPreferences. If you need access to Apple preferences, design your code to not need to do this from within the sandbox. This could be done using IPC from an unsandboxed process such as SpringBoard. Avoid sending sensitive information via IPC to sandboxed apps, as they can still get access to data you send through various ways.

Initializing an HBPreferences Object

  • Creates an instance of the class for the specified identifier.

    Declaration

    Objective-C

    + (nonnull instancetype)preferencesForIdentifier:(nonnull NSString *)identifier;

    Parameters

    identifier

    The identifier to be used. This is usually the same as the package identifier of the tweak.

    Return Value

    An autoreleased instance of HBPreferences for the specified identifier.

  • Initializes an instance of the class for the specified identifier.

    Declaration

    Objective-C

    - (nonnull instancetype)initWithIdentifier:(nonnull NSString *)identifier;

    Swift

    init(identifier: String)

    Parameters

    identifier

    The identifier to be used. This is usually the same as the package identifier of the tweak.

    Return Value

    An autoreleased instance of HBPreferences for the specified identifier.

  • The preferences identifier provided at initialisation.

    Declaration

    Objective-C

    @property (nonatomic, retain, readonly) NSString *_Nonnull identifier;

    Swift

    var identifier: String { get }

Synchronizing Preferences

  • Synchronizes preferences data to prevent race conditions.

    On iOS 8.0 and later, waits until all communications between the cfprefsd daemon and the current process have completed, preventing race conditions and guaranteeing no data will be lost. Prior to iOS 8.0, writes all pending changes to disk, and reads latest preferences from disk.

    Deprecated. On iOS 12.0 and later, synchronization is no longer required. The underlying CFPreferencesSynchronize() function simply returns YES.

    For earlier iOS releases, do not use this method directly unless you have a specific need. HBPreferences will synchronize automatically when needed. For further information on what this method does and when to use it, refer to NSUserDefaults in Practice § “Sharing Defaults Between Programs”.

    Declaration

    Objective-C

    - (BOOL)synchronize;

    Swift

    func synchronize() -> Bool

    Return Value

    YES if synchronization was successful, NO if an error occurred.

Registering Default Preference Values

  • The default preferences to be used when no value has been set by the user.

    You may modify the values of this dictionary directly.

    Declaration

    Objective-C

    @property (nonatomic, copy, readonly) NSMutableDictionary<NSString *, id> *_Nonnull defaults;

    Swift

    @NSCopying var defaults: NSMutableDictionary { get }
  • Adds the contents of the specified dictionary to the defaults property.

    Merges the provided dictionary with the mutable dictionary found on the defaults property.

    See

    defaults

    Declaration

    Objective-C

    - (void)registerDefaults:(nonnull NSDictionary<NSString *, id> *)defaultValues;

    Swift

    func register(defaults defaultValues: [String : Any])

    Parameters

    defaultValues

    The dictionary of keys and values you want to register.

Getting Preference Values

  • Returns a dictionary that contains all preferences that are set.

    This does not include default values.

    Declaration

    Objective-C

    - (nonnull NSDictionary<NSString *, id> *)dictionaryRepresentation;

    Swift

    func dictionaryRepresentation() -> [String : Any]

    Return Value

    A dictionary containing all keys and values.

  • Returns the object associated with the specified key.

    If the preference is not yet set, returns the default. If no default is set, returns nil.

    Warning

    You must manually synchronize preferences or use -registerObject:default:forKey: for this value to be updated when running on iOS 7 or older.

    Declaration

    Objective-C

    - (nonnull id)objectForKey:(nonnull NSString *)key;

    Swift

    func object(forKey key: String) -> Any

    Parameters

    key

    The key for which to return the corresponding value.

    Return Value

    The object associated with the specified key.

  • Returns the integer value associated with the specified key.

    If the preference is not yet set, returns the default. If no default is set, returns nil.

    Declaration

    Objective-C

    - (NSInteger)integerForKey:(nonnull NSString *)key;

    Swift

    func integer(forKey key: String) -> Int

    Parameters

    key

    The key for which to return the corresponding value.

    Return Value

    The integer value associated with the specified key.

  • Returns the unsigned integer value associated with the specified key.

    If the preference is not yet set, returns the default. If no default is set, returns nil.

    Declaration

    Objective-C

    - (NSUInteger)unsignedIntegerForKey:(nonnull NSString *)key;

    Swift

    func unsignedInteger(forKey key: String) -> UInt

    Parameters

    key

    The key for which to return the corresponding value.

    Return Value

    The unsigned integer value associated with the specified key.

  • Returns the floating-point value associated with the specified key.

    If the preference is not yet set, returns the default. If no default is set, returns nil.

    Declaration

    Objective-C

    - (CGFloat)floatForKey:(nonnull NSString *)key;

    Swift

    func float(forKey key: String) -> CGFloat

    Parameters

    key

    The key for which to return the corresponding value.

    Return Value

    The floating-point value associated with the specified key.

  • Returns the double value associated with the specified key.

    If the preference is not yet set, returns the default. If no default is set, returns nil.

    Declaration

    Objective-C

    - (double)doubleForKey:(nonnull NSString *)key;

    Swift

    func double(forKey key: String) -> Double

    Parameters

    key

    The key for which to return the corresponding value.

    Return Value

    The double value associated with the specified key.

  • Returns the Boolean value associated with the specified key.

    If the preference is not yet set, returns the default. If no default is set, returns nil.

    Declaration

    Objective-C

    - (BOOL)boolForKey:(nonnull NSString *)key;

    Swift

    func bool(forKey key: String) -> Bool

    Parameters

    key

    The key for which to return the corresponding value.

    Return Value

    The Boolean value associated with the specified key.

  • Returns the value associated with a given key.

    This method behaves the same as -objectForKey:, and enables the preferences object to be used with a subscript (square brackets). For example:

    Objective-C:

    NSString *fooBar = preferences[@"FooBar"];
    preferences[@"Awesome"] = @YES;
    

    Swift:

    let fooBar = preferences["FooBar"] as? String
    preferences["Awesome"] = true
    

    Declaration

    Objective-C

    - (nonnull id)objectForKeyedSubscript:(nonnull id)key;

    Swift

    subscript(key: Any) -> Any! { get set }

    Parameters

    key

    The key for which to return the corresponding value.

    Return Value

    The value associated with the specified key.

  • Returns the object associated with the specified key, or if no user preference is set, the provided default.

    Declaration

    Objective-C

    - (nonnull id)objectForKey:(nonnull NSString *)key
                       default:(nullable id)defaultValue;

    Swift

    func object(forKey key: String, default defaultValue: Any?) -> Any

    Parameters

    key

    The key for which to return the corresponding value.

    defaultValue

    The default value to use when no user preference is set.

    Return Value

    The object associated with the specified key, or the default value.

  • Returns the integer value associated with the specified key, or if no user preference is set, the provided default.

    Declaration

    Objective-C

    - (NSInteger)integerForKey:(nonnull NSString *)key
                       default:(NSInteger)defaultValue;

    Swift

    func integer(forKey key: String, default defaultValue: Int) -> Int

    Parameters

    key

    The key for which to return the corresponding value.

    defaultValue

    The default value to use when no user preference is set.

    Return Value

    The integer value associated with the specified key, or the default value.

  • Returns the unsigned integer value associated with the specified key, or if no user preference is set, the provided default.

    Declaration

    Objective-C

    - (NSUInteger)unsignedIntegerForKey:(nonnull NSString *)key
                                default:(NSUInteger)defaultValue;

    Swift

    func unsignedInteger(forKey key: String, default defaultValue: UInt) -> UInt

    Parameters

    key

    The key for which to return the corresponding value.

    defaultValue

    The default value to use when no user preference is set.

    Return Value

    The unsigned integer value associated with the specified key, or the default value.

  • Returns the floating-point value associated with the specified key, or if no user preference is set, the provided default.

    Declaration

    Objective-C

    - (CGFloat)floatForKey:(nonnull NSString *)key default:(CGFloat)defaultValue;

    Swift

    func float(forKey key: String, default defaultValue: CGFloat) -> CGFloat

    Parameters

    key

    The key for which to return the corresponding value.

    defaultValue

    The default value to use when no user preference is set.

    Return Value

    The floating-point value associated with the specified key, or the default value.

  • Returns the double value associated with the specified key, or if no user preference is set, the provided default.

    Declaration

    Objective-C

    - (double)doubleForKey:(nonnull NSString *)key default:(double)defaultValue;

    Swift

    func double(forKey key: String, default defaultValue: Double) -> Double

    Parameters

    key

    The key for which to return the corresponding value.

    defaultValue

    The default value to use when no user preference is set.

    Return Value

    The double value associated with the specified key, or the default value.

  • Returns the Boolean value associated with the specified key, or if no user preference is set, the provided default.

    Declaration

    Objective-C

    - (BOOL)boolForKey:(nonnull NSString *)key default:(BOOL)defaultValue;

    Swift

    func bool(forKey key: String, default defaultValue: Bool) -> Bool

    Parameters

    key

    The key for which to return the corresponding value.

    defaultValue

    The default value to use when no user preference is set.

    Return Value

    The Boolean value associated with the specified key, or the default value.

Setting Preference Values

  • Sets the value of the specified key.

    You should only call these methods if you are certain that the process is running as the mobile user.

    Declaration

    Objective-C

    - (void)setObject:(nullable id)value forKey:(nonnull NSString *)key;

    Swift

    func set(_ value: Any?, forKey key: String)

    Parameters

    value

    The object to store in the preferences.

    key

    The key with which to associate with the value. @exception HBPreferencesNotMobileException Thrown when the method is called by a process not running as the mobile user.

  • Sets the value of the specified key to the specified integer value.

    This is a convenience method that calls -setObject:forKey:. See the discussion of that method for more details.

    Declaration

    Objective-C

    - (void)setInteger:(NSInteger)value forKey:(nonnull NSString *)key;

    Swift

    func set(_ value: Int, forKey key: String)

    Parameters

    value

    The integer value to store in the preferences.

    key

    The key with which to associate with the value.

  • Sets the value of the specified key to the specified unsigned integer value.

    This is a convenience method that calls -setObject:forKey:. See the discussion of that method for more details.

    Declaration

    Objective-C

    - (void)setUnsignedInteger:(NSUInteger)value forKey:(nonnull NSString *)key;

    Swift

    func set(_ value: UInt, forKey key: String)

    Parameters

    value

    The unsigned integer value to store in the preferences.

    key

    The key with which to associate with the value.

  • Sets the value of the specified key to the specified floating-point value.

    This is a convenience method that calls -setObject:forKey:. See the discussion of that method for more details.

    Declaration

    Objective-C

    - (void)setFloat:(CGFloat)value forKey:(nonnull NSString *)key;

    Swift

    func set(_ value: CGFloat, forKey key: String)

    Parameters

    value

    The floating-point value to store in the preferences.

    key

    The key with which to associate with the value.

  • Sets the value of the specified key to the specified double value.

    This is a convenience method that calls -setObject:forKey:. See the discussion of that method for more details.

    Declaration

    Objective-C

    - (void)setDouble:(double)value forKey:(nonnull NSString *)key;

    Swift

    func set(_ value: Double, forKey key: String)

    Parameters

    value

    The double value to store in the preferences.

    key

    The key with which to associate with the value.

  • Sets the value of the specified key to the specified Boolean value.

    This is a convenience method that calls -setObject:forKey:. See the discussion of that method for more details.

    Declaration

    Objective-C

    - (void)setBool:(BOOL)value forKey:(nonnull NSString *)key;

    Swift

    func set(_ value: Bool, forKey key: String)

    Parameters

    value

    The Boolean value to store in the preferences.

    key

    The key with which to associate with the value.

  • Sets the value of the specified key to the specified value.

    This method behaves the same as -setObject:forKey:, and enables the preferences object to be used with a subscript (square brackets). For example:

    NSString *fooBar = preferences[@"FooBar"];
    preferences[@"Awesome"] = @YES;
    

    Declaration

    Objective-C

    - (void)setObject:(nullable id)object forKeyedSubscript:(nonnull id)key;

    Parameters

    object

    The value to store in the preferences.

    key

    The key with which to associate with the value.

Removing Preference Values

  • Removes a given key and its associated value from the dictionary.

    Declaration

    Objective-C

    - (void)removeObjectForKey:(nonnull NSString *)key;

    Swift

    func removeValue(forKey key: String)

    Parameters

    key

    The key to remove.

  • Removes all stored preferences.

    This method acts in the same way as discussed in -removeObjectForKey:.

    Declaration

    Objective-C

    - (void)removeAllObjects;

    Swift

    func removeAll()

Registering Variables

  • Register an object to be automatically set to the user’s preference.

    If the preference is not yet set, the object will be set to the provided default.

    You must post a Darwin notification after updating preferences for this to work. In particular, it must be set to the value of identifier, followed by /ReloadPrefs - for instance, ws.hbang.common.demo/ReloadPrefs. In a Preferences specifier property list, you can use the PostNotification key on your specifiers to achieve this:

    <dict><key>PostNotification</key>
        <string>ws.hbang.common.demo/ReloadPrefs</string>
    </dict>
    

    See

    -registerObject:default:forKey:

    Declaration

    Objective-C

    - (void)registerObject:(id _Nullable *_Nonnull)object
                   default:(nullable id)defaultValue
                    forKey:(nonnull NSString *)key;

    Swift

    func register(_ object: UnsafeMutablePointer<AnyObject?>, default defaultValue: Any?, forKey key: String)

    Parameters

    object

    The pointer to the object.

    defaultValue

    The default value to be used if no user preference is set.

    key

    The key in the preferences property list.

  • Register an integer value to be automatically set to the user’s preference.

    If the preference is not yet set, the object will be set to the provided default.

    Declaration

    Objective-C

    - (void)registerInteger:(nonnull NSInteger *)object
                    default:(NSInteger)defaultValue
                     forKey:(nonnull NSString *)key;

    Swift

    func register(_ object: UnsafeMutablePointer<Int>, default defaultValue: Int, forKey key: String)

    Parameters

    object

    The pointer to the integer.

    defaultValue

    The default value to be used if no user preference is set.

    key

    The key in the preferences property list.

  • Register an unsigned integer value to be automatically set to the user’s preference.

    If the preference is not yet set, the object will be set to the provided default.

    Declaration

    Objective-C

    - (void)registerUnsignedInteger:(nonnull NSUInteger *)object
                            default:(NSUInteger)defaultValue
                             forKey:(nonnull NSString *)key;

    Swift

    func register(_ object: UnsafeMutablePointer<UInt>, default defaultValue: UInt, forKey key: String)

    Parameters

    object

    The pointer to the unsigned integer.

    defaultValue

    The default value to be used if no user preference is set.

    key

    The key in the preferences property list.

  • Register a floating-point value to be automatically set to the user’s preference.

    If the preference is not yet set, the object will be set to the provided default.

    Declaration

    Objective-C

    - (void)registerFloat:(nonnull CGFloat *)object
                  default:(CGFloat)defaultValue
                   forKey:(nonnull NSString *)key;

    Swift

    func register(_ object: UnsafeMutablePointer<CGFloat>, default defaultValue: CGFloat, forKey key: String)

    Parameters

    object

    The pointer to the integer.

    defaultValue

    The default value to be used if no user preference is set.

    key

    The key in the preferences property list.

  • Register a double value to be automatically set to the user’s preference.

    If the preference is not yet set, the object will be set to the provided default.

    Declaration

    Objective-C

    - (void)registerDouble:(nonnull double *)object
                   default:(double)defaultValue
                    forKey:(nonnull NSString *)key;

    Swift

    func register(_ object: UnsafeMutablePointer<Double>, default defaultValue: Double, forKey key: String)

    Parameters

    object

    The pointer to the double.

    defaultValue

    The default value to be used if no user preference is set.

    key

    The key in the preferences property list.

  • Register a Boolean value to be automatically set to the user’s preference.

    If the preference is not yet set, the object will be set to the provided default.

    Declaration

    Objective-C

    - (void)registerBool:(nonnull BOOL *)object
                 default:(BOOL)defaultValue
                  forKey:(nonnull NSString *)key;

    Swift

    func register(_ object: UnsafeMutablePointer<ObjCBool>, default defaultValue: Bool, forKey key: String)

    Parameters

    object

    The pointer to the Boolean.

    defaultValue

    The default value to be used if no user preference is set.

    key

    The key in the preferences property list.

Preference Change Callbacks

  • Register a block to be called when a preference change is detected.

    Blocks are called after HBPreferences’ cache of values is updated. The block will also be called immediately after calling this method. See registerObject:default:forKey: for details on how to set up callbacks.

    Declaration

    Objective-C

    - (void)registerPreferenceChangeBlock:
        (nonnull HBPreferencesChangeCallback)callback;

    Swift

    func registerPreferenceChange(_ callback: @escaping HBPreferencesChangeCallback)

    Parameters

    callback

    A block object called when the specified key’s value changes. The block object takes no parameters and returns no value.

  • Register a block to be called when a specific preference is changed.

    Blocks are called after HBPreferences’ cache of values is updated. The block will also be called immediately after calling this method. See registerObject:default:forKey: for details on how to set up callbacks.

    Declaration

    Objective-C

    - (void)
        registerPreferenceChangeBlockForKey:(nonnull NSString *)key
                                      block:
                                          (nonnull HBPreferencesValueChangeCallback)
                                              callback;

    Swift

    func registerPreferenceChangeBlock(forKey key: String, block callback: @escaping HBPreferencesValueChangeCallback)

    Parameters

    key

    The key to listen for.

    callback

    A block object called when the specified key’s value changes. The block object’s parameters are the key and its new value.

  • Deprecated

    Use registerPreferenceChangeBlockForKey:block: instead.

    Register a block to be called when a specific preference is changed.

    Blocks are called after HBPreferences’ cache of values is updated. The block will also be called immediately after calling this method. See -registerObject:default:forKey: for details on how to set up callbacks.

    Deprecated. This method signature changed in Cephei 1.17 to better support the order of arguments preferred by Swift closure syntax. Use -registerPreferenceChangeBlockForKey:block: instead.

    Declaration

    Objective-C

    - (void)registerPreferenceChangeBlock:
                (nonnull HBPreferencesValueChangeCallback)callback
                                   forKey:(nonnull NSString *)key;

    Swift

    func registerPreferenceChange(_ callback: @escaping HBPreferencesValueChangeCallback, forKey key: String)

    Parameters

    callback

    A block object called when the specified key’s value changes. The block object’s parameters are the key and its new value.

    key

    The key to listen for.