Packaging Applications¶
This guide shows how to package your StackIt applications as standalone macOS .app bundles using py2app.
Prerequisites¶
Install py2app:
pip install py2app
Ensure StacKit is installed:
# Development mode (recommended) cd /path/to/stackit pip install -e . # Or from PyPI pip install stackitui
Creating a Setup File¶
Create a setup.py file for your application:
from setuptools import setup
import sys
import os
# Add parent directory to path if stackit is local
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
APP = ['your_app.py']
DATA_FILES = []
OPTIONS = {
'argv_emulation': False,
'plist': {
'CFBundleName': 'YourApp',
'CFBundleDisplayName': 'Your App Display Name',
'CFBundleIdentifier': 'com.yourcompany.yourapp',
'CFBundleVersion': '1.0.0',
'CFBundleShortVersionString': '1.0',
'LSUIElement': True, # Menu bar app (no Dock icon)
'NSHighResolutionCapable': True,
'NSRequiresAquaSystemAppearance': False, # Support dark mode
},
'packages': [
'stackit',
'AppKit',
'Foundation',
'objc',
],
'includes': [
'stackit.core',
'stackit.controls',
'stackit.sfsymbol',
'stackit.utils',
'stackit.delegate',
],
'excludes': [
'tkinter',
'matplotlib',
'numpy',
'scipy',
'pandas',
'pytest',
'IPython',
],
'strip': True,
'optimize': 2,
}
setup(
name='YourApp',
app=APP,
data_files=DATA_FILES,
options={'py2app': OPTIONS},
setup_requires=['py2app'],
)
Building the Application¶
Development Build (Alias Mode)¶
For development and testing, use alias mode (-A). This creates a lightweight build that links to your source files:
python setup.py py2app -A
Advantages:
Builds in seconds
Changes to source code are immediately reflected
Perfect for iteration and testing
Much smaller app size
Limitations:
Requires Python to be installed on the system
Not suitable for distribution
Standalone Build¶
For distribution, create a full standalone build:
python setup.py py2app
Advantages:
Bundles Python and all dependencies
Can be distributed to users without Python
Self-contained application
Limitations:
Takes longer to build (minutes)
Larger app size (50-100 MB)
May have issues with editable installs
Note
If you encounter “No module named ‘stackit’” errors during standalone builds, use alias mode (-A) instead. The standalone build can have issues with editable installs.
Testing the Application¶
After building, test your application:
open dist/YourApp.app
Check the Console.app for any runtime errors or warnings.
Customization¶
Adding an Icon¶
Create or download an .icns file and add it to your setup:
OPTIONS = {
'iconfile': 'path/to/icon.icns',
# ... other options
}
Bundle Information¶
Customize the app’s bundle information in the plist:
'plist': {
'CFBundleName': 'MyApp', # Internal name
'CFBundleDisplayName': 'My Application', # Display name
'CFBundleIdentifier': 'com.mycompany.myapp',
'CFBundleVersion': '1.0.0',
'CFBundleShortVersionString': '1.0',
'LSMinimumSystemVersion': '10.15.0', # Minimum macOS version
}
Permissions¶
If your app needs special permissions (like Full Disk Access), add usage descriptions:
'plist': {
# ... other settings
'NSAppleEventsUsageDescription': 'Your app needs to access system events.',
'NSSystemAdministrationUsageDescription': 'Your app needs Full Disk Access.',
}
Reducing App Size¶
Add unused packages to the excludes list:
'excludes': [
'tkinter',
'matplotlib',
'numpy',
'scipy',
'pandas',
'pytest',
'IPython',
# Add more as needed
]
Distribution¶
Option 1: ZIP Archive¶
Create a ZIP file for easy distribution:
cd dist
zip -r YourApp.zip YourApp.app
Users can download, unzip, and drag to /Applications.
Option 2: DMG Installer¶
Create a professional disk image installer:
# Install create-dmg
brew install create-dmg
# Create DMG
create-dmg \
--volname "YourApp Installer" \
--window-pos 200 120 \
--window-size 600 400 \
--icon-size 100 \
--icon "YourApp.app" 175 120 \
--hide-extension "YourApp.app" \
--app-drop-link 425 120 \
"YourApp.dmg" \
"dist/"
Option 3: Code Signing¶
To avoid “unidentified developer” warnings (requires Apple Developer account):
# Sign the app
codesign --deep --force --sign "Developer ID Application: Your Name" dist/YourApp.app
# Verify signature
codesign --verify --verbose dist/YourApp.app
# Notarize with Apple
xcrun notarytool submit YourApp.zip --apple-id your@email.com --wait
Troubleshooting¶
ImportError: No module named ‘stackit’¶
Solution:
Ensure stackit is installed:
pip install -e /path/to/stackitUse alias mode:
python setup.py py2app -A
App won’t launch¶
Solution:
Open Console.app and filter for your app name to see error messages
Ensure you used alias mode:
python setup.py py2app -ACheck that all required modules are in the
packageslist
Missing modules at runtime¶
Solution:
Add the missing module to the packages list in your setup file:
'packages': [
'stackit',
'your_missing_module',
# ...
]
App too large¶
Solution:
Add unused packages to the
excludeslistUse system Python instead of Homebrew/pyenv Python
Enable stripping and optimization (already default in example)
Can’t access files/permissions¶
Solution:
After first launch, grant necessary permissions:
Open System Settings → Privacy & Security
Find the relevant permission (e.g., Full Disk Access)
Click + and add your
.appRestart the app
Complete Example¶
See examples/packaging_test/screentime.py and examples/packaging_test/setup_screentime.py for a complete working example of a packaged StackIt application.
Resources¶
examples/packaging_test/BUILD.md - Quick reference
examples/packaging_test/PACKAGING.md - Detailed guide