Skip to main content

Xcode Bundle Plugins & Distribution

For complex plugins with multiple source files, resources, or third-party dependencies, you can create a full Xcode project that builds a plugin bundle.

For simpler plugins, consider using Swift Source Plugins instead - they require no Xcode project.

Bundle Extensions

Each plugin type uses a specific bundle extension:

Plugin TypeExtensionProtocol
Touch Bar.btttouchbarpluginBTTPluginInterface
Stream Deck.bttstreamdeckpluginBTTStreamDeckPluginInterface
Floating Menu Widget.bttwidgetBTTFloatingMenuWidgetInterface
Action.bttactionpluginBTTActionPluginInterface
Trigger.btttriggerpluginBTTTriggerPluginInterface
Launcher.bttlauncherpluginBTTLauncherPluginInterface

Project Setup

1. Clone the Template Project

git clone git@github.com:folivoraAI/BetterTouchToolPlugins.git

Open xcode-bundle-examples/BetterTouchToolPluginDevelopment.xcodeproj in Xcode. It contains sample plugins and the required BTTPluginSupport.framework.

2. Create a New Target

Add a new macOS Bundle target to the project. Set the bundle extension to match your plugin type (e.g. .bttwidget).

Add BTTPluginSupport.framework to your target's Frameworks and Libraries. This framework provides:

  • BTTPluginFormItem - configuration form item class
  • BTTFormConstants - form field type constants
  • All plugin protocol definitions from BTTPluginInterface.h

4. Configure Info.plist

Every plugin bundle must include these Info.plist keys:

KeyTypeDescription
BTTPluginNameStringDisplay name shown in BTT
BTTPluginIdentifierStringUnique reverse-domain identifier (e.g. com.yourname.myplugin)
BTTPluginTypeStringOne of: TouchBar, StreamDeck, FloatingMenuWidget, Action, Trigger, Launcher
BTTPluginIconStringSF Symbol name (optional)
NSPrincipalClassStringFully qualified class name

For Swift classes, set NSPrincipalClass to $(PRODUCT_MODULE_NAME).ClassName:

<key>NSPrincipalClass</key>
<string>$(PRODUCT_MODULE_NAME).CPUUsagePlugin</string>

5. Implement the Protocol

Create your plugin class conforming to the appropriate protocol. See the individual plugin type pages for protocol details:

6. Build and Test

Build the project in Xcode. Find the built bundle under the Products group (right-click > Show in Finder), then install it by double-clicking or dragging it onto the BTT preferences window.

Distribution

Plugins distributed to other users must be notarized by Apple. This requires an Apple Developer account.

1. Build/Archive

xcodebuild archive \
-scheme YourPluginScheme \
-configuration Release \
-archivePath ./build/yourplugin.xcarchive
cd build/yourplugin.xcarchive/Products/Library/Bundles/

2. Code Sign

codesign --deep \
-s "Developer ID Application: Your Name (TEAMID)" \
-f YourPlugin.bttwidget

Replace the identity string with your own Developer ID certificate and the extension with your plugin's bundle extension.

3. Zip for Notarization

ditto -c -k --keepParent --rsrc YourPlugin.bttwidget YourPlugin.notarize.zip

4. Submit for Notarization

xcrun notarytool submit YourPlugin.notarize.zip \
--apple-id "your@email.com" \
--team-id TEAMID \
--password "@keychain:notarization" \
--wait

5. Staple the Notarization Ticket

xcrun stapler staple YourPlugin.bttwidget

6. Zip for Distribution

ditto -c -k --keepParent --rsrc YourPlugin.bttwidget YourPlugin.zip

Share the resulting .zip file. Users install the plugin by unzipping it and double-clicking the bundle, or dragging it onto the BTT preferences window.

tip

Swift source plugins (.swift files) do not require notarization and can be shared directly. Only compiled Xcode bundle plugins need to go through the notarization process.

Source Code & Examples

The full plugin source code, Xcode project templates, and sample plugins are available on GitHub:

https://github.com/folivoraAI/BetterTouchToolPlugins/tree/master/xcode-bundle-examples