PostNotification - adds a way for the tweak to communicate with the preference bundle
<key>PostNotification</key>
<string>com.nightwind.prefbundleexampleprefs-updated</string>
height - determines the height of the cell
<key>height</key>
<string>66</string>
id - gives a unique identifier to the cell
<key>id</key>
<string>testCellId</string>
key - unique identifier to the cell, which can later be used when linking the cells to the main tweak file.
<key>key</key>
<string>testCellKey</string>
This is a cell that - when pressed, does a certain action. This action can be specified in your XXXRootListController.m
file.
Root.plist:
<dict>
<key>action</key>
<string>killPhoneApp</string>
<key>cell</key>
<string>PSButtonCell</string>
<key>label</key>
<string>Kill Phone App</string>
<key>defaults</key>
<string>com.nightwind.prefbundleexampleprefs</string>
</dict>
XXXRootListController.m:
- (void)killPhoneApp {
pid_t pid;
const char* args[] = {"killall", "MobilePhone", NULL};
posix_spawn(&pid, ROOT_PATH("/usr/bin/killall"), NULL, NULL, (char* const*)args, NULL);
}
This is a cell where text can be inputted and then later used in your tweak somewhere.
Root.plist:
<dict>
<key>cell</key>
<string>PSEditTextCell</string>
<key>defaults</key>
<string>com.nightwind.prefbundleexampleprefs</string>
<key>label</key>
<string>Text:</string>
<key>default</key>
<string>default text</string>
</dict>
This is a cell where text can be inputted, secured in a password-style manner, and then later used in your tweak somewhere.
Root.plist:
<dict>
<key>cell</key>
<string>PSSecureEditTextCell</string>
<key>defaults</key>
<string>com.nightwind.prefbundleexampleprefs</string>
<key>label</key>
<string>Text:</string>
<key>default</key>
<string>default text</string>
</dict>
(The screenshot does not pick it up, but there are dots where the normal text characters of the text field should be).
This cell is like PSEditTextCell
, in the way that it is also an area for text input. Unlike PSEditTextCell
, this cell expands the text input area to fit the whole cell.
Root.plist
:
<dict>
<key>cell</key>
<string>PSEditTextViewCell</string>
<key>defaults</key>
<string>com.nightwind.prefbundleexampleprefs</string>
<key>default</key>
<string>default text</string>
</dict>
This is a cell that is larger than normal cells. This cell can take an action assigned to it, just like PSButtonCell
.
Root.plist
:
<dict>
<key>cell</key>
<string>PSGiantCell</string>
<key>label</key>
<string>Test</string>
<key>action</key>
<string>respring</string>
</dict>
XXXRootListController.m
:
- (void)respring {
pid_t pid;
const char* args[] = {"killall", "SpringBoard", NULL};
posix_spawn(&pid, ROOT_PATH("/usr/bin/killall"), NULL, NULL, (char* const*)args, NULL);
}
This cell is similar to PSGiantCell
in the terms of size, however it has an option to put an icon into it.
Your icon should be placed in your Resources
folder and should be named accordingly to your plist. This cell also allows for an action, just like the PSGiantCell
mentioned above.
Root.plist:
<dict>
<key>cell</key>
<string>PSGiantIconCell</string>
<key>label</key>
<string>Test</string>
<key>icon</key>
<string>testicon.png</string>
<key>action</key>
<string>killSettingsApp</string>
</dict>
XXXRootListController.m:
- (void)killSettingsApp {
pid_t pid;
const char* args[] = {"killall", "Preferences", NULL};
posix_spawn(&pid, ROOT_PATH("/usr/bin/killall"), NULL, NULL, (char* const*)args, NULL);
}
In this case, the icon is named testicon.png
, so the image in your Resources
folder should be named testicon.png
as well. If you want to look at the icon in Filza on device, you can find it in /var/jb/Library/PreferenceBundles/YourBundleName.bundle/
on rootless and /Library/PreferenceBundles/YourBundleName.bundle
on non-rootless ("rootful").
PSGroupCell
is a really useful cell that allows for seperation of large clusters of cells.
Root.plist:
<dict>
<key>cell</key>
<string>PSGroupCell</string>
<key>label</key>
<string>PSGroupCell Test</string>
</dict>
(Pictured here: two PSGiantIconCell
s, which are the ones with the icons, and PSGroupCell
s above them).
This cell is used to link to a different view controller. For example in this code snippet, the cell leads to PSUIPrefsListController
which is the main Settings app page.
Root.plist:
<dict>
<key>cell</key>
<string>PSLinkCell</string>
<key>detail</key>
<string>PSUIPrefsListController</string>
<key>icon</key>
<string>icon.png</string>
<key>isController</key>
<true/>
<key>label</key>
<string>test label</string>
</dict>
This cell is used to link to a predefined view controller, which has the cells inside of it defined here.
Root.plist:
<dict>
<key>cell</key>
<string>PSLinkListCell</string>
<key>detail</key>
<string>PSListItemsController</string>
<key>label</key>
<string>Test 1</string>
<key>validTitles</key>
<array>
<string>List Test 1</string>
<string>List Test 2</string>
</array>
<key>validValues</key>
<array>
<integer>0</integer>
<integer>1</integer>
</array>
</dict>
This is a segmented cell, which can have multiple values inputted into it.
Root.plist:
<dict>
<key>cell</key>
<string>PSSegmentCell</string>
<key>default</key>
<integer>0</integer>
<key>label</key>
<string>Test</string>
<key>validTitles</key>
<array>
<string>test 1</string>
<string>test 2</string>
<string>test 3</string>
</array>
<key>validValues</key>
<array>
<integer>0</integer>
<integer>1</integer>
<integer>2</integer>
</array>
</dict>
This is a cell which contains a slider. The slider can be dragged and have multiple output values based on where the knob is located.
Root.plist:
<dict>
<key>cell</key>
<string>PSSliderCell</string>
<key>default</key>
<real>66</real>
<key>min</key>
<integer>0</integer>
<key>max</key>
<integer>50</integer>
</dict>
This cell is a cell which has a spinner inside of it. This cell is meant to be inserted before an actual cell is loaded and then deleted.
Root.plist:
<dict>
<key>cell</key>
<string>PSSpinnerCell</string>
<key>label</key>
<string>Test</string>
</dict>
This is a cell which just has text.
Root.plist:
<dict>
<key>cell</key>
<string>PSStaticTextCell</string>
<key>label</key>
<string>Test</string>
</dict>
This is a cell which has a switch in it, and the value of the switch can be used in the tweak.
Root.plist:
<dict>
<key>cell</key>
<string>PSSwitchCell</string>
<key>default</key>
<true/>
<key>label</key>
<string>Test</string>
</dict>
The code below shoould be put above %hook
s and, if present, %group
s as well.
static BOOL testSwitchKey; // PSSwitchCell
static NSInteger testSegmentkey; // PSSegmentCell
static NSInteger testSliderKey; // PSSliderCell
static NSString *testEditTextKey; // PSEditTextCell or PSSecureEditTextCell
The code below should be put in the main Tweak.x
/Tweak.xm
file.
static void preferencesChanged() {
NSUserDefaults *const prefs = [[NSUserDefaults alloc] initWithSuiteName:@"com.nightwind.prefbundleexampleprefs"];
testSwitchKey = [prefs objectForKey:@"testSwitchKey"] ? [prefs boolForKey:@"testSwitchKey"] : YES; // PSSwitchCell
testSegmentKey = [prefs objectForKey:@"testSegmentKey"] ? [prefs integerForKey:@"testSegmentKey"] : 0; // PSSegmentCell
testSliderKey = [prefs objectForKey:@"testSliderKey"] ? [prefs floatForKey:@"testSliderKey"] : 30.0f; // PSSliderCell
testEditTextKey = [prefs objectForKey:@"testEditTextKey"] ? [prefs stringForKey:@"testEditTextKey"] : @""; // PSEditTextCell or PSSecureEditTextCell
}
%ctor {
preferencesChanged();
CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), NULL, (CFNotificationCallback)preferencesChanged, CFSTR("com.nightwind.prefbundleexampleprefs-updated"), NULL, CFNotificationSuspensionBehaviorDeliverImmediately);
}
The key in the Tweak.x
/Tweak.xm
file should of course correspond to the key in the .plist
file.
So for example say there's a enable tweak switch in the preference bundle, which looks like this:
<dict>
<key>cell</key>
<string>PSSwitchCell</string>
<key>default</key>
<true/>
<key>label</key>
<string>Enable tweak</string>
<key>key</key>
<string>tweakEnabled</string>
<key>PostNotification</key>
<string>com.nightwind.prefbundleexampleprefs-updated</string>
</dict>
In the Tweak.x
/Tweak.xm
file, there should be this at the top:
static BOOL tweakEnabled;
...and this at the bottom:
tweakEnabled = [prefs objectForKey:@"tweakEnabled"] ? [prefs boolForKey:@"tweakEnabled"] : YES;
Note: If the default in the switch in the preference bundle is true, then the default should be YES
in the Tweak.x
/Tweak.xm
file as well. If the default is set to false, then the default in the Tweak.x
/Tweak.xm
file should be NO
.
Root.plist
:
<key>default</key>
<true/>
Tweak.x
:
tweakEnabled = [prefs objectForKey:@"tweakEnabled"] ? [prefs boolForKey:@"tweakEnabled"] : YES;
It says YES
at the very end so that corresponds to the .plist
file.
https://theapplewiki.com/wiki/Dev:Preferences_specifier_plist