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 asroot
. - 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.
-
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 }
-
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.
-
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.
-
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
.See
-objectForKey:
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
.See
-objectForKey:
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
.See
-objectForKey:
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
.See
-objectForKey:
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
.See
-objectForKey:
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
See
-objectForKey:
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.
-
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.
-
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()
-
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 thePostNotification
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.
-
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.