Skip to main content

Python によるモバイルアプリ開発: PySide6 が iOS に対応

コメント
このブログは「Python Mobile App Development: Bringing PySide6 on iOS」の抄訳です。

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 自身の静的フレームワークや、BeeWarePython.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 ▶️ を押すだけです。

pyside-ios図1:Xcode プロジェクト(左)、実機のスクリーンショット(右)

Android と iOS を1つのコードベースで

PySide6 は Android(Qt 6.5 以降)に加えて iOS (Qt 6.12 以降) にも対応したことで、同じ PySide6 のコードベースで2大モバイルプラットフォームの両方をターゲットにできるようになりました。ビルドやパッケージングの手順は内部的には異なり、iOS は静的リンク、Android は動的ロードという違いがありますが、アプリケーションのコード自体は両者で変更する必要がありません。1つの PySide6 プロジェクトを、デスクトップ・Android・iOS へ書き直しなしで展開できます。

現時点での制限事項

今回が iOS 対応を含む最初のバージョンということもあり、いくつか把握しておくべき制限があります。以下のいずれかについて修正を貢献いただける場合は、ぜひレビューさせてください。

  • サードパーティ製パッケージは未対応。C 拡張を含むパッケージ(numpyPillow など)は使用できません。PyPI に iOS 向けの wheel がまだ存在しないためです。
  • iOS シミュレータは未対応。現状のテストには実機が必要で、シミュレータ対応は現在調査を進めています。
  • Xcode プロジェクトの生成は手動。pyside6-android-deploy に相当する pyside6-ios-deploy コンソールスクリプトを計画中で、手動での生成・オープン作業を置き換える予定です。
  • 現状は BeeWare の Python.xcframework に依存。Python 3.15 が正式リリースされ次第、Python 公式の iOS サポートへ切り替える予定です。

よくある質問

  • 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.mmInfo.plistLD_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 上で動かすための初期の検証作業に感謝します。最終的なアプローチは異なるものになりましたが、その初期の取り組みが本プロジェクトの出発点になりました。

コメント

ブログを購読

Qt 6.11 を今すぐ試そう!

最新リリースはこちらからダウンロードできます。 www.qt.io/download

 Qt 6.11 がリリースされました!アプリケーション開発者やデバイス開発者向けに、多くの新機能と改善が追加されています。 

採用情報 

現在、さまざまなポジションで採用を行っています。募集職種はこちら をご覧ください。また、Instagram をフォローして #QtPeople の働き方もぜひチェックしてください。