├── src ├── Icon.icns ├── Icon.iconset │ ├── icon_16x16.png │ ├── icon_32x32.png │ ├── icon_128x128.png │ ├── icon_16x16@2x.png │ ├── icon_256x256.png │ ├── icon_32x32@2x.png │ ├── icon_512x512.png │ ├── icon_128x128@2x.png │ ├── icon_256x256@2x.png │ └── icon_512x512@2x.png ├── hello_pyobjc.py ├── hello_qt.py ├── hello_wx.py ├── HelloAppStore.py ├── app.entitlements ├── hello_tk.py └── Info.plist ├── .gitignore ├── setup.py ├── code-signing-config.sh ├── LICENSE └── README.md /src/Icon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidfstr/Python-in-Mac-App-Store/HEAD/src/Icon.icns -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OS X 2 | .DS_Store 3 | 4 | # Python 5 | .py[co] 6 | 7 | # Build artifacts 8 | build 9 | dist 10 | -------------------------------------------------------------------------------- /src/Icon.iconset/icon_16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidfstr/Python-in-Mac-App-Store/HEAD/src/Icon.iconset/icon_16x16.png -------------------------------------------------------------------------------- /src/Icon.iconset/icon_32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidfstr/Python-in-Mac-App-Store/HEAD/src/Icon.iconset/icon_32x32.png -------------------------------------------------------------------------------- /src/Icon.iconset/icon_128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidfstr/Python-in-Mac-App-Store/HEAD/src/Icon.iconset/icon_128x128.png -------------------------------------------------------------------------------- /src/Icon.iconset/icon_16x16@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidfstr/Python-in-Mac-App-Store/HEAD/src/Icon.iconset/icon_16x16@2x.png -------------------------------------------------------------------------------- /src/Icon.iconset/icon_256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidfstr/Python-in-Mac-App-Store/HEAD/src/Icon.iconset/icon_256x256.png -------------------------------------------------------------------------------- /src/Icon.iconset/icon_32x32@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidfstr/Python-in-Mac-App-Store/HEAD/src/Icon.iconset/icon_32x32@2x.png -------------------------------------------------------------------------------- /src/Icon.iconset/icon_512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidfstr/Python-in-Mac-App-Store/HEAD/src/Icon.iconset/icon_512x512.png -------------------------------------------------------------------------------- /src/Icon.iconset/icon_128x128@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidfstr/Python-in-Mac-App-Store/HEAD/src/Icon.iconset/icon_128x128@2x.png -------------------------------------------------------------------------------- /src/Icon.iconset/icon_256x256@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidfstr/Python-in-Mac-App-Store/HEAD/src/Icon.iconset/icon_256x256@2x.png -------------------------------------------------------------------------------- /src/Icon.iconset/icon_512x512@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidfstr/Python-in-Mac-App-Store/HEAD/src/Icon.iconset/icon_512x512@2x.png -------------------------------------------------------------------------------- /src/hello_pyobjc.py: -------------------------------------------------------------------------------- 1 | import AppKit 2 | 3 | def main(): 4 | alert = AppKit.NSAlert.alertWithMessageText_defaultButton_alternateButton_otherButton_informativeTextWithFormat_( 5 | "Hello World", "OK", None, None, "") 6 | alert.runModal() 7 | -------------------------------------------------------------------------------- /src/hello_qt.py: -------------------------------------------------------------------------------- 1 | from PySide.QtGui import QApplication 2 | from PySide.QtGui import QMessageBox 3 | import sys 4 | 5 | def main(): 6 | app = QApplication(sys.argv) 7 | QMessageBox.information(None, 'Greetings', 'Hello World!') 8 | app.exec_() 9 | -------------------------------------------------------------------------------- /src/hello_wx.py: -------------------------------------------------------------------------------- 1 | import wx 2 | 3 | def main(): 4 | app = wx.PySimpleApp() 5 | colors = ['Red', 'Blue', 'Green', 'Pink', 'White'] 6 | dialog = wx.SingleChoiceDialog( 7 | None, 'Pick something...', 'Pick a Color', colors) 8 | dialog.ShowModal() 9 | -------------------------------------------------------------------------------- /src/HelloAppStore.py: -------------------------------------------------------------------------------- 1 | import hello_tk 2 | import sys 3 | 4 | # Display a simple dialog 5 | hello_tk.main() 6 | #hello_pyobjc.main() 7 | #hello_wx.main() 8 | #hello_qt.main() 9 | 10 | # Explicitly quit, as is required by some toolkits (like QT) 11 | sys.exit(0) 12 | -------------------------------------------------------------------------------- /src/app.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/hello_tk.py: -------------------------------------------------------------------------------- 1 | from Tkinter import Tk 2 | import tkMessageBox 3 | 4 | def main(): 5 | # Force Tk's required top-level window to be hidden 6 | top = Tk() 7 | top.state('withdrawn') 8 | 9 | # Display simple dialog 10 | tkMessageBox.showinfo('Greetings', 'Hello World!') 11 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | """ 2 | This is a setup.py script generated by py2applet 3 | 4 | Usage: 5 | python setup.py py2app 6 | """ 7 | 8 | from setuptools import setup 9 | 10 | APP = ['src/HelloAppStore.py'] 11 | # Extra items to add to dist/HelloAppStore.app/Contents/Resources 12 | DATA_FILES = [] 13 | OPTIONS = { 14 | 'argv_emulation': True, 15 | 'iconfile': 'src/Icon.icns', 16 | 'plist': 'src/Info.plist', 17 | } 18 | 19 | setup( 20 | app=APP, 21 | data_files=DATA_FILES, 22 | options={'py2app': OPTIONS}, 23 | setup_requires=['py2app'], 24 | ) 25 | -------------------------------------------------------------------------------- /code-signing-config.sh: -------------------------------------------------------------------------------- 1 | # Configure code signing. 2 | 3 | # To enable signing, set this to "1". Otherwise, no signing is done; useful 4 | # for local testing. 5 | DO_CODE_SIGNING=0 6 | 7 | # The package signing identity corresponds to a "3rd Party Mac Developer Application" 8 | # certificate that resides within the Keychain Access application. 9 | SIGNING_IDENTITY_APP="3rd Party Mac Developer Application: David Foster" 10 | 11 | # The package signing identity corresponds to a "3rd Party Mac Developer Installer" 12 | # certificate that resides within the Keychain Access application. 13 | SIGNING_IDENTITY_INSTALLER="3rd Party Mac Developer Installer: David Foster" -------------------------------------------------------------------------------- /src/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleDisplayName 8 | Hello App Store 9 | CFBundleName 10 | HelloAppStore 11 | CFBundleShortVersionString 12 | 1.0 13 | CFBundleVersion 14 | 1.0 15 | NSHumanReadableCopyright 16 | Copyright © 2014 David Foster 17 | CFBundleIdentifier 18 | net.dafoster.Hello-App-Store 19 | CFBundlePackageType 20 | APPL 21 | CFBundleSignature 22 | HAPS 23 | LSApplicationCategoryType 24 | public.app-category.reference 25 | CFBundleDocumentTypes 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2014-2015 David Foster 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Hello App Store 2 | 3 | This is a barebones Python app that can be submitted to the Mac App Store. 4 | 5 | It displays a simple dialog and exits. 6 | 7 | ## Quickstart 8 | 9 | ### Prerequisites 10 | 11 | * OS X 10.8 (Mountain Lion) 12 | * Other OS X versions from 10.6+ will probably work. 13 | * Python 2.7.x 14 | * This exact version of Python is required because the build process has patching steps specific to `lib/python2.7`. 15 | * py2app 0.8.1 or later 16 | * Really old versions of py2app create invalid `Python.framework` bundles in generated apps that won't pass Mac App Store checks. 17 | * **(Optional)** wx 3.0.0.0 osx-cocoa (classic) 18 | * **(Optional)** PySide 1.1.1 / QT 4.8.6 19 | * **(Optional)** PtQt 4.11 / sip 4.16.1 / QT 4.8.6 20 | 21 | ### How to Build 22 | 23 | 1. Clone this repository or download a ZIP file of it: 24 | * `git clone https://github.com/davidfstr/Python-in-Mac-App-Store.git` 25 | * `cd Python-in-Mac-App-Store` 26 | 2. Build the app package `dist/HelloAppStore.app`: 27 | * `./build-app.sh` 28 | 3. Build the installer package `dist/HelloAppStore.pkg`: 29 | * `./build-pkg.sh` 30 | 31 | For submission to the App Store you will also need to enable code signing: 32 | 33 | 1. Configure code signing: 34 | * Update the `SIGNING_IDENTITY` line in `code-signing-config.sh` to refer to your Mac App Store signing certificates: 35 | * You will need an [Apple Developer account](https://developer.apple.com/devcenter/mac/) and a subscription to the Mac Developer Program ($99/year) to get signing certificates. 36 | * Create the appropriate Mac App Store certificates in the [Mac Dev Center](https://developer.apple.com/account/mac/certificate/) and download them to your dev machine. 37 | * Change the `DO_CODE_SIGNING` line in `code-signing-config.sh` to assign 38 | `1` instead of `0`. 39 | 2. Rebuild the app package and installer package using the same steps as above. 40 | 41 | ### How to Submit 42 | 43 | 1. Create a record for your app inside [iTunes Connect](https://itunesconnect.apple.com/). 44 | * Create a unique *bundle identifier* for your app record and update the `CFBundleIdentifier` key in `src/Info.plist` to match it. 45 | * Fill out app metadata, including its description, keywords, screenshots, etc. 46 | * Press "Ready to Upload Binary". 47 | 2. Open Application Loader: 48 | * Open Xcode. 49 | * From the menubar, select Xcode > Open Developer Tool > Application Loader. 50 | 3. Click "Deliver Your App" and select the app record you created in iTunes Connect. 51 | 3. When you are prompted for an item to upload, select `dist/HelloAppStore.pkg`. 52 | 53 | ## Writing your Own App? 54 | 55 | ### Choosing a GUI Library 56 | 57 | Any app you submit to the Mac App Store must have a GUI. In Python there are a few libraries available to create a GUI: 58 | 59 | * **[Tkinter] / Tk** - Built-in to Python. Just works. 60 | * Poorly documented. Limited widget set. 61 | * Overhead: Nothing 62 | * **[PyObjC] / Cocoa** - Full bindings to the Cocoa frameworks. 63 | * Reasonably documented and maintained. (But requires you to learn Cocoa.) 64 | * Provides full access to all OS X native widgets. 65 | * Overhead: Nothing 66 | * **[ctypes] / Cocoa** - Low-level bindings directly to Cocoa frameworks. 67 | * Most direct way to access native Cocoa frameworks, albeit verbose. 68 | * Almost no online documentation for this approach. 69 | * The [cocoa-python](https://code.google.com/p/cocoa-python/) library exposes a tiny subset of Cocoa using ctypes. Reading its source code is illustrative. 70 | * Overhead: Nothing 71 | * **[wxPython] / wxWidgets** 72 | * Well documented. Lots of widgets. 73 | * **Note:** Cannot be submitted to Mac App Store due to wxPython's reliance on [deprecated QuickTime APIs](https://groups.google.com/forum/#!topic/wxpython-mac/BeUS9GHigvE). 74 | * Overhead: 38.7 MB uncompressed, 13.3 MB compressed 75 | * **[PySide] / QT** 76 | * Well documented. Unsure if maintained. 77 | * **Note:** The app created by py2app crashes with a segmentation fault. My guess is that the py2app needs a special "recipe" for PySide. I don't feel like writing one myself. 78 | * Overhead: 16.6 MB uncompressed, 6.3 MB compressed (estimated) 79 | * **[PyQt]4 / QT** 80 | * **Note:** I am unable to build from source and no binary installers for OS X are available. Seriously don't people test anything these days? 81 | 82 | The above assessment leaves the following choices for Mac App Store apps: 83 | 84 | * Tkinter 85 | * PyObjC 86 | * ctypes 87 | 88 | Probably PyObjC is the best choice to get full functionality. I'm disappointed that wxPython gets the shaft here, as most of my preexisting GUI apps in Python are written with wxPython. 89 | 90 | This example app uses Tkinter by default but includes samples for several of the other GUI libraries. 91 | 92 | If you'd like to try the other samples, open `src/HelloAppStore.py` and change the `main` function to call one of the other libraries. 93 | 94 | [ctypes]: https://docs.python.org/2/library/ctypes.html 95 | [Tkinter]: https://wiki.python.org/moin/TkInter 96 | [wxPython]: http://wxpython.org 97 | [PySide]: http://www.pyside.org/ 98 | [PyQt]: http://www.riverbankcomputing.com/software/pyqt/intro 99 | [PyObjC]: https://pythonhosted.org/pyobjc/ 100 | --------------------------------------------------------------------------------