Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.
Sign upPart 6: Preferences, Preferences, a little Tweak, and Heaps of More Preferences
Hook code (in Logos)
The hooking code itself is really really simple. This is all that is needed in my Tweak.xm file:
%hook DATaskManager {
-(id) userAgent {
return @"iPhone8C2/1307.36"; // iPhone6S+ running iOS 9.3.5
}
}
%endAnd this works fine!
But what happens when iOS 9.3.6 comes out? Or iOS 10.0? I don't want to have to check out, modify, re-build, re-package, and re-submit my tweak for every upgrade. That's ludicrous.
There should be a way for the user to specify what User-Agent they want to use...
Creating a Preference Bundle
I used nic.pl to create a preference_bundle inside of my existing tweak, and named it ExchangentPrefs under the namespace com.derv82.exchangentprefs. This created the exchangentprefs directory seen in the code on this repo.
The benefit of creating the PreferenceBundle inside of the existing tweak is:
- It gets packaged together with the main tweak
-
nic.plknows to update THEOS' Makefile to automatically include the preference bundle when building/packaging. - Everything is all in one place. You don't need create multiple Github repos for one project.
I followed a lot of guides and looked at sample code when creating my preference bundle. The guides were useful but the main points that took me a while to get are:
- PreferenceBundles used by Theos integrate with MobileSubstrate's PreferenceLoader.
- PreferenceLoader injects MobileSubstrate tweaks' PreferenceBundles (like the one we're making, or Activator's bundle, etc) into the iOS Settings application at runtime (above 3rd-party non-jailbreak tweaks).
- PreferenceBundles are their own bundle.
- Your
Tweak.xmcannot directly call your preference bundle to get preferences; it has to go through some other way (like reading preferences from a .plist file). - See PreferenceBundles#Loading_Preferences (iPhoneDevWiki) for examples of loading preferences within your
Tweak.xm - See kirb's guide on the "right way" to load/store preferences: http://sharedinstance.net/2014/11/settings-the-right-way/
- I couldn't get this to work. I should've gone to the #iphonedev IRC channel to get help! You can too!
- I ended up modifying my PreferenceBundle code (
ExchangentRootListController.m) to write to the.plistfile on every change, and read from the.plistfile on every load. This required sendingPostNostificationmessages to theTweak.xmclass which would then reload the.plistfile. Very circuitious.
- PreferenceBundles are mostly-defined by
.plistfiles that dictate the order of elements (enabled, the text for "Enabled", sliders, buttons, icons, etc). - However, PreferenceBundles have their own code (in Objective-C, usually
.mor.mmfiles) that is executed when the user taps on the tweak in the "Settings" app.
- There's generic/boiler-plate code that "just works" for most simple preferences: PreferenceBundles#Issues_with_OS_3.2_and_4.0
- More-complicated preference logic (like hiding/showing preference fields, changing fields, etc) require adding code to the PreferenceBundle's Objective-C code. This is what I did for Exchangent.
Preferences get really complicated really fast. I suggest keeping your settings as simple as possible.
Protip: Validate .plist files using plutil
Example:
$ plutil "/var/mobile/Library/Preferences/com.derv82.exchangentprefs.plist"
{
customUserAgent = "iPhone8C2/1307.69";
device = iPhone8C2;
enabled = 1;
iosVersion = "1307.36";
useCustom = 0;
userAgent = "iPhone8C2/1307.37";
}If there is no output, then it's not a valid .plist file. This came in handy when I made a typo in a plist file but didn't get any errors when compiling/installing with Theos.