Reading view

There are new articles available, click to refresh the page.

What is a bundle, and how are frameworks different?

Apps, frameworks and other items come in bundles, structured hierarchies of folders and files that look like a single file in the Finder. This article explains what bundles are and shows how they are structured.

Bundles came to Mac OS X from its NeXTSTEP parent, not Classic Mac OS. The latter assembled its apps from many resources stored in the app’s resource fork. NeXTSTEP and Mac OS X instead built their apps from component files arranged in a series of directories. Those bundles gathered together all the files required for apps and similar items, into what was then presented to the user as a single item. Modern app bundles are descended from ‘new-style’ bundles introduced in Mac OS X, which had a minimum requirement of a top-level folder named Contents, and inside that a property list named Info.plist.

Bundles and packages

When a folder has a name with an extension for a standard bundle type, such as .app, .bundle, .plugin or .kext, the Finder will display and treat it as if it were a file, also offering to Show Package Contents in its contextual menu. For historical reasons, bundles with the extension .framework aren’t treated as bundles, but are displayed and navigated as if they were still folders.

Although bundles have similarities with packages, Apple draws a clear distinction between them, even if the Finder doesn’t. Directory-based documents and similar items that are used to contain multiple files for Rich Text Format Directory (RTFD) and other documents don’t conform to the rules for bundles, and should be referred to as packages to avoid confusion. Look inside an RTFD package, for example, and you’ll see the structure:

  • Contents, a directory containing a PkgInfo file
  • files containing graphics to be included within the documents
  • TXT.rtf, a Rich Text Format file containing the styled text.

which has some common features, but is structured differently and lacks both an Info.plist file and executable code.

Apps and frameworks

The fundamental requirements for an app or related bundle, including those for app extensions or appexes, are:

  • The whole bundle’s contents are within a single top-level folder named Contents.
  • Within Contents is an Info.plist property list containing information and settings for the bundle.
  • There’s executable code, normally in the form of a Mach-O binary inside the MacOS folder.
  • For historical and compatibility reasons, there’s a PkgInfo file containing a Classic Mac OS type and creator code for the bundle, e.g. APPL and ???? for an app.

However, frameworks have a different and more complex structure, lacking a Contents folder, providing at least one version of the framework, and burying the Info.plist file deeper in the hierarchy. This is shown in full later.

App bundles can contain frameworks and other app bundles, as can framework bundles. In the worst case you may need to dive deep into a series of folder hierarchies to reach your goal.

Info.plist

The information property list Info.plist contains key-value pairs in XML format, for attributes such as:

  • bundle name (CFBundleName),
  • name of bundle executable (CFBundleExecutable),
  • version (CFBundleShortVersionString),
  • document types handled by the app (CFBundleDocumentTypes),
  • app identifier (CFBundleIdentifier),
  • other metadata.

Because of the importance of its contents, code signatures protect the Info.plist from being changed in any way.

App bundle

In addition to the minimum requirements of an Info.plist, executable code, and PkgInfo file inside its Contents folder, apps almost invariably contain several additional folders, among them:

  • Resources is universal, and contains any of a rich range of images, localised versions of menu and other text contents, the app icon and any for custom document types, storyboards for GUI elements, Help books, and more.
  • PlugIns is now common, to contain appexes in particular.
  • Library, containing one or more sub-folders with QuickLook and Spotlight support for custom document types, any login items or property lists for LaunchServices, and other support and extensions for the main app.
  • Apps obtained through the App Store should contain a _MASReceipt folder with the store receipt inside it.
  • Signed apps will have a _CodeSignature folder containing the CodeResources file with signature data.
  • Notarized apps may have a notarization ticket in a CodeResources file, but that isn’t required for notarization to work.
  • Some apps may have an embedded.provisionprofile file containing their provisioning profile.
  • Other folders, such as Frameworks for nested framework bundles.

This layout is shown below, with the essentials in light red.

Framework bundle

In comparison, framework bundles are deeper, lack a top-level Contents folder, contain at least one version of the framework (although two or more are now exceptional), and come with symbolic links. This is shown below, again with the essentials in light red.

Three symlinks merit explanation:

  • Versions/Current links to A, the current (and only) version of the framework.
  • a symlink with the same name as the framework’s code is at the top level of the bundle, alongside the Versions folder. That links through the Current symlink, giving the path Current/A/.
  • a symlink named Resources is also at the top level of the bundle, alongside the Versions folder. That too links through the Current symlink, giving the path Current/A/Resources.

Thus paths to the Info.plist file include Resources ➜ Info.plist via the top-level Resources symlink, Versions/Current ➜ Resources via the Current symlink, and Versions/A/Resources without using any symlinks. This demonstrates how confusing this layout can appear in the Finder.

Frameworks commonly include other nested frameworks, appexes in their PlugIns folder, and a diverse range of other resources including localisations in the Resources folder.

Conclusions

  • Bundles are formal structures of folders and files used for apps and their relatives, and for frameworks. Packages used for RTFD and other documents have different structural requirements.
  • App bundles have a top-level Contents folder, inside which is an Info.plist property file, and executable code inside a MacOS folder.
  • Framework bundles don't have a Contents folder, but contain versions of the framework, normally only one named A. They use important symlinks to provide standard access paths to their contents, and their Info.plist file is inside their Resources folder.
  • Info.plist files and other contents are protected by code signatures and can't be modified without breaking the signature. However, they contain valuable information about the app or framework.
  • Building bundles by hand is prone to error, causing bugs. When possible, leave it to Xcode.

Reference

Apple's instructions for developers.

An overview of app extensions and plugins in macOS Sequoia

With well over 400 app extensions and plugins managed by PlugInKit in Sequoia 15.4.1, this article tries to give an overview of their management and control, as well as the diversity of their functions. This follows:

Appex types

Although Apple refers to the type identifier for appexes as NSExtensionPointIdentifier in its developer documentation, where it lists some of them, in macOS this is also synonymous with NSExtensionPointName. In pluginkit dumps, it’s referred to as the SDK, and LaunchServices dumps use both terms, NSExtensionPointName in NSExtensionsAttributes, and NSExtensionPointIdentifier in NSExtension. This is even more confused in the log, where PlugInKit’s entries use the term NSExtensionPointName, but use NSExtensionIdentifier to refer instead to the appex-specific identifier, such as com.apple.iCal.CalendarWidgetExtension.

For the sake of clarity and consistency here, I’ll refer to the appex type identifier as NSExtensionPointName.

Appex locations

Many appexes supplied in macOS are stored as bundles inside dedicated collections such as /System/Library/ExtensionKit/Extensions or in frameworks. Where they are supplied in an app or similar bundle, they’re normally in a PlugIns folder, although according to this article QuickLook generators should be installed in Library/QuickLook, and Spotlight importers in Library/Spotlight.

Types and management

The rest of this article lists appex types, omitting the universal prefix com.apple., according to their management and discovery by PlugInKit during startup. I provide for each, as far as I’m able to tell, the type-specific manager, any controls provided in System Settings or elsewhere, and illustrative examples and other relevant information.

Type-specific managers are those services or subsystems that PlugInKit hands over to during discovery. For example, when it discovers appexes that extend QuickLook by providing either thumbnails or previews, PlugInKit hands those over to com.apple.quicklook.ThumbnailsAgent to manage.

Many appex types aren’t exposed in System Settings, are managed by PlugInKit, but don’t appear to undergo startup discovery. I have relegated those to the appendix at the end. Most of those are single-appex types, and others are only used by macOS.

Appex types that are managed in System Settings and by PlugInKit, and undergo startup discovery:

  • FinderSync, managed by the Finder, and controlled in File Providers settings, e.g. Keka Finder Integration
  • quicklook.preview, managed by com.apple.quicklook.ThumbnailsAgent, and controlled in Quick Look settings; these are modern substitutes for qlgenerators
  • quicklook.thumbnail, managed by com.apple.quicklook.ThumbnailsAgent, and controlled in Quick Look settings; these are modern substitutes for qlgenerators
  • ui-services, managed by the Finder, and controlled in Actions settings, includes Markup, ShareSheetUI (not exposed in settings)

Appex types that aren’t managed in System Settings, but are managed by PlugInKit, and undergo startup discovery:

  • AppSSO.idp-extension, managed by AppSSOAgent, includes Kerberos and Sign In With Apple; these are single-sign-on extensions
  • appstored-services.testflight, managed by appstoreagent; these handle App Store TestFlight
  • AudioUnit, managed by AudioComponentRegistrar and axassetsd, for WardaSynthesizer
  • AudioUnit-Speech, managed by AudioComponentRegistrar and axassetsd, include KonaSynthesizer and AUSPs
  • AudioUnit-UI, managed by AudioComponentRegistrar
  • cache_delete_extension, managed by deleted; these support app-specific cache management
  • contacts.donation, managed by contactsdonationagent; these exchange info with Contacts
  • ctk-tokens, managed by ctkd, include CryptoTokenKit and PlatformSSOToken; these handle tokens for CryptoTokenKit
  • diagnosticextensions-service, managed by ControlCenter and diagnosticextensionsd, includes many service-specific Diagnostic Extensions
  • email.extension, managed by maild, e.g. SpamSieve; these are Mail plugins
  • fileprovider-nonui, managed by the Finder, includes iCloud Drive and PhotosFileProvider
  • services, managed by the Finder; none listed
  • spotlight.import, managed by mdbulkimport, includes PDFImporter
  • spotlight.index, managed by corespotlightd, includes system extensions but not mdimporters
  • textinputmethod-services, managed by imklaunchagent, includes many Input Methods
  • usernotifications.content-extension, managed by NotificationCenter, includes ContentExtensions
  • widgetkit-extension, managed by chronod, includes system and third-party widgets.

Significant appex types that are managed by PlugInKit, but don’t undergo startup discovery:

  • appintents-extension, multiple instances
  • intents-service, many IntentsExtensions
  • photo-editing, Photos editing, controlled in Photos Editing settings
  • Safari.extension, Safari extensions, managed in Safari settings
  • share-services, many Share extensions, managed in Sharing settings
  • widget-extension, only a couple, e.g. iStat Menus.

Appex types that apparently aren’t managed by PlugInKit, but are controlled in System Settings:

  • Dock Tiles
  • Finder, these are services offered in the Finder’s Services menu
  • Spotlight, these are mdimporters.

also Safari.content-blocker, which is managed in Safari settings rather than System Settings.

Appex types that aren’t apparently managed by PlugInKit or controlled in System Settings:

  • authentication-services-account-authentication-modification-ui
  • authentication-services-credential-provider-ui
  • broadcast-services-setupui
  • broadcast-services-upload
  • callkit.call-directory
  • classkit.context-provider
  • dt.Xcode.extension.source-editor
  • fileprovider-actionsui
  • identitylookup.classification-ui
  • identitylookup.message-filter
  • intents-ui-service
  • keyboard-service
  • networkextension.app-proxy
  • photo-project
  • tv-top-shelf

Appendix:

Appex types that aren’t exposed in System Settings, are managed by PlugInKit, but don’t undergo startup discovery

System, multiple appexes:
followup-extension – multiple FollowUpExtensions
lighthouse.SAOrchestratedExtension – multiple Ingestors
message-payload-provider – multiple
mlhost.worker – many ML-related
mlruntime.extension-point-high
mlruntime.extension-point-ondemand
mlruntime.extension-point-restricted
screensaver – several ScreenSavers
Settings.extension.ui – System Settings
storagemanagement – many apps
usernotifications.service – several NotificationServiceExtensions
wallpaper – several Wallpapers

System, single-app extensions:
amsengagementd-extension – Books, News
amsutility-extension – News
app.non-ui-extension – Swift Playground
app.non-ui-extension.multiple-instances – Swift Playground
app.ui-extension.multiple-instances – Swift Playground
applemediaservices.extensions.compose-review – ComposeReviewExtension
askpermission-extension – App Store related
askto.extension – AskToMessagesHost
calendar.EventKitUIRemoteUIService – EventKitUIRemoteUIExtension
calendar.virtualconference – FaceTimeExtension
contact-view – System Service
contacts.avatar-picker-ui – AvatarPickers
deviceactivity.monitor-extension – ScreenTimeDeviceActivityMonitorExtension
deviceactivityui.report-service – DeviceActivityReportService
extension-view-service-sample-rk – RPVideoEditorExtension_macOS, ReplayKit
extensionkit.app-extension-management – AppExtensionManagement
extensionkit.app-extension-settings – ExtensionKit components
facetime.notification – FaceTimeNotificationExtension
feedback.drafting-extension – Feedback
freeform.USD-renderer-remote-UI – USDRendererExtension
fskit.fsmodule – exfat and msdos file systems (File System Extensions)
GenerativePlaygroundUI.remoteUI – Image Playground
groupactivities – FaceTime RemotePeoplePicker
Home.ui-extension.userList – HomeUIUserList
ImagePlayground.NonUIExtension – GPNonUIExtension
ManagedSettings.service – ManagedClientMSExtension
mapkit.private.RemoteUI – MKRemoteUI for MapKit
mobileslideshow.photo-picker – PhotoPicker and PhotosPicker
networkextension.packet-tunnel – network extensions
PaperKit.extension.ui – PaperKitExtension
PassKit.in-app-payment-ui – Wallet
pdfkit-private – PDFExtensionView in PDFKit
people-picker – System Service
people.legacy.extension – PeopleLegacyMessageService
Photos.MacMusicPickerExtension – PhotosMacMusicPickerExtension
preference.security.privacy – Apple Advertising
preference.sharing.service – Media Sharing
private.translation-api-support – TranslationAPISupportExtension
private.translation-ui – Translate
private.voiceshortcuts-ui – three extensions
replaykit.broadcast-picker – RPBroadcastActivityExtension_macOS in ReplayKit
screentime.web-service – ScreenTimeWebExtension.

How PlugInKit enables app extensions

App extensions or appexes perform a wide range of tasks, from providing support for file systems like ExFAT to generating thumbnails for QuickLook and enabling Spotlight to index the contents of files. Although they’re relatively old, macOS made major changes in their management in Ventura, and they’ve become popular in many third-party apps. Despite that, there’s remarkably little information about how appexes are managed. As a result, when they play up it’s not clear what you should do. This article tries to disperse that cloud of unknowing.

There are four relatively unknown services responsible for managing apps, their extensions and related services:

  • LaunchServices, which plays a prominent part in managing app launch, and maintains a large and comprehensive database of information about known apps and their extensions;
  • RunningBoard, which manages resources such as memory and GPU access for some apps and their extensions;
  • PlugInKit, which manages appexes for QuickLook, Spotlight, and many other services;
  • Duet Activity Scheduler (DAS), which dispatches and manages background activities.

At the heart of PlugInKit is its management daemon pkd, in /usr/libexec, which relies on working files and folders buried in a locked directory deep in /var/folders. It maintains its own registry of appexes, to which it adds annotations such as when they were last managed, and whether they have been ‘elected’. You can follow activities in the log using the subsystem com.apple.PlugInKit, and exchanges with com.apple.launchservices and PlugInKit’s client services such as com.apple.quicklook.ThumbnailsAgent, responsible for the generation of QuickLook thumbnails for files.

Discovery

Of the four services, only LaunchServices appears to maintain a database that persists across restarts, although it’s rumoured to be stored over more than one database. RunningBoard maintains a list of running processes, DAS maintains a list of activities that it’s scheduled to dispatch, and PlugInKit keeps a registry of appexes, but each of those appears to be built from scratch during startup.

Shortly after user login, PlugInKit is initialised and starts populating its registry by a process of discovery, apparently deriving its information from the LaunchServices database, where each installed appex is detailed. Among the information stored there for appexes is their PlugInKit dictionary (PKDict) with the NSExtensionPointIdentifier that sets what type of appex it is, and their SDK data, repeating that type information as the NSExtensionPointName.

PlugInKit looks up batches of appexes to register, grouped according to their NSExtensionPointName. The first of these is com.apple.textinputmethod-services, providing text input methods such as Vietnamese and Traditional Chinese. After those come com.apple.FinderSync and com.apple.fileprovider-nonui, and so on through a set sequence until ending with com.apple.widgetkit-extension.

Log entries for this discovery phase are remarkable as, provided appexes haven’t changed in the LaunchServices database, entries by PlugInKit are almost identical during every startup. This stability is particularly helpful over appex UUIDs: so long as the appex remains the same, its UUID and order in discovery will be the same as well.

Coverage and versions

Particularly in recent versions of macOS, LaunchServices appears to cast its net widely, adding apps to its database from almost any accessible source. This results in some of the features it supports listing multiple versions of apps, some of which aren’t installed in traditional Applications folders.

PlugInKit’s coverage appears more focussed, and its rules over which appex to use ensure that old versions are excluded. Although old versions are registered during discovery, PlugInKit normally only offers the most recent version and, if there are multiple copies of that, the last registered by its timestamp in the registry. It’s also more conservative about which appexes it recognises: while LaunchServices will happily add apps that aren’t stored in an Applications folder and have never been opened on that Mac, PlugInKit appears more cautious in those it registers.

This is best illustrated in a VM with the host Applications folder shared. Initially, before that folder has been opened in the VM, apps and appexes inside it aren’t offered in the Finder’s Open With menu, and appexes such as a QuickLook thumbnail previewer can’t be used. When that shared folder has been opened in the Finder, LaunchServices makes its apps available through Open With. But the thumbnail previewer is only registered with PlugInKit when its shared parent app has been run in the VM.

Continuous discovery

In addition to startup discovery, PlugInKit has automatic continuous discovery during normal running. This can be seen best when an app containing an appex is installed and launched. LaunchServices adds the new app and its appex to its database, in what its log entries refer to as seeding. This is reported to PlugInKit, which then performs re-discovery for all appexes with the same NSExtensionPointName, so adding the new appex to its registry. During this, PlugInKit informs the service using that type of appex, triggering deployment of the capabilities of the new appex.

For example, launching a new app containing an appex with the NSExtensionPointName of com.apple.quicklook.thumbnail results in LaunchServices adding that app and its appex to its database, then PlugInKit performs another discovery of all appexes with that NSExtensionPointName. When the new appex is added to its registry, PlugInKit informs com.apple.quicklook.ThumbnailsAgent of the new QuickLook thumbnail previewer, so it can be made available for creating thumbnails almost immediately.

Discovery is readily traced in the log, but even simpler to follow by opening successive windows in AppexIndexer, and following the UUIDs given there.

Removal of an app with an enclosed appex is also quickly reflected in PlugInKit’s registry, and the appex’s service is informed immediately to ensure that no attempt is made to run the deleted extension.

Practical consequences

  • Features of appexes are made available by the subsystem they act in.
  • PlugInKit informs an appex’s subsystem of its availability during discovery.
  • PlugInKit’s discovery relies on updates to the LaunchServices database.
  • Damage to or dysfunction of the LaunchServices database can therefore block or impair PlugInKit registration, in turn preventing correct function of the appex.
  • Resetting the LaunchServices database will inevitably delay PlugInKit’s discovery, and could lead to malfunction of appexes, such as failure to generate QuickLook thumbnails.
  • Controlling appexes is currently only available in System Settings > General > Login Items & Extensions.
  • Controlling appexes using the pluginkit command tool is only temporary, and any changes made there will be reverted in subsequent discovery.
  • Investigating appex problems by examining com.apple.PlugInKit subsystem entries in the log is clear and straightforward, and individual appexes can readily be traced using their UUID.

AppexIndexer build 8 has sort and search features

I’m very grateful to all of you who looked at my little AppexIndexer, and particularly to those who commented and made suggestions. I’m delighted to come back with version 1.0 build 8, which I hope gets closer to what you’ll enjoy using. Its changes include:

  • Adding support for appex UUIDs. Although the log tends to censor most clues about which appex an entry is referring to, it’s more likely to give its UUID, and armed with AppexIndexer you can use that to identify the appex in question.
  • Providing a range of four sort orders. These are the SDK or type, the name of its parent app, the UUID, and the appex’s display name. Once you have loaded up the list of appexes, you can switch instantly between these sort orders.
  • ‘Live’ search for UUIDs, explained below.

Tools at the top of each window include the UUID search box at the top right, four radio buttons at the left to switch between sort orders, and checkboxes for the two content options of showing appex and parent paths, and UUIDs. Start by clicking on the Get Appexes button to populate the window, then you can set it up how you want.

To help distinguish the name of parent apps, there’s a ‘parent’ emoji preceding each. You’ll also notice that SDKs shown now omit the standard com.apple. opening, as that is universal.

As before, AppexIndexer supports mixtures of continuous and discontinuous selection. Copy those you want, and they’ll paste as text containing all the available fields, not just those being displayed at the time.

Search was quite a challenge, and my solution is inspired by that explained by Tiago Gomes Pereira in his Create with Swift blog.

SwiftUI Search on Lists and similar is nothing like macOS Find, and is better-suited to displaying those entries that match in a single field rather than in all their text content. With its new sort options, AppexIndexer should be quick and simple to locate appexes by all criteria except UUID. Rather than requiring the user to paste in the UUID they want to find, this ‘live’ search should produce perfect matches when you’ve only typed in a few characters from the target UUID. Those don’t have to be characters from the start, but can be any from within the UUID. For example, to find the appex with a UUID of E1366424-89DD-4CEB-85D8-C8E00928313F, you could start typing in e1366, or c8e00, etc., as you wish. You don’t need to use capitals either.

Typing the first couple of characters should narrow the list down quickly, and by the third or fourth you should have a perfect match. If you want to return to the full list of appexes, select that appex entry and empty the search box by clicking on the X button at its right and just that single entry will be selected in the full list.

If you type in an incorrect character, you’ll be informed that no results could be found.

AppexIndexer 1.0 build 8 is now available from here: appexindexer108
I’m afraid that it still requires Sonoma 14.6 or later, but hope that you find it efficient in use and a good tool for exploring appexes.

Enjoy!

Last Week on My Mac: Discovering discovery

Apps are getting ever more flexible, and in doing so they’re also becoming increasingly complex. Gone are the days when they mostly opened files, did things to them, and saved them again. We now expect to be able to use our favourite image editor from inside the Photos app, and to share documents between multiple apps, using features as services in reusable components.

For those of us who used OpenDoc back in the 1990s this is all familiar territory. Intended as Apple’s response to Microsoft’s OLE (Object Linking and Embedding), OpenDoc broke apps down to single-task components that worked together. This was best exemplified in the suite of Internet tools provided collectively as Cyberdog for a brief period in 1996-97. Those included a web browser, FTP and email clients, and a newsreader, that could be embedded in other apps that supported OpenDoc’s Bento format.

When Steve Jobs killed OpenDoc in 1997, few could have envisaged what was to come later in app extensions, or appexes, nor how extensively they have become used by macOS. From speech synthesisers and Blu-ray encoders to wallpapers and widgets, appexes have proliferated far beyond the wildest dreams of the OpenDoc designers, but so little is known about they’re managed by macOS.

macOS Sequoia keeps extensive registries of apps and appexes. The most detailed is the grand database maintained by LaunchServices, only visible through its hidden lsregister command tool. Appexes are the preserve of the PlugInKit registry, which can be dumped using the pluginkit tool. Resource management is performed by RunningBoard and appears inaccessible, as do the activity schedules managed by Duet Activity Scheduler (DAS).

All four registries appear to be constructed afresh during startup, in the case of LaunchServices and PlugInKit by a process of discovery, something I’ll be looking at in more detail in the near future. For PlugInKit, it’s discovery that determines which appex services are offered, whether they’re generators of QuickLook thumbnails or previews, Safari extensions, or file systems such as ExFAT or MS-DOS. The latter are refugees from their former existence as kernel extensions, a route now being followed by macFuse 5.0.

Although the user has limited control over those in System Settings and, in the case of Safari extensions, in Safari’s settings, the PlugInKit registry is designed to operate automatically. If the user does try making changes using pluginkit those are likely to be undone when the registry is next updated, and in any case following reboot.

There are some differences obvious between LaunchServices’ database and PlugInKit’s registry. While LaunchServices comfortably accommodates as many versions of apps that it can find, and offers them as choices for opening documents in the Finder’s contextual menu, PlugInKit makes the user’s life simpler by only offering the latest version of each appex. Given that appexes now include replacements for QuickLook’s qlgenerators, and Spotlight importers, that’s hardly surprising, and the prospect of being offered multiple versions in the Share menu would be overwhelming for any user.

PlugInKit and appexes aren’t recent, and probably date back to OS X 10.9 Mavericks, with their NSExtension property list definitions appearing a year later in Yosemite. In macOS 13 Ventura, Apple augmented that with ExtensionKit and ExtensionFoundations both for creating extensions and the extension points offered by host apps. Appexes now cover many different domains, and have become increasingly popular in third-party products, with some like Eternal Storms’ Yoink relying on them for their tight integration with macOS.

Improving our understanding of appexes and their management by PlugInKit isn’t an academic exercise. Host apps and their extensions don’t always work in perfect harmony. Whether you’re developing either of them, or just trying to cope with their disagreements, insight can be important. Now that Sequoia requires QuickLook thumbnail and preview generation to occur in appexes rather than qlgenerators, the qlmanage command tool is of limited value, and you have to rely on PlugInKit instead.

Once upon a time, Apple used to provide extensive and well-written conceptual documentation, where it explained how Mac OS worked, so that when we came to tackle problems we could fall back on understanding. Now we’re largely left to fend for ourselves, so armed with a forthcoming new version of AppexIndexer, I’m off to discover PlugInKit discovery.

Discover appexes with AppexIndexer

App extensions, appexes, have become plentiful and widely used by macOS and third-party software, yet discovering and controlling them is patchy and limited. The most coherent access is in System Settings > General > Login Items & Extensions, where some are gathered in the list of Extensions at the end. Others like Safari extensions are controlled in app settings, while most remain hidden out of sight.

To take stock of all these appexes, I turned to the pluginkit command tool, but the lists it generates are seemingly ordered at random, and so extensive that it would require some serious scripting to make any sense. Instead, it’s easier and more effective to put together a little app to do that. So I present you with AppexIndexer, an exploratory utility that displays key information about all appexes recognised by macOS.

Click on its button to Get Appexes and the window below will fill with well over 400 items, arranged in alphabetical order by the first entry in each line, the SDK or NSExtensionPointIdentifier. Some of those should be fairly obvious: for instance, those appexes listed in Photos Editing settings use the com.apple.photo-editing SDK. In a future article I will explore the relationships between settings categories and SDKs given.

Following that comes the display name of that appex, again ordered alphabetically within that SDK group, which should be the same as that used in System Settings. Next comes the path to that appex, so you can inspect it and its Info.plist for further information.

Many appexes also have a parent, so the last two entries given are the name and path to that parent, when they’re available. One quick way to recognise third-party appexes is to glance down the right side of the list, as they invariably have a familiar parent. Appexes built into macOS are far less likely to have parents (and you can read into that what you like!).

Even in a modest installation, you’re likely to see well over 400 in your Mac’s list, from SpamSieve, an Email Extension with the SDK of com.apple.email.extension, through to QuickLook thumbnail previewers, screensavers and wallpaper. I’ve already explained in general terms what these are and how they work, in this article.

One significant feature missing at this stage is Find/Search, which I’m still working on, for LogUI as well. There’s also additional information given by the pluginkit command tool, and more still that’s available from each appex’s Info.plist file inside its bundle. This initial release lets you save the window’s contents using the Save as RTF button, and you can copy any selected entries and paste them as text. Row selection can be continuous using the Shift key, and discontinuous using Command.

Appexes are not only growing in number, but also becoming increasingly important in macOS. In some cases, they include background processes that could be used maliciously as a method of persistence. Although appexes still need to comply with TCC’s strict rules for accessing protected services and data, they can be an effective way to fly under a user’s radar.

AppexIndexer 1.0 build 5 is now available from here: appindexer105
I’m afraid that it requires macOS Sonoma 14.6 or later, to support the features it uses in SwiftUI.

I hope that you find this information of use. Please let me know what features you’d like the app to support, whether you’d like it to access appex property lists, or other useful data, and how you might want to use a future version. While I’ve got my own ideas, I’m interested in yours, and will try to accommodate them.

Rise of the Appex: What are App Extensions?

Open System Settings, then General, and Login Items & Extensions. Scroll to the end of that list and you’ll see a section titled Extensions. All looks tidy there and in order, but you’re looking at the tip of the iceberg. Click on the ⓘ button at the right of any of those entries, and prepare to be thoroughly confused. These aren’t, of course, kernel extensions, nor are they only system extensions (although some may be), they’re app extensions, conveniently shortened to appexes, the subject of this article.

System Settings

That section in System Settings is unusual as its list depends entirely on what you have installed on your Mac. Among those you’re most likely to see are:

  • Actions allow access to an app’s functions from within other apps, such as Markup provided by macOS.
  • Dock Tiles customise the Dock and normally run in the background (although not listed in Background items above), including several phantom ‘apps’ added by macOS.
  • File Providers allow you to see both local and remote-storage files together in the Finder, and normally run in the background (although not listed in Background items above). Note this isn’t confined to ‘file providers’ in the sense of cloud services like iCloud Drive.
  • File System Extensions, userland file systems, including ExFAT and MSDOS in macOS 15.4, which are intended to replace kernel extensions.
  • Finder provides enhanced search and other functions for files and more. These can also be accessed directly through the Quick Actions item in the Finder’s contextual menu.
  • Photos Editing provides enhanced editing in the Photos app. This also includes Markup provided by macOS.
  • Quick Look includes custom QuickLook thumbnail and preview extensions, replacing qlgenerators.
  • Sharing includes features provided in the Share menu. These include some from macOS that can’t be disabled, such as Mail and Messages, others that are optional, as well as third-party apps.
  • Spotlight includes custom mdimporter modules to extract indexable content from custom file types not supported by macOS.

To add to the uncertainty, not all those available in Sequoia 15.4 are listed in the Mac User Guide’s total of 17 classes, or Apple’s list of 25 for developers.

Where are appexes?

Most of these are installed as .appex bundles inside a PlugIns folder inside the bundle of an app, although some can instead be in a Library folder inside the app. The best information about each is in the Info.plist file in their appex bundle. In that, the nested dictionary of NSExtensionAttributes is most informative. That gives the NSExtensionPointIdentifier type, which for a QuickLook appex might be com.apple.quicklook.preview, indicating that it generates custom previews for QuickLook, in the way that qlgenerators used to. That type corresponds to the SDK entry listed by pluginkit, described below.

Not all appexes are exposed in System Settings, though. New-style drivers supplied in .dext bundles, that are listed as extensions, aren’t included despite there being 17 bundled in macOS 15.4. There’s also no mention of nearly 200 appexes provided in /System/Library/ExtensionKit/Extensions.

pluginkit

In addition to their control in System Settings, the command tool for working with appexes is pluginkit. Most of its options are aimed at those developing and debugging their own appexes, but there’s one command that will dump details of all managed appexes to a lengthy text file, with a form like
pluginkit -m -vv > ~/Documents/pluginkitOut.text
which pipes its output to the file at ~/Documents/pluginkitOut.text. You can add another v to the options for greater details.

The output from pluginkit reveals just how many appexes there are, possibly as many as 500 or more installed in your Mac. Most are system components that aren’t exposed in System Settings, and many have SDK names, specifying their type, that fall outside the categories listed by Apple. For instance, there’s a com.apple.CloudDocs.iCloudDriveFileProvider appex buried deep in the CloudDocs private framework that has an SDK type of com.apple.fileprovider-nonui for iCloud Drive.

Anomalies

Extensions settings currently appears to be a work in progress. It’s among the most opaque sections in System Settings, with all of its controls accessed through ⓘ buttons and floating windows, rather than being laid out clearly. It’s riddled with inconsistencies, and some sections don’t appear to work properly, most notably Quick Look.

This screenshot shows that Apparency’s Quick Look appex is currently disabled, but at the right is a QuickLook preview demonstrating Apparency’s customisation. This applies to other custom Quick Look appexes in Sequoia 15.4: when apparently disabled, they continue to work normally.

As system qlgenerators aren’t included in the Quick Look list, it can’t be used to disable those to allow third-party appexes to generate thumbnails and previews instead, which might have been a useful function.

Summary

  • Appexes are app extensions, now found in the PlugIns or Library folders within app bundles.
  • Although some appexes are also system extensions, or their relatives, most aren’t, and simply extend that app’s features.
  • Many appexes are controlled in System Settings > General > Login Items & Extensions, at the end.
  • Lists shown there vary according to which types of appex are installed. Click on the ⓘ button to view and control them.
  • Some system appexes are listed but can’t be disabled, while others can be.
  • They can also be controlled and listed using the pluginkit command tool, although that’s not straightforward.
  • In Sequoia 15.4, Quick Look appex controls appear dysfunctional.

References

man pluginkit
Apple’s developer master page with links to documentation
QuickLook and its appexes
Dock tile appexes.

❌