A modern AppList alternative for iOS

AltList

A modern AppList alternative

The main focus of this dependency is to be an easy to use and easy to customize framework to handle per app preferences.
Unlike AppLists ALApplicationList class, AltList does not have a way to get installed applications yourself, as stock iOS classes like LSApplicationWorkspace and LSApplicationProxy (MobileCoreService / CoreServices framework) can already do that. Communication to SpringBoard is not needed for this.

Example uses:

// get LSApplicationProxy of all installed applications
NSArray<LSApplicationProxy*>* allInstalledApplications = [[LSApplicationWorkspace defaultWorkspace] atl_allInstalledApplications];

// get LSApplicationProxy for one application
LSApplicationProxy* appProxy = [LSApplicationProxy applicationProxyForIdentifier:@"com.yourapp.yourapp"];

Features

  • Uses LSApplicationWorkspace, not dependent on RocketBootstrap / SpringBoard injection
  • Supports search bars
  • Supports application sections (similar to AppList)
  • Supports alphabetic indexing if only one section is specified
  • Doesn't reinvent the wheel
  • Supports iOS 7 and up

Installation

Run install_to_theos.sh and add it to the makefile of your project:

<YOUR_PROJECT>_EXTRA_FRAMEWORKS = AltList

Then you can import it using #import <AltList/AltList.h> or just use the classes below in your preferences plist.

Documentation

AltList features three PSListController subclasses that can be used from your preference bundle or application.
Unlike AppList it is highly customizable, so if you want to adapt something you can just make a subclass and specify that instead.

All classes can be configured via values in your plist.

Plist-Only approach

For very simple preferences, it is possible to use AltList straight from your entry.plist without implementing any class. For an example check out AltListTestBundlelessPreferences.

ATLApplicationSection

Just like the original AppList, AltList allows you to specify the sections of applications it should display.

AltList ships with a few stock section types:

  • All: All Applications, including hidden ones
  • System: System Applications (e.g. App Store, Safari)
  • User: User installed applications (e.g. Reddit, Instagram)
  • Hidden: Hidden applications (e.g. InCallService, Carplay Settings)
  • Visible: All applications that are not hidden (e.g. System and User applications)

The stock section types already have predicates and localized names.
Custom sections are also supported and allow you to specify your own section name and predicate.
If you want your custom section name to be localized: the value you set will be passed to the localizedStringForString of your ListController (see below).

Key Type Fallback Usage
sectionType String (All/System/User/Hidden/Visible/Custom) Visible Type of the section, see above
sectionName String @"" For custom sections, name of the section
sectionPredicate String @"" For custom sections, predicate to filter the applications, check out the LSApplicationProxy headers for possible values to use
customClass String @"" Custom subclass of ATLApplicationSection to use, in case you want to implement even more custom behaviour

ATLApplicationListControllerBase

ATLApplicationListControllerBase is the base class inherited by the other classes, it has several features that apply to all classes below.

Keys

Key Type Fallback Usage
sections Array One Visible section Array of dictionaries that represent the sections in which the applications are shown
useSearchBar Boolean false Whether there should be a search bar at the top that allows to search for applications (Example)
hideSearchBarWhileScrolling Boolean false When useSearchBar is enabled, whether the search bar should be hidden while scrolling (Always true on iOS 10 and below) (Example)
includeIdentifiersInSearch Boolean false When useSearchBar is enabled, whether it should be possible to search for apps by their identifier. When this is false, it is only possible to search for apps by their name.
showIdentifiersAsSubtitle Boolean false Whether the application identifiers should be shown in the subtitle (Example)
alphabeticIndexingEnabled Boolean false When there is only one section, whether to section and index it by the starting letters (Example)
hideAlphabeticSectionHeaders Boolean false When alphabeticIndexingEnabled is true, whether to hide the sections that contain the first letters (Example)
localizationBundlePath String @"" Path to the bundle that should be used for localizing custom section titles

Methods (Can be subclassed for customization)

Method Purpose
- (void)loadPreferences Load the preference value that the list controller will display
- (void)prepareForPopulatingSections Initialize stuff that needs to be done before the populating starts
- (NSString*)localizedStringForString:(NSString*)string Localize string if possible from internal AltList bundle or the localization bundle specified by localizationBundlePath
- (void)reloadApplications Reload applications and specifiers
- (BOOL)shouldHideApplicationSpecifiers Whether any specifier at all should be hidden (internally used for search bar)
- (BOOL)shouldHideApplicationSpecifier:(PSSpecifier*)specifier Whether the specifier specifier should be hidden (internally used for search bar)
- (BOOL)shouldShowSubtitles Whether subtitles should be shown on the application cells
- (NSString*)subtitleForApplicationWithIdentifier:(NSString*)applicationID The subtitle that should be displayed in the cell for the specific application that's passed as applicationID
- (PSCellType)cellTypeForApplicationCells Cell type for the application cells
- (Class)customCellClassForCellType:(PSCellType)cellType Custom cell class for the application cells
- (Class)detailControllerClassForSpecifierOfApplicationProxy:(LSApplicationProxy*)applicationProxy detailControllerClass to be used by the application specifiers
- (SEL)getterForSpecifierOfApplicationProxy:(LSApplicationProxy*)applicationProxy getter to be used by the application specifiers
- (SEL)setterForSpecifierOfApplicationProxy:(LSApplicationProxy*)applicationProxy setter to be used by the application specifiers
- (PSSpecifier*)createSpecifierForApplicationProxy:(LSApplicationProxy*)applicationProxy Create a specifier for the application represented by applicationProxy
- (NSArray*)createSpecifiersForApplicationSection:(ATLApplicationSection*)section Create the specicifers for a whole application section represented by section (Calls the method above)

ATLApplicationListSelectionController

ATLApplicationListSelectionController can be used as the detail class of a PSLinkListCell to have a list of applications of which one can be selected.
The selected applications bundle identifier will be saved in the preference domain specified via defaults under the specified key.
It respects the get / set attributes so by default it will use the readPreferenceValue and setPreferenceValue:specifier: methods of the PSListController that contains the cell for reading / writing the value.
Setting the cellClass to ATLApplicationSelectionCell is recommended so the value preview shows the application name instead of the application bundle identifier.

Example

<dict>
	<key>cell</key>
	<string>PSLinkListCell</string>
	<key>detail</key>
	<string>ATLApplicationListSelectionController</string>
	<key>cellClass</key>
	<string>ATLApplicationSelectionCell</string>
	<key>defaults</key>
	<string>com.yourcompany.yourtweakprefs</string>
	<key>key</key>
	<string>(...)</string>
	<key>label</key>
	<string>(...)</string>
	<key>sections</key>
	<array>
		<dict>
			<key>sectionType</key>
			<string>System</string>
		</dict>
		<dict>
			<key>sectionType</key>
			<string>User</string>
		</dict>
	</array>
	<key>useSearchBar</key>
	<true/>
	<key>hideSearchBarWhileScrolling</key>
	<false/>
</dict>

ATLApplicationListMultiSelectionController

ATLApplicationListSelectionController can be used as the detail class of a PSLinkListCell to have a list of applications where each has a switch next to it.
The key defaultApplicationSwitchValue can be set to a boolean and will be used as the default value of the application switches.
An array with the application identifiers of the enabled (or disabled when defaultApplicationSwitchValue is true) applications will be saved in the preference domain specified via defaults under the specified key.
It respects the get / set attributes so by default it will use the readPreferenceValue and setPreferenceValue:specifier: methods of the PSListController that contains the cell for reading / writing the value.

Keys

Key Type Fallback Usage
defaultApplicationSwitchValue Boolean false Default value of the application switches

Example

<dict>
	<key>cell</key>
	<string>PSLinkListCell</string>
	<key>detail</key>
	<string>ATLApplicationListMultiSelectionController</string>
	<key>defaults</key>
	<string>(...)</string>
	<key>key</key>
	<string>(...)</string>
	<key>label</key>
	<string>(...)</string>
	<key>sections</key>
	<array>
		<dict>
			<key>sectionType</key>
			<string>Visible</string>
		</dict>
		<dict>
			<key>sectionType</key>
			<string>Hidden</string>
		</dict>
	</array>
	<key>showIdentifiersAsSubtitle</key>
	<true/>
	<key>defaultApplicationSwitchValue</key>
	<false/>
	<key>useSearchBar</key>
	<true/>
</dict>

ATLApplicationListSubcontrollerController

ATLApplicationListSubcontrollerController can be used as the detail class of a PSLinkListCell to have one PSListController per application.
The key subcontrollerClass is used to specify the PSListController subclass, although you can also subclass ATLApplicationListSubcontroller instead which has a convienience method to get the application identifier and also automatically reloads the preview string shown in the application list.
Preview strings are supported but require you to subclass ATLApplicationListSubcontrollerController and use your subclass instead. In your subclass you need to overwrite the previewStringForApplicationWithIdentifier: method and return the preview string there.
Preferences also need to be handled in your PSListController/ATLApplicationListSubcontrollerController subclass, if you want an example for this, check out the Choicy preferences.

Keys

Key Type Fallback Usage
subcontrollerClass String None (Required) Name of the class that should be used for the application subpages

Example

<dict>
	<key>cell</key>
	<string>PSLinkListCell</string>
	<key>detail</key>
	<string>ATLApplicationListSubcontrollerController</string>
	<key>subcontrollerClass</key>
	<string>(...)</string>
	<key>label</key>
	<string>(...)</string>
	<key>sections</key>
	<array>
		<dict>
			<key>sectionType</key>
			<string>Visible</string>
		</dict>
		<dict>
			<key>sectionType</key>
			<string>Hidden</string>
		</dict>
	</array>
	<key>showIdentifiersAsSubtitle</key>
	<true/>
	<key>useSearchBar</key>
	<true/>
</dict>

GitHub

https://github.com/opa334/AltList