Qt 6.12 で、Python によるモバイルアプリ開発がついに iOS にも対応しました。PySide6 を使っている開発者は、Android やデスクトップ向けにすでに使っているコードベースをそのまま使って、ネイティブの iOS アプリをリリースできます。Swift や Objective-C で書き直す必要はなく、2つ目のコードベースを維持する手間もありません。
Qt 6.5 で PySide6 アプリが Android に対応して以来、自然と出てきた疑問が「iOS はどうなるのか」でした。iOS は Android とはまったく異なる課題を抱えていますが、Qt 6.12 では、PySide6 のエコシステムを離れて別の Python→iOS ツールチェーンを探す必要なく、Python 開発者が iPhone や iPad 向けにアプリを配布できるようになりました。
Python で iOS アプリは作れるのか?
答えは Yes 🎉。Qt 6.12 以降、PySide6 アプリは iOS 上でネイティブに動作します。PySide6 を iOS 向けにクロスコンパイルすると、静的な .a ライブラリ一式が生成されます。これらの静的ライブラリは、Qt 自身の静的フレームワークや、BeeWare の Python.xcframework(Python 3.15 がリリースされて公式に iOS をサポートするまでの代替)と一緒に、アプリの Xcode プロジェクトに直接リンクされます。つまり、実行時に動的にロードされるのではなく、すべてが1つの最終的なアプリバイナリにまとめられる形です。
iOS は Android と違う方法が必要な理由
iOS では、Qt をアプリケーションバイナリに静的にリンクする必要があります。Qt は iOS 向けには共有 dylib ではなく静的ライブラリとして提供されています。もし PySide6 のモジュールを動的ファイルとしてロードしてしまうと、Qt のシンボルが二重に現れてしまい、ロード時にシンボルの重複エラーが発生します。
この問題への対処法は、すべての PySide6 モジュールをバイナリに静的にリンクし、Py_Initialize の前に Python インタプリタへあらかじめ登録しておくことです。
Qt による iOS アプリライフサイクルの引き継ぎ
iOS アプリは UIApplicationMain によって駆動され、これがプロセスを掌握したまま戻ってきません。Qt の iOS プラットフォームプラグインは qt_main_wrapper を提供しており、これが Qt 自身のアプリケーションデリゲートを使って UIApplicationMain を呼び出すことで、シグナルやスロット、イベントループを含む Qt プラットフォームの機能を丸ごと利用できるようにします。Xcode の LD_ENTRY_POINT ビルド設定をセットすることで、最初から Qt がプロセスを所有する形になります。
その後、Qt のランループ統合の仕組みによって、制御はこちらの main() に戻され、そこで Python が初期化されてアプリケーションスクリプトが実行されます。
PySide6 アプリの iPhone や iPad で起動方法
PySide6 アプリを iOS 上で動かすまでの手順は3ステップです。Qt のバージョンごとに一度 PySide6 をクロスコンパイルし、アプリを設定ファイルに記述し、Xcode プロジェクトを生成してビルドします。
ステップ1 - PySide6 をクロスコンパイル
python pyside-setup/tools/cross_compile_ios/main.py build --qt-install-path ~/Qt/6.12.0
これにより Python.xcframework がダウンロードされ、CMake のツールチェーンファイルが生成され、shiboken6 と PySide6 が ios_arm64 向けにクロスコンパイルされて、静的ライブラリが出来上がります。
このステップは Qt のバージョンごとに一度実行すれば十分です。生成された成果物は、そのバージョンを使うすべての iOS アプリで使い回せます。
ステップ2 - アプリの記述
Xcode プロジェクトの生成には pyside6-ios.toml ファイルが必要です。ここには Xcode プロジェクトの設定に必要な情報を記述します。現時点ではこのファイルは手動で作成する必要がありますが、既存の 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"
|
ステップ3 - Xcode プロジェクトを生成してビルド
python pyside-setup/tools/cross_compile_ios/main.py generate -c pyside6-ios.toml
open generated/MyPySide6App.xcodeproj
This generates:
これにより以下が生成されます。
main.mm Python を初期化し、すべての PySide6 モジュールをビルトインとして登録し、Python スクリプトを実行
Info.plist iOS アプリのメタデータ
project.pbxproj Qt の各フレームワーク、PySide6 の静的アーカイブ、Python.xcframework、iOS のシステムフレームワークをリンクし、LD_ENTRY_POINT を設定
あとは Xcode でデバイスを選択し、Run ▶️ を押すだけです。
図1:Xcode プロジェクト(左)、実機のスクリーンショット(右)
Android と iOS を1つのコードベースで
PySide6 は Android(Qt 6.5 以降)に加えて iOS (Qt 6.12 以降) にも対応したことで、同じ PySide6 のコードベースで2大モバイルプラットフォームの両方をターゲットにできるようになりました。ビルドやパッケージングの手順は内部的には異なり、iOS は静的リンク、Android は動的ロードという違いがありますが、アプリケーションのコード自体は両者で変更する必要がありません。1つの PySide6 プロジェクトを、デスクトップ・Android・iOS へ書き直しなしで展開できます。
現時点での制限事項
今回が iOS 対応を含む最初のバージョンということもあり、いくつか把握しておくべき制限があります。以下のいずれかについて修正を貢献いただける場合は、ぜひレビューさせてください。
- サードパーティ製パッケージは未対応。C 拡張を含むパッケージ(
numpy、Pillow など)は使用できません。PyPI に iOS 向けの wheel がまだ存在しないためです。
- iOS シミュレータは未対応。現状のテストには実機が必要で、シミュレータ対応は現在調査を進めています。
- Xcode プロジェクトの生成は手動。pyside6-android-deploy に相当する
pyside6-ios-deploy コンソールスクリプトを計画中で、手動での生成・オープン作業を置き換える予定です。
- 現状は BeeWare の
Python.xcframework に依存。Python 3.15 が正式リリースされ次第、Python 公式の iOS サポートへ切り替える予定です。
よくある質問
作れます。PySide6 と Qt 6.12 以降を使えば、Python アプリケーションを静的にコンパイルしてネイティブの iOS アプリバイナリにし、iPhone や iPad 上で実行できます。PySide6 を ios_arm64 向けにクロスコンパイルして Xcode プロジェクトを生成する必要はありますが、アプリケーションコード自体は通常の PySide6 のままです。
-
PySide6 以外に Python で iOS アプリを開発する方法はありますか?
他にも Python→iOS のツールチェーンは存在します。例えば BeeWare の Briefcase。PySide6 の iOS ツールもここから Python.xcframework を再利用しています。また kivy-ios というパッケージもありますが、Qt のネイティブな Widget や QML ツールキットをフルに使えるのは PySide6 だけです。
-
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 の公式ドキュメントを参照してください。Android での同様のアプローチについては、Qt for Python on Android: pyside6-android-deploy によるクロスコンパイルで、並行するワークフローを紹介しています。
ご意見・バグ報告・ご質問は、Qt bug tracker の PySide コンポーネント宛にお寄せください。
Patrick Stinson 氏には、PySide6 を iOS 上で動かすための初期の検証作業に感謝します。最終的なアプローチは異なるものになりましたが、その初期の取り組みが本プロジェクトの出発点になりました。