Difference between revisions of "PreferenceLoader"

From iPhone Development Wiki
Jump to: navigation, search
m (References: - Updated Reference link "Settings How To")
(Extended description, reordered keys, explanation of each approach, pl_filter usage correction, formatting)
Line 8: Line 8:
 
'''PreferenceLoader''' is an open-source<ref>[http://github.com/DHowett/preferenceloader PreferenceLoader Source]</ref> [[MobileSubstrate]] based utility that allows developers to add entries to the [[Preferences.app|Settings]] application, similar to the Settings bundles that AppStore apps use.
 
'''PreferenceLoader''' is an open-source<ref>[http://github.com/DHowett/preferenceloader PreferenceLoader Source]</ref> [[MobileSubstrate]] based utility that allows developers to add entries to the [[Preferences.app|Settings]] application, similar to the Settings bundles that AppStore apps use.
  
== Entry ==
+
The approach PreferenceLoader takes is different from other approaches in that the Settings-iPhone.plist and Settings-iPod.plist files are not modified on disk. When the [[Preferences.app|Settings]] application is loaded, entries are read from plists in <tt>/Library/PreferenceLoader/Preferences/</tt> and are dynamically added to the list before the AppStore applications' preferences group.
  
The approach PreferenceLoader takes is different from other approaches in that the Settings-iPhone.plist and Settings-iPod.plist files are not modified on disk. When the [[Preferences.app|Settings]] application is loaded, entries are read from plists in <tt>/Library/PreferenceLoader/Preferences/</tt> and are dynamically added to the list. Each entry is defined in its own plist and consists of a dictionary containing an element named <tt>entry</tt>, which is also a dictionary. The entry dictionary must define a <tt>cell</tt> of type <tt>PSLinkCell</tt> and have a <tt>label</tt>. Additionally, the <tt>bundle</tt> and <tt>isController</tt> keys can be set for entries referencing [[PreferenceBundles]].
+
PreferenceLoader also allows [[PreferenceBundles]] to be loaded from <tt>/Library/PreferenceBundles/</tt><ref name="1.2">PreferenceLoader version 1.2 and later</ref><ref>Bundles can also be loaded from /System/Library/PreferenceBundles/, but this is no longer the preferred method as of PreferenceLoader 1.2</ref>.
 +
 
 +
== Entry file ==
 +
 
 +
Each entry is defined in its own plist. There are at least three ways to approach preferences support for your tweaks.
 +
 
 +
=== Reduced approach ===
 +
 
 +
Provides a switch on the root section of the preferences (like Airplane Mode). Recommended for configuration-less tweaks.
  
 
<source lang="xml">
 
<source lang="xml">
Line 17: Line 25:
 
<plist version="1.0">
 
<plist version="1.0">
 
<dict>
 
<dict>
  <key>entry</key>
+
<key>entry</key>
  <dict>
+
<dict>
      <key>cell</key>
+
<key>cell</key>
      <string>PSLinkCell</string>
+
<string>PSSwitchCell</string>
      <key>icon</key>
+
<key>defaults</key>
      <string>TestIcon.png</string>
+
<string>com.test.TestSettings</string>
      <key>label</key>
+
<key>label</key>
      <string>Test</string>
+
<string>Test</string>
  </dict>
+
<key>key</key>
 +
<string>enabled</string>
 +
<key>default</key>
 +
<true/>
 +
<key>icon</key>
 +
<string>TestIcon.png</string>
 +
<key>PostNotification</key>
 +
<string>com.test.TestSettings/preferences.changed</string>
 +
</dict>
 
</dict>
 
</dict>
 
</plist>
 
</plist>
 
</source>
 
</source>
 +
 +
This sets up an entry called <code>Test</code> with an icon loaded from <code>TestIcon.png</code> to the left and a UISwitch on the right, starting in the ON position, saving the value in <code>[NSHomeDirectory() stringByAppendingFormat:@"/Library/Preferences/%s.plist", "com.test.TestSettings"]</code> for the key <tt>enabled</tt> and posting a Darwin notification named <code>com.test.TestSettings/preferences.changed</code>.
  
 
== Simple Approach ==
 
== Simple Approach ==
  
In the simple approach the settings page is defined in a plist file located in the <tt>/Library/PreferenceLoader/Preferences/</tt> folder. The name of the plist file must match the label option in the entry dictionary. For example, if the label in the entry dictionary is defined as <tt>Test</tt>, then the plist that defines the settings page must be named <tt>Test.plist</tt>.
+
Provides a pane where other cells can appear (like Wi-Fi). Recommended for configuration-friendly tweaks. Here's an example:
 
 
Typically, the settings and entry plists are combined into a single plist. This works because the settings plist has elements named items and title, so adding an entry element does not break anything. Here's an example of a combined plist:
 
  
 
<source lang="xml">
 
<source lang="xml">
Line 41: Line 57:
 
<plist version="1.0">
 
<plist version="1.0">
 
<dict>
 
<dict>
  <key>entry</key>
+
<key>entry</key>
  <dict>
+
<dict>
      <key>cell</key>
+
<key>cell</key>
        <string>PSLinkCell</string>
+
<string>PSLinkCell</string>
        <key>icon</key>
+
<key>icon</key>
        <string>TestIcon.png</string>
+
<string>TestIcon.png</string>
        <key>label</key>
+
<key>label</key>
        <string>Test</string>
+
<string>Test</string>
      </dict>
+
</dict>
      <key>items</key>
+
<key>title</key>
      <array>
+
<string>Test Settings</string>
        <dict>
+
<key>items</key>
            <key>cell</key>
+
<array>
            <string>PSSwitchCell</string>
+
<dict>
            <key>default</key>
+
<key>cell</key>
            <true/>
+
<string>PSSwitchCell</string>
            <key>defaults</key>
+
<key>defaults</key>
            <string>com.test.TestSettings</string>
+
<string>com.test.TestSettings</string>
            <key>key</key>
+
<key>key</key>
            <string>testKey</string>
+
<string>enabled</string>
            <key>label</key>
+
<key>label</key>
            <string>Test Setting</string>
+
<string>Enabled</string>
        </dict>
+
<key>default</key>
      </array>
+
<true/>
      <key>title</key>
+
<key>PostNotification</key>
      <string>Test</string>
+
<string>com.test.TestSettings/preferences.changed</string>
  </dict>
+
</dict>
 +
</array>
 +
</dict>
 
</plist>
 
</plist>
 
</source>
 
</source>
  
There is a good tutorial on how to create these settings plists on MMi at http://modmyi.com/forums/file-mods/22453-how-make-custom-menus-preferences-app-custom-preferences.html.
+
This sets up an entry called <code>Test</code> with an icon loaded from <code>TestIcon.png</code> to the left. The pushed page has the title set to <tt>Test Settings</tt>. The page will only contain a cell with the label <tt>Enabled</tt> UISwitch on the right, starting in the ON position, saving the value in <code>[NSHomeDirectory() stringByAppendingFormat:@"/Library/Preferences/%s.plist", "com.test.TestSettings"]</code> for the key <tt>enabled</tt> and posting a Darwin notification named <code>com.test.TestSettings/preferences.changed</code>.
 +
 
 +
For more preferences values you can add [[Preferences_specifier_plist|specifier]] dictionaries to the <tt>items</tt> array.
 +
 
 +
There is a good tutorial on [http://modmyi.com/forums/file-mods/22453-how-make-custom-menus-preferences-app-custom-preferences.html how to create settings plists on MMi].
  
== Localizable Simple Approach<ref name="1.2">PreferenceLoader version 1.2 and later</ref> ==
+
=== Localization<ref name="1.2">PreferenceLoader version 1.2 and later</ref> ===
  
This approach is similar to the Simple Approach, except the settings and entry plists are located in a sub-folder of <tt>/Library/PreferenceLoader/Preferences/</tt>. In addition to the plists and icons, the sub-folder can also contain .lproj folders with appropriate localization strings.
+
Instead of placing the entry plist in <tt>/Library/PreferenceLoader/Preferences/</tt>, place it in a subfolder in that directory along with the .lproj folders containing a strings file named <tt>Localizable.strings</tt>.
  
 
== PreferenceBundle Approach ==
 
== PreferenceBundle Approach ==
  
With this technique, you can actually create custom settings pages that are able to execute code. The entry plist for this approach must now include a reference to the name of the [[PreferenceBundles|PreferenceBundle]] and define the <tt>isController</tt> option to <tt>true</tt>. This will cause the [[Preferences.app|Settings]] application to load the corresponding bundle located in <tt>/Library/PreferenceBundles/</tt><ref name="1.2">PreferenceLoader version 1.2 and later</ref><ref>Bundles can also be loaded from /System/Library/PreferenceBundles/, but this is no longer the preferred method as of PreferenceLoader 1.2</ref>. Unlike the simple method, all of the files except the entry plist are located inside the bundle. The following example shows an entry plist for loading a [[PreferenceBundles|PreferenceBundle]]:
+
You can create custom settings pages that are able to execute code. This only requires a plist that loads a [[PreferenceBundles|PreferenceBundle]]. Here's an example:
  
 
<source lang="xml">
 
<source lang="xml">
Line 86: Line 108:
 
<plist version="1.0">
 
<plist version="1.0">
 
<dict>
 
<dict>
  <key>entry</key>
+
<key>entry</key>
  <dict>
+
<dict>
      <key>bundle</key>
+
<key>cell</key>
      <string>TestSettings</string>
+
<string>PSLinkCell</string>
      <key>cell</key>
+
<key>label</key>
      <string>PSLinkCell</string>
+
<string>Test</string>
      <key>icon</key>
+
<key>icon</key>
      <string>TestIcon.png</string>
+
<string>TestIcon.png</string>
      <key>isController</key>
+
<key>isController</key>
      <true/>
+
<true/>
      <key>label</key>
+
<key>bundle</key>
      <string>Test</string>
+
<string>TestSettings</string>
  </dict>
+
</dict>
 
</dict>
 
</dict>
 
</plist>
 
</plist>
 
</source>
 
</source>
  
A skeleton [[PreferenceBundles|PreferenceBundle]] project can be found at http://www.volatile-dev.com/PreferenceLoader/TestSettings.zip
+
This sets up an entry called <code>Test</code> with an icon loaded from <code>TestIcon.png</code> to the left. The rest of the details are up to the bundle named <tt>TestSettings</tt>.
==Filtering<ref name="2.2.0-1">PreferenceLoader version 2.2.0-1 and later</ref>==
+
 
 +
== Filtering<ref name="2.2.0-1">PreferenceLoader version 2.2.0-1 and later</ref> ==
 +
 
 
In a way similar to that of [[MobileSubstrate#MobileLoader|MobileSubstrate]], developers may add filters to entry plists and specifiers within simple and localized simple preferences. The filter should be a dictionary at the top level of the entry plist, or within a specifier, which can contain these keys:
 
In a way similar to that of [[MobileSubstrate#MobileLoader|MobileSubstrate]], developers may add filters to entry plists and specifiers within simple and localized simple preferences. The filter should be a dictionary at the top level of the entry plist, or within a specifier, which can contain these keys:
* '''CoreFoundationVersion''' (array): The entry or specifier is loaded or displayed only if the version of [[CoreFoundation.framework]] is above the specified values. Currently, only the first 2 values are checked.
+
* '''CoreFoundationVersion''' (array): The entry or specifier is loaded or displayed only if the version of [[CoreFoundation.framework]] is above the specified value or within the specified range. Currently, only the first 2 values are checked.
 
{{CoreFoundation Version Table|center=1}}
 
{{CoreFoundation Version Table|center=1}}
 +
 
Below sample specifier will be filter for iOS 6.0 or later.
 
Below sample specifier will be filter for iOS 6.0 or later.
 
<source lang="xml">
 
<source lang="xml">
 
<dict>
 
<dict>
  <key>cell</key>
+
<key>cell</key>
  <string>PSSwitchCell</string>
+
<string>PSSwitchCell</string>
  <key>default</key>
+
<key>defaults</key>
  <true/>
+
<string>com.test.TestSettings</string>
  <key>defaults</key>
+
<key>label</key>
  <string>com.test.TestSettings</string>
+
<string>Test Setting</string>
  <key>key</key>
+
<key>key</key>
  <string>testKey</string>
+
<string>testKey</string>
  <key>label</key>
+
<key>default</key>
  <string>Test Setting</string>
+
<true/>
  <key>pl_filter</key>
+
<key>pl_filter</key>
  <dict>
+
<dict>
    <key>CoreFoundationVersion</key>
+
<key>CoreFoundationVersion</key>
    <array>
+
<array>
      <string>793.00</string>
+
<string>793.00</string>
    </array>
+
</array>
  </dict>
+
</dict>
 
</dict>
 
</dict>
 
</source>
 
</source>
  
==Issues with OS 3.2 and 4.0==
+
== Issues with OS 3.2 and 4.0 ==
 
<tt>PSViewController</tt> underwent a massive change after 3.1, breaking all custom subclasses on the iPad and on 4.0 - it is now a UIViewController.
 
<tt>PSViewController</tt> underwent a massive change after 3.1, breaking all custom subclasses on the iPad and on 4.0 - it is now a UIViewController.
  
Line 138: Line 163:
 
- (id) specifiers {
 
- (id) specifiers {
 
if (!_specifiers){
 
if (!_specifiers){
    _specifiers = [[self loadSpecifiersFromPlistName: kNameOfPreferencesPlist target: self] retain];
+
_specifiers = [[self loadSpecifiersFromPlistName: kNameOfPreferencesPlist target: self] retain];
 
}
 
}
 
 
Line 145: Line 170:
 
</source>
 
</source>
  
==Notes==
+
== Notes ==
 
<references />
 
<references />
  
==References==
+
== References ==
 
<div class="references-2column">
 
<div class="references-2column">
 
* [[Preferences specifier plist]]
 
* [[Preferences specifier plist]]

Revision as of 21:39, 31 July 2014

PreferenceLoader
PrefLoaderScreenshot.png
Cydia Package
Developer Dustin Howett
Package ID preferenceloader
Latest Version 2.2.0-1


PreferenceLoader is an open-source[1] MobileSubstrate based utility that allows developers to add entries to the Settings application, similar to the Settings bundles that AppStore apps use.

The approach PreferenceLoader takes is different from other approaches in that the Settings-iPhone.plist and Settings-iPod.plist files are not modified on disk. When the Settings application is loaded, entries are read from plists in /Library/PreferenceLoader/Preferences/ and are dynamically added to the list before the AppStore applications' preferences group.

PreferenceLoader also allows PreferenceBundles to be loaded from /Library/PreferenceBundles/[2][3].

Entry file

Each entry is defined in its own plist. There are at least three ways to approach preferences support for your tweaks.

Reduced approach

Provides a switch on the root section of the preferences (like Airplane Mode). Recommended for configuration-less tweaks.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>entry</key>
	<dict>
		<key>cell</key>
		<string>PSSwitchCell</string>
		<key>defaults</key>
		<string>com.test.TestSettings</string>
		<key>label</key>
		<string>Test</string>
		<key>key</key>
		<string>enabled</string>
		<key>default</key>
		<true/>
		<key>icon</key>
		<string>TestIcon.png</string>
		<key>PostNotification</key>
		<string>com.test.TestSettings/preferences.changed</string>
	</dict>
</dict>
</plist>

This sets up an entry called Test with an icon loaded from TestIcon.png to the left and a UISwitch on the right, starting in the ON position, saving the value in [NSHomeDirectory() stringByAppendingFormat:@"/Library/Preferences/%s.plist", "com.test.TestSettings"] for the key enabled and posting a Darwin notification named com.test.TestSettings/preferences.changed.

Simple Approach

Provides a pane where other cells can appear (like Wi-Fi). Recommended for configuration-friendly tweaks. Here's an example:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>entry</key>
	<dict>
		<key>cell</key>
		<string>PSLinkCell</string>
		<key>icon</key>
		<string>TestIcon.png</string>
		<key>label</key>
		<string>Test</string>
	</dict>
	<key>title</key>
	<string>Test Settings</string>
	<key>items</key>
	<array>
		<dict>
			<key>cell</key>
			<string>PSSwitchCell</string>
			<key>defaults</key>
			<string>com.test.TestSettings</string>
			<key>key</key>
			<string>enabled</string>
			<key>label</key>
			<string>Enabled</string>
			<key>default</key>
			<true/>
			<key>PostNotification</key>
			<string>com.test.TestSettings/preferences.changed</string>
		</dict>
	</array>
</dict>
</plist>

This sets up an entry called Test with an icon loaded from TestIcon.png to the left. The pushed page has the title set to Test Settings. The page will only contain a cell with the label Enabled UISwitch on the right, starting in the ON position, saving the value in [NSHomeDirectory() stringByAppendingFormat:@"/Library/Preferences/%s.plist", "com.test.TestSettings"] for the key enabled and posting a Darwin notification named com.test.TestSettings/preferences.changed.

For more preferences values you can add specifier dictionaries to the items array.

There is a good tutorial on how to create settings plists on MMi.

Localization[2]

Instead of placing the entry plist in /Library/PreferenceLoader/Preferences/, place it in a subfolder in that directory along with the .lproj folders containing a strings file named Localizable.strings.

PreferenceBundle Approach

You can create custom settings pages that are able to execute code. This only requires a plist that loads a PreferenceBundle. Here's an example:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>entry</key>
	<dict>
		<key>cell</key>
		<string>PSLinkCell</string>
		<key>label</key>
		<string>Test</string>
		<key>icon</key>
		<string>TestIcon.png</string>
		<key>isController</key>
		<true/>
		<key>bundle</key>
		<string>TestSettings</string>
	</dict>
</dict>
</plist>

This sets up an entry called Test with an icon loaded from TestIcon.png to the left. The rest of the details are up to the bundle named TestSettings.

Filtering[4]

In a way similar to that of MobileSubstrate, developers may add filters to entry plists and specifiers within simple and localized simple preferences. The filter should be a dictionary at the top level of the entry plist, or within a specifier, which can contain these keys:

  • CoreFoundationVersion (array): The entry or specifier is loaded or displayed only if the version of CoreFoundation.framework is above the specified value or within the specified range. Currently, only the first 2 values are checked.
Firmware CoreFoundation version
2.0 478.23
2.1 478.26.1
2.2 478.29
3.0 478.47.7
3.1 478.52
3.2 478.61
4.0 550.32
4.1 550.38.1
4.2 550.52
4.3 550.58.1
5.0 675.00
5.1 690.10
6.0 793.00
6.1 793.00
7.0 847.20
7.1 847.24
8.0 1140.10
8.1 1141.14
8.2 1142.16
8.3 1144.17
8.4 1145.15
9.0 1240.10
9.1 1241.11
9.2 1242.13
9.3 1280.38
10.0 1348.00
10.1 1348.00
10.2 1348.22
10.3 1349.56
11.0 1443.00
11.1 1445.32
11.2 1450.14
11.3 1452.23
11.4 1452.23
12.0 1556.00
12.1 1560.10
12.2 1570.15
12.3 1575.13
12.4 1575.17
12.5 1575.23
13.0 1665.15
13.1 1671.101
13.2 1673.126
13.3 1674.102
13.4 1675.129
13.5 1676.104
13.6 1677.104
13.7 1677.104
14.0 1751.108
14.1 1751.108
14.2 1770.106
14.3 1770.300
14.4 1774.101
14.5 1775.118
14.6 1776.103
14.7 1777.103
14.8 1778.101
15.0 1854
15.1 1855.105
15.2 1856.105
15.3 1856.105
15.4 1858.112

Below sample specifier will be filter for iOS 6.0 or later.

<dict>
	<key>cell</key>
	<string>PSSwitchCell</string>
	<key>defaults</key>
	<string>com.test.TestSettings</string>
	<key>label</key>
	<string>Test Setting</string>
	<key>key</key>
	<string>testKey</string>
	<key>default</key>
	<true/>
	<key>pl_filter</key>
	<dict>
		<key>CoreFoundationVersion</key>
		<array>
			<string>793.00</string>
		</array>
	</dict>
</dict>

Issues with OS 3.2 and 4.0

PSViewController underwent a massive change after 3.1, breaking all custom subclasses on the iPad and on 4.0 - it is now a UIViewController.

Improper implementations of PSListController subclasses will fail to work properly on 4.0. You must set _specifiers within the -(id) specifiers method (instead of returning a different array of specifiers.) This is because OS 4.0 relies on _specifiers to generate specifier metadata and group indices. Example:

- (id) specifiers {
	if (!_specifiers){
		_specifiers = [[self loadSpecifiersFromPlistName: kNameOfPreferencesPlist target: self] retain];
	}
		
	return _specifiers;
}

Notes

  1. PreferenceLoader Source
  2. 2.0 2.1 PreferenceLoader version 1.2 and later
  3. Bundles can also be loaded from /System/Library/PreferenceBundles/, but this is no longer the preferred method as of PreferenceLoader 1.2
  4. PreferenceLoader version 2.2.0-1 and later

References