从 Qt 6.12 起,用 Python 开发移动应用终于覆盖到了 iOS。PySide6 开发者沿用现有的 Android 与桌面端代码,就能直接发布原生 iOS 应用,既不用 Swift 或 Objective-C 重写,也不用再维护第二套需要同步的代码。
自 Qt 6.5 让 PySide6 应用跑上 Android 之后,大家自然会追问:那 iOS 呢?iOS 的难点和 Android 完全不是一回事,但从 Qt 6.12 开始,Python 开发者不必为了把应用发布到 iPhone 和 iPad 而改用其他工具链,留在 PySide6 生态里就能完成。
能用 Python 开发 iOS 应用吗?
可以 🎉。从 Qt 6.12 起,PySide6 应用已经能在 iOS 上原生运行。为 iOS 交叉编译 PySide6 会得到一组静态 .a 库,它们会连同 Qt 自带的静态框架、以及 BeeWare 的 Python.xcframework ,一起直接链接进应用的 Xcode 工程(在正式提供 iOS 支持的 Python 3.15 发布之前,都沿用这个方案)。这样一来,所有内容最终都打包进同一个应用二进制文件,而不是在运行时动态加载。
iOS 为什么不能沿用 Android 的做法?
iOS 要求把 Qt 静态链接进应用二进制文件。面向 iOS 的 Qt 是以静态库形式发布的,而不是动态库(.dylib)。如果 PySide6 模块按动态文件加载,Qt 的符号就会出现两份,加载时会直接报重复符号错误。
解决办法是:把每个 PySide6 模块都静态链接进二进制文件,并在 Py_Initialize 之前预先注册到 Python 解释器中。
Qt 是如何接管 iOS 应用生命周期的?
iOS 应用由 UIApplicationMain 驱动,它会接管整个进程并且永不返回。Qt 的 iOS 平台插件提供了 qt_main_wrapper,用 Qt 自己的 application delegate 去调用 UIApplicationMain,从而让完整的 Qt 平台集成生效——包括信号与槽机制和事件循环。再通过设置 Xcode 的 LD_ENTRY_POINT 构建设置,Qt 就能从进程启动那一刻起掌握控制权。
之后,Qt 的运行循环集成(run loop integration)会把控制权交回给 main(),由它初始化 Python 并运行应用脚本。
怎样让 PySide6 应用跑在 iPhone 或 iPad 上?
把 PySide6 应用跑到 iOS 上一共三步:每个 Qt 版本交叉编译一次 PySide6,在配置文件里写清楚应用信息,然后生成并构建 Xcode 工程。
第一步 · 交叉编译 PySide6
python pyside-setup/tools/cross_compile_ios/main.py build --qt-install-path ~/Qt/6.12.0
这条命令会下载 Python.xcframework,生成 CMake 工具链文件,并针对 ios_arm64 交叉编译 shiboken6 和 PySide6,产出静态库。
这一步每个 Qt 版本只需执行一次,产物可以在您所有的 iOS 应用中复用。
第二步 · 描述应用信息
生成 Xcode 工程需要一个 pyside6-ios.toml 文件,里面写明配置工程所需的信息。目前这个文件要手动编写,从现有 PySide6 项目自动生成的功能正在开发中。
|
[app]
name = "My PySide6 App"
bundle-id = "com.example.mypyside6app"
output-dir = "generated"
[pyside6]
modules = ["QtCore", "QtGui", "QtWidgets"]
[python]
version = "3.14"
scripts = ["scripts/main.py"]
[signing]
style = "Automatic"
|
第三步 · 生成并构建 Xcode 工程
python pyside-setup/tools/cross_compile_ios/main.py generate -c pyside6-ios.toml
open generated/MyPySide6App.xcodeproj
这一步会生成:
在 Xcode 中选好设备,点击运行 ▶️ 即可。

图 1:Xcode 工程(左)与设备截图(右)
一套代码,同时覆盖 Android 与 iOS
PySide6 现在同时支持 Android(Qt 6.5 起)和 iOS(Qt 6.12 起),一套 PySide6 代码就能覆盖这两大主流移动平台。底层的构建与打包方式确实不同——iOS 走静态链接,Android 走动态加载——但应用代码本身不需要为此改动。一个 PySide6 项目,不用重写就能部署到桌面、Android 以及 iOS。
PySide6 在 iOS 上的现有限制
这将是首个包含 iOS 部署支持的版本,因此有几点限制需要提前了解。如果您愿意为其中任何一项提交修复方案,我们很乐意评审:
- 暂不支持第三方包。带 C 扩展的包(
numpy、Pillow 等)目前无法使用,PyPI 上还没有 iOS 平台的 wheel 包。
- 暂不支持 iOS 模拟器。目前测试必须使用真机,模拟器支持仍在研究中。
- Xcode 工程需手动生成。我们计划提供
pyside6-ios-deploy 控制台脚本(对应 Android 端的 pyside6-android-deploy),取代目前“先生成、再打开工程”的手动步骤。
- 目前依赖 BeeWare 的
Python.xcframework。待 Python 3.15 正式发布后,我们打算切换到 Python 官方的 iOS 支持。
常见问题
能用 Python 开发 iOS 应用吗?
可以。用 PySide6 搭配 Qt 6.12 或更高版本,就能把 Python 应用静态编译成原生 iOS 应用二进制文件,在 iPhone 或 iPad 上运行。前提是为 ios_arm64 交叉编译 PySide6 并生成 Xcode 工程,但应用代码本身就是标准的 PySide6 代码。
除了 PySide6,还有别的方式用 Python 开发 iOS 应用吗?
有。例如 BeeWare 的 Briefcase(PySide6 的 iOS 工具链正是复用了它的 Python.xcframework),以及 kivy-ios。区别在于,PySide6 能提供完整的原生 Qt Widgets 与 QML 工具集。
Python 支持跨平台移动开发吗?
支持。有了 PySide6,同一套代码现在可以同时面向 Android 和 iOS。底层构建流程因平台而异(Android 用动态库加载,iOS 需要静态链接),但应用逻辑和 UI 代码在两个平台上可以共用。
Python 在 iOS 上目前有哪些限制?
眼下主要有三点:带 C 扩展的第三方包还用不了(PyPI 上还没有 iOS 平台的 wheel 包)、不支持 iOS 模拟器、以及 Xcode 工程仍需手动生成,还没有做到一条命令完成部署。这三项都在推进中。
把 PySide6 应用发布到 iOS,需要会 Swift 或 Objective-C 吗?
不需要。生成的 Xcode 工程已经处理好原生 iOS 的入口点和应用生命周期(main.mm、Info.plist、LD_ENTRY_POINT)。应用逻辑仍然写在 PySide6 里,Xcode 只负责构建和签名,不用您写原生代码。
去哪里获取 PySide6 上手试用?
相关工具位于 pyside-setup/tools/cross_compile_ios/ 目录下。
本文之外的完整 API 参考,请查阅 Qt for Python 官方文档。如果想看看同样的 PySide6 方案在 Android 上是怎么做的,可以参考 Qt for Python on Android:用 pyside6-android-deploy 交叉编译,两边的流程是对应的。
欢迎在 Qt bug tracker 的 PySide 组件下提交反馈、缺陷报告和疑问。
感谢 Patrick Stinson 在让 PySide6 跑上 iOS 这件事上所做的早期探索。我们最终采用的方案和他的并不相同,但那些前期工作为这项进展打下了基础。