Apps rejected by macOS App Store due to "use of non-public or deprecated APIs"
Describe the bug
If you use Briefcase package an app for distribution in the macOS App Store, the app will be rejected with the following message:
Guideline 2.5.1 - Performance - Software Requirements
Your app uses or references the following non-public or deprecated APIs:
Contents/Frameworks/Python.framework/Versions/3.12/lib/libtk8.6.dylib
Symbols:
• _NSWindowDidOrderOnScreenNotification
The use of non-public or deprecated APIs is not permitted on the App Store, as they can lead to a poor user experience should these APIs change and are otherwise not supported on Apple platforms.
Steps to reproduce
- Generate a Hello World app
- Sign the app with a macOS App Store distribution certificate
- Submit the app for publication in the App Store
- See error described above
Expected behavior
It should be possible to distribute a macOS app in the App Store.
Screenshots
No response
Environment
- Operating System: macOS (all)
- Python version: all
- Software versions:
- Briefcase: 0.3.20+
Logs
No response
Additional context
This is caused by a known issue with Tk.
It has been reported to Python (see python/cpython#129247) - however, there's nothing Python can do to fix this issue.
If your app uses Tkinter, you are unfortunately out of luck. With the current state of Tk, it is not possible to distribute a Tk app in the macOS App Store. You will need to use other distribution mechanisms.
However, if your app does not use Tkinter, you can use the Briefcase cleanup_paths option to purge the Tkinter libraries as part of the app packaging process. If you add the following to your the macOS section of your pyproject.toml:
cleanup_paths = [
"**/Frameworks/Python.framework/**/lib/Tk.*",
"**/Frameworks/Python.framework/**/lib/itcl*",
"**/Frameworks/Python.framework/**/lib/libtcl*",
"**/Frameworks/Python.framework/**/lib/libtk*",
"**/Frameworks/Python.framework/**/lib/tcl*",
"**/Frameworks/Python.framework/**/lib/tdbc*",
"**/Frameworks/Python.framework/**/lib/tk*",
"**/Frameworks/Python.framework/**/lib/thread*",
]
the tk binaries will be deleted, which should allow your app to be released. This has the added benefit of reducing the size of your app binary.
At the very least, this issue should be documented as a macOS platform quirk (with the fix described above).
It may also be worth formalizing this fix by providing customizable options for what parts of the standard library are installed. Tkinter is only needed by apps that actually use tkinter; for all other apps, it's dead weight in the app bundle. The same goes for curses, maybe sqlite and openssl, and some parts of the non-binary standard library (e.g., the test module is almost 31MB, but most apps won't need any of it). Having an analog of "extras" (i.e pip install foo[extra1,extra2]), but for the Python standard library, would provide a way to formalize what is removed.
Ideally, this "extras" philosophy would be pushed completely upstream, so that there's a "minimal" standard library, and tkinter is a binary wheel on PyPI... but that's a much bigger argument to be had.
I suggest renaming:
"**/Frameworks/Python.framework/**/lib/tk",
to
"**/Frameworks/Python.framework/**/lib/tk*",
(i.e., missing '*' at the end)