{"id":26286597,"url":"https://github.com/nightwinddev/preference-bundle-example","last_synced_at":"2026-02-26T16:04:49.975Z","repository":{"id":131259155,"uuid":"391736664","full_name":"NightwindDev/Preference-Bundle-Example","owner":"NightwindDev","description":"Some information about preference bundles and the different cells in there.","archived":false,"fork":false,"pushed_at":"2024-07-08T06:17:50.000Z","size":701,"stargazers_count":12,"open_issues_count":0,"forks_count":2,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-07-08T08:08:11.982Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/NightwindDev.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-08-01T20:56:40.000Z","updated_at":"2024-07-08T08:08:19.375Z","dependencies_parsed_at":"2024-07-08T08:08:13.705Z","dependency_job_id":"506fd8ac-0bbe-43b5-9e40-d031b2e78163","html_url":"https://github.com/NightwindDev/Preference-Bundle-Example","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NightwindDev%2FPreference-Bundle-Example","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NightwindDev%2FPreference-Bundle-Example/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NightwindDev%2FPreference-Bundle-Example/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NightwindDev%2FPreference-Bundle-Example/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/NightwindDev","download_url":"https://codeload.github.com/NightwindDev/Preference-Bundle-Example/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243642429,"owners_count":20324023,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-03-14T20:32:31.208Z","updated_at":"2026-02-26T16:04:44.921Z","avatar_url":"https://github.com/NightwindDev.png","language":null,"readme":"# Preference Bundle Example\n\n## Universal Keys\n\n**PostNotification** - adds a way for the tweak to communicate with the preference bundle\n```xml\n\u003ckey\u003ePostNotification\u003c/key\u003e\n\u003cstring\u003ecom.nightwind.prefbundleexampleprefs-updated\u003c/string\u003e\n```\n\n**height** - determines the height of the cell \n```xml\n\u003ckey\u003eheight\u003c/key\u003e\n\u003cstring\u003e66\u003c/string\u003e\n```\n\n**id** - gives a unique identifier to the cell\n```xml\n\u003ckey\u003eid\u003c/key\u003e\n\u003cstring\u003etestCellId\u003c/string\u003e\n```\n\n**key** - unique identifier to the cell, which can later be used when \u003ca href =\"https://github.com/NightwindDev/Preference-Bundle-Example/blob/main/README.md#linking-cells-to-tweak\"\u003elinking the cells to the main tweak file.\u003c/a\u003e\n```xml\n\u003ckey\u003ekey\u003c/key\u003e\n\u003cstring\u003etestCellKey\u003c/string\u003e\n```\n\n\u003cbr/\u003e\n\n## PSButtonCell\n\nThis is a cell that - when pressed, does a certain action. This action can be specified in your `XXXRootListController.m` file.\n\nRoot.plist:\n\n```xml\n\u003cdict\u003e\n\t\u003ckey\u003eaction\u003c/key\u003e\n\t\u003cstring\u003ekillPhoneApp\u003c/string\u003e\n\t\u003ckey\u003ecell\u003c/key\u003e\n\t\u003cstring\u003ePSButtonCell\u003c/string\u003e\n\t\u003ckey\u003elabel\u003c/key\u003e\n\t\u003cstring\u003eKill Phone App\u003c/string\u003e\n\t\u003ckey\u003edefaults\u003c/key\u003e\n\t\u003cstring\u003ecom.nightwind.prefbundleexampleprefs\u003c/string\u003e\n\u003c/dict\u003e\n```\n\nXXXRootListController.m:\n\n```logos\n- (void)killPhoneApp {\n\tpid_t pid;\n\tconst char* args[] = {\"killall\", \"MobilePhone\", NULL};\n\tposix_spawn(\u0026pid, ROOT_PATH(\"/usr/bin/killall\"), NULL, NULL, (char* const*)args, NULL);\n}\n```\n\n\u003cimg src=\"https://github.com/NightwindDev/Preference-Bundle-Example/blob/main/PSButtonCell.jpeg\" width=\"415\"\u003e\n\n\n## PSEditTextCell\n\nThis is a cell where text can be inputted and then later used in your tweak somewhere.\n\nRoot.plist:\n\n```xml\n\u003cdict\u003e\n\t\u003ckey\u003ecell\u003c/key\u003e\n\t\u003cstring\u003ePSEditTextCell\u003c/string\u003e\n\t\u003ckey\u003edefaults\u003c/key\u003e\n\t\u003cstring\u003ecom.nightwind.prefbundleexampleprefs\u003c/string\u003e\n\t\u003ckey\u003elabel\u003c/key\u003e\n\t\u003cstring\u003eText:\u003c/string\u003e\n\t\u003ckey\u003edefault\u003c/key\u003e\n\t\u003cstring\u003edefault text\u003c/string\u003e\n\u003c/dict\u003e\n```\n\n\u003cimg src=\"https://github.com/NightwindDev/Preference-Bundle-Example/blob/main/PSEditTextCell.jpeg?raw=true\" width=\"415\"\u003e\n\n## PSSecureEditTextCell\n\nThis is a cell where text can be inputted, secured in a password-style manner, and then later used in your tweak somewhere.\n\nRoot.plist:\n\n```xml\n\u003cdict\u003e\n\t\u003ckey\u003ecell\u003c/key\u003e\n\t\u003cstring\u003ePSSecureEditTextCell\u003c/string\u003e\n\t\u003ckey\u003edefaults\u003c/key\u003e\n\t\u003cstring\u003ecom.nightwind.prefbundleexampleprefs\u003c/string\u003e\n\t\u003ckey\u003elabel\u003c/key\u003e\n\t\u003cstring\u003eText:\u003c/string\u003e\n\t\u003ckey\u003edefault\u003c/key\u003e\n\t\u003cstring\u003edefault text\u003c/string\u003e\n\u003c/dict\u003e\n```\n\n\u003cimg src=\"https://github.com/NightwindDev/Preference-Bundle-Example/blob/main/PSSecureEditTextCell.jpeg?raw=true\" width=\"415\"\u003e\n\n(The screenshot does not pick it up, but there are dots where the normal text characters of the text field should be).\n\n## PSEditTextViewCell\n\nThis 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.\n\n`Root.plist`:\n\n```xml\n\u003cdict\u003e\n\t\u003ckey\u003ecell\u003c/key\u003e\n\t\u003cstring\u003ePSEditTextViewCell\u003c/string\u003e\n\t\u003ckey\u003edefaults\u003c/key\u003e\n\t\u003cstring\u003ecom.nightwind.prefbundleexampleprefs\u003c/string\u003e\n\t\u003ckey\u003edefault\u003c/key\u003e\n\t\u003cstring\u003edefault text\u003c/string\u003e\n\u003c/dict\u003e\n```\n\n\u003cimg src=\"https://github.com/NightwindDev/Preference-Bundle-Example/blob/main/PSEditTextViewCell.jpeg?raw=true\" width=\"415\"\u003e\n\n## PSGiantCell\n\nThis is a cell that is larger than normal cells. This cell can take an action assigned to it, just like `PSButtonCell`.\n\n\n`Root.plist`:\n\n```xml\n\u003cdict\u003e\n\t\u003ckey\u003ecell\u003c/key\u003e\n\t\u003cstring\u003ePSGiantCell\u003c/string\u003e\n\t\u003ckey\u003elabel\u003c/key\u003e\n\t\u003cstring\u003eTest\u003c/string\u003e\n\t\u003ckey\u003eaction\u003c/key\u003e\n\t\u003cstring\u003erespring\u003c/string\u003e\n\u003c/dict\u003e\n```\n\n`XXXRootListController.m`:\n\n```logos\n- (void)respring {\n\tpid_t pid;\n\tconst char* args[] = {\"killall\", \"SpringBoard\", NULL};\n\tposix_spawn(\u0026pid, ROOT_PATH(\"/usr/bin/killall\"), NULL, NULL, (char* const*)args, NULL);\n}\n```\n\n\u003cimg src=\"https://github.com/NightwindDev/Preference-Bundle-Example/blob/main/PSGiantCell.jpeg?raw=true\" width=\"415\"\u003e\n\n## PSGiantIconCell\n\nThis cell is similar to `PSGiantCell` in the terms of size, however it has an option to put an icon into it.\nYour 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.\n\n\nRoot.plist:\n\n```xml\n\u003cdict\u003e\n\t\u003ckey\u003ecell\u003c/key\u003e\n\t\u003cstring\u003ePSGiantIconCell\u003c/string\u003e\n\t\u003ckey\u003elabel\u003c/key\u003e\n\t\u003cstring\u003eTest\u003c/string\u003e\n\t\u003ckey\u003eicon\u003c/key\u003e\n\t\u003cstring\u003etesticon.png\u003c/string\u003e\n\t\u003ckey\u003eaction\u003c/key\u003e\n\t\u003cstring\u003ekillSettingsApp\u003c/string\u003e\n\u003c/dict\u003e\n```\n\nXXXRootListController.m:\n\n```logos\n- (void)killSettingsApp {\n\tpid_t pid;\n\tconst char* args[] = {\"killall\", \"Preferences\", NULL};\n\tposix_spawn(\u0026pid, ROOT_PATH(\"/usr/bin/killall\"), NULL, NULL, (char* const*)args, NULL);\n}\n```\n\nIn 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\").\n\n\n\u003cimg src=\"https://github.com/NightwindDev/Preference-Bundle-Example/blob/main/PSGiantIconCell.jpeg?raw=true\" width=\"415\"\u003e\n\n## PSGroupCell\n\n`PSGroupCell` is a really useful cell that allows for seperation of large clusters of cells. \n\n\nRoot.plist:\n\n```xml\n\u003cdict\u003e\n\t\u003ckey\u003ecell\u003c/key\u003e\n\t\u003cstring\u003ePSGroupCell\u003c/string\u003e\n\t\u003ckey\u003elabel\u003c/key\u003e\n\t\u003cstring\u003ePSGroupCell Test\u003c/string\u003e\n\u003c/dict\u003e\n\n```\n\n\u003cimg src=\"https://github.com/NightwindDev/Preference-Bundle-Example/blob/main/PSGroupCell.jpeg?raw=true\" width=\"415\"\u003e\n\n(Pictured here: two `PSGiantIconCell`s, which are the ones with the icons, and `PSGroupCell`s above them).\n\n## PSLinkCell\n\nThis 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.\n\n\nRoot.plist:\n\n```xml\n\u003cdict\u003e\n\t\u003ckey\u003ecell\u003c/key\u003e\n\t\u003cstring\u003ePSLinkCell\u003c/string\u003e\n\t\u003ckey\u003edetail\u003c/key\u003e\n\t\u003cstring\u003ePSUIPrefsListController\u003c/string\u003e\n\t\u003ckey\u003eicon\u003c/key\u003e\n\t\u003cstring\u003eicon.png\u003c/string\u003e\n\t\u003ckey\u003eisController\u003c/key\u003e\n\t\u003ctrue/\u003e\n\t\u003ckey\u003elabel\u003c/key\u003e\n\t\u003cstring\u003etest label\u003c/string\u003e\n\u003c/dict\u003e\n```\n\n\u003cimg src=\"https://github.com/NightwindDev/Preference-Bundle-Example/blob/main/PSLinkCell.jpeg?raw=true\" width=\"415\"\u003e\n\n## PSLinkListCell\n\nThis cell is used to link to a predefined view controller, which has the cells inside of it defined here.\n\n\nRoot.plist:\n\n```xml\n\u003cdict\u003e\n\t\u003ckey\u003ecell\u003c/key\u003e\n\t\u003cstring\u003ePSLinkListCell\u003c/string\u003e\n\t\u003ckey\u003edetail\u003c/key\u003e\n\t\u003cstring\u003ePSListItemsController\u003c/string\u003e\n\t\u003ckey\u003elabel\u003c/key\u003e\n\t\u003cstring\u003eTest 1\u003c/string\u003e\n\t\u003ckey\u003evalidTitles\u003c/key\u003e\n\t\u003carray\u003e\n\t\t\u003cstring\u003eList Test 1\u003c/string\u003e\n\t\t\u003cstring\u003eList Test 2\u003c/string\u003e\n\t\u003c/array\u003e\n\t\u003ckey\u003evalidValues\u003c/key\u003e\n\t\u003carray\u003e\n\t\t\u003cinteger\u003e0\u003c/integer\u003e\n\t\t\u003cinteger\u003e1\u003c/integer\u003e\n\t\u003c/array\u003e\n\u003c/dict\u003e\n```\n\n\u003cimg src=\"https://github.com/NightwindDev/Preference-Bundle-Example/blob/main/PSLinkListCell.gif?raw=true\" width=\"415\"\u003e\n\n## PSSegmentCell\n\nThis is a segmented cell, which can have multiple values inputted into it.\n\n\nRoot.plist:\n\n```xml\n\u003cdict\u003e\n\t\u003ckey\u003ecell\u003c/key\u003e\n\t\u003cstring\u003ePSSegmentCell\u003c/string\u003e\n\t\u003ckey\u003edefault\u003c/key\u003e\n\t\u003cinteger\u003e0\u003c/integer\u003e\n\t\u003ckey\u003elabel\u003c/key\u003e\n\t\u003cstring\u003eTest\u003c/string\u003e\n\t\u003ckey\u003evalidTitles\u003c/key\u003e\n\t\u003carray\u003e\n\t\t\u003cstring\u003etest 1\u003c/string\u003e\n\t\t\u003cstring\u003etest 2\u003c/string\u003e\n\t\t\u003cstring\u003etest 3\u003c/string\u003e\n\t\u003c/array\u003e\n\t\u003ckey\u003evalidValues\u003c/key\u003e\n\t\u003carray\u003e\n\t\t\u003cinteger\u003e0\u003c/integer\u003e\n\t\t\u003cinteger\u003e1\u003c/integer\u003e\n\t\t\u003cinteger\u003e2\u003c/integer\u003e\n\t\u003c/array\u003e\n\u003c/dict\u003e\n```\n\n\u003cimg src=\"https://github.com/NightwindDev/Preference-Bundle-Example/blob/main/PSSegmentCell.jpeg?raw=true\" width=\"415\"\u003e\n\n## PSSliderCell\n\nThis is a cell which contains a slider. The slider can be dragged and have multiple output values based on where the knob is located.\n\nRoot.plist:\n\n```xml\n\u003cdict\u003e\n\t\u003ckey\u003ecell\u003c/key\u003e\n\t\u003cstring\u003ePSSliderCell\u003c/string\u003e\n\t\u003ckey\u003edefault\u003c/key\u003e\n\t\u003creal\u003e66\u003c/real\u003e\n\t\u003ckey\u003emin\u003c/key\u003e\n\t\u003cinteger\u003e0\u003c/integer\u003e\n\t\u003ckey\u003emax\u003c/key\u003e\n\t\u003cinteger\u003e50\u003c/integer\u003e\n\u003c/dict\u003e\n```\n\n\u003cimg src=\"https://github.com/NightwindDev/Preference-Bundle-Example/blob/main/PSSliderCell.jpeg?raw=true\" width=\"415\"\u003e\n\n## PSSpinnerCell\n\nThis 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.\n\n\nRoot.plist:\n\n```xml\n\u003cdict\u003e\n\t\u003ckey\u003ecell\u003c/key\u003e\n\t\u003cstring\u003ePSSpinnerCell\u003c/string\u003e\n\t\u003ckey\u003elabel\u003c/key\u003e\n\t\u003cstring\u003eTest\u003c/string\u003e\n\u003c/dict\u003e\n```\n\n\u003cimg src=\"https://github.com/NightwindDev/Preference-Bundle-Example/blob/main/PSSpinnerCell.jpeg?raw=true\" width=\"415\"\u003e\n\n## PSStaticTextCell\n\nThis is a cell which just has text.\n\n\nRoot.plist:\n\n```xml\n\u003cdict\u003e\n\t\u003ckey\u003ecell\u003c/key\u003e\n\t\u003cstring\u003ePSStaticTextCell\u003c/string\u003e\n\t\u003ckey\u003elabel\u003c/key\u003e\n\t\u003cstring\u003eTest\u003c/string\u003e\n\u003c/dict\u003e\n```\n\n\u003cimg src=\"https://github.com/NightwindDev/Preference-Bundle-Example/blob/main/PSStaticTextCell.jpeg?raw=true\" width=\"415\"\u003e\n\n## PSSwitchCell\n\nThis is a cell which has a switch in it, and the value of the switch can be used in the tweak.\n\n\nRoot.plist:\n\n```xml\n\u003cdict\u003e\n\t\u003ckey\u003ecell\u003c/key\u003e\n\t\u003cstring\u003ePSSwitchCell\u003c/string\u003e\n\t\u003ckey\u003edefault\u003c/key\u003e\n\t\u003ctrue/\u003e\n\t\u003ckey\u003elabel\u003c/key\u003e\n\t\u003cstring\u003eTest\u003c/string\u003e\n\u003c/dict\u003e\n```\n\n\u003cimg src=\"https://github.com/NightwindDev/Preference-Bundle-Example/blob/main/PSSwitchCell.jpeg?raw=true\" width=\"415\"\u003e\n\n\u003cbr/\u003e\n\n# Linking Cells to Tweak\n\nThe code below shoould be put above `%hook`s and, if present, `%group`s as well. \n\n```logos\nstatic BOOL testSwitchKey; // PSSwitchCell\nstatic NSInteger testSegmentkey; // PSSegmentCell\nstatic NSInteger testSliderKey; // PSSliderCell\nstatic NSString *testEditTextKey; // PSEditTextCell or PSSecureEditTextCell\n```\n\nThe code below should be put in the main `Tweak.x`/`Tweak.xm` file.\n\n```logos\nstatic void preferencesChanged() {\n\tNSUserDefaults *const prefs = [[NSUserDefaults alloc] initWithSuiteName:@\"com.nightwind.prefbundleexampleprefs\"];\n\n\ttestSwitchKey = [prefs objectForKey:@\"testSwitchKey\"] ? [prefs boolForKey:@\"testSwitchKey\"] : YES; // PSSwitchCell\n\ttestSegmentKey = [prefs objectForKey:@\"testSegmentKey\"] ? [prefs integerForKey:@\"testSegmentKey\"] : 0; // PSSegmentCell\n\ttestSliderKey = [prefs objectForKey:@\"testSliderKey\"] ? [prefs floatForKey:@\"testSliderKey\"] : 30.0f; // PSSliderCell\n\ttestEditTextKey = [prefs objectForKey:@\"testEditTextKey\"] ? [prefs stringForKey:@\"testEditTextKey\"] : @\"\"; // PSEditTextCell or PSSecureEditTextCell\n}\n\n%ctor {\n\tpreferencesChanged();\n\n\tCFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), NULL, (CFNotificationCallback)preferencesChanged, CFSTR(\"com.nightwind.prefbundleexampleprefs-updated\"), NULL, CFNotificationSuspensionBehaviorDeliverImmediately);\n}\n```\n\nThe key in the `Tweak.x`/`Tweak.xm` file should of course correspond to the key in the `.plist` file.\n\nSo for example say there's a enable tweak switch in the preference bundle, which looks like this:\n\n```xml\n\u003cdict\u003e\n\t\u003ckey\u003ecell\u003c/key\u003e\n\t\u003cstring\u003ePSSwitchCell\u003c/string\u003e\n\t\u003ckey\u003edefault\u003c/key\u003e\n\t\u003ctrue/\u003e\n\t\u003ckey\u003elabel\u003c/key\u003e\n\t\u003cstring\u003eEnable tweak\u003c/string\u003e\n\t\u003ckey\u003ekey\u003c/key\u003e\n\t\u003cstring\u003etweakEnabled\u003c/string\u003e\n\t\u003ckey\u003ePostNotification\u003c/key\u003e\n\t\u003cstring\u003ecom.nightwind.prefbundleexampleprefs-updated\u003c/string\u003e\n\u003c/dict\u003e\n```\n\nIn the `Tweak.x`/`Tweak.xm` file, there should be this at the top:\n\n```logos\nstatic BOOL tweakEnabled;\n```\n\n...and this at the bottom:\n\n```logos\ntweakEnabled = [prefs objectForKey:@\"tweakEnabled\"] ? [prefs boolForKey:@\"tweakEnabled\"] : YES;\n```\n\n**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`.\n\n`Root.plist`:\n\n```xml\n\u003ckey\u003edefault\u003c/key\u003e\n\u003ctrue/\u003e\n```\n\n`Tweak.x`:\n\n```logos\ntweakEnabled = [prefs objectForKey:@\"tweakEnabled\"] ? [prefs boolForKey:@\"tweakEnabled\"] : YES;\n```\n*It says `YES` at the very end so that corresponds to the `.plist` file.*\n\n# Further Information\nhttps://theapplewiki.com/wiki/Dev:Preferences_specifier_plist\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnightwinddev%2Fpreference-bundle-example","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnightwinddev%2Fpreference-bundle-example","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnightwinddev%2Fpreference-bundle-example/lists"}