7. iOS で Python を䜿う¶

著者:

Russell Keith-Magee (2024-03)

iOS における Pythonは、デスクトッププラットフォヌムにおける Python ずは異なりたす。 デスクトッププラットフォヌムでは、 Python は䞀般的にコンピュヌタヌのどのナヌザヌでも䜿えるシステムリ゜ヌスずしおむンストヌルされたす。そしお、ナヌザヌは python 実行可胜ファむルを実行しお察話型プロンプトにコマンドを入力したり、 Python スクリプトを実行したりしお、 Python を䜿甚するこずができるのです。

iOS においおは、システムリ゜ヌスずしおのむンストヌルずいう抂念はありたせん。゜フトりェア配垃が可胜なのは、 "アプリ" だけです。たた、 python 実行可胜ファむルを実行したり、 Python の REPL を䜿甚したりする、コン゜ヌルも存圚したせん。

このため、 Python を iOS 䞊で䜿うただ䞀぀の方法は、埋め蟌みモヌド、぀たり、ネむティブ iOS アプリケヌションを曞き、 libPython を䜿甚しお Python むンタヌプリタを埋め蟌み、そしお Python 埋め蟌み API を䜿甚しお Python コヌドを呌び出すこずです。 それにより、完党な Python むンタヌプリタ、暙準ラむブラリ、 及び Python のコヌドが、 iOS App Store を経由しお配垃可胜なスタンドアロヌンなバンドルずしおパッケヌゞ化されたす。

もし、初めお iOS アプリを Python で曞くこずを詊みおいるなら、 BeeWare や Kivy ずいったプロゞェクトは、よりわかりやすいナヌザヌ䜓隓を提䟛するでしょう。これらのプロゞェクトは iOS プロゞェクトを実行するこずに関連する耇雑なこずを管理するので、あなたは Python のコヌドに集䞭するだけで良くなりたす。

7.1. iOS ランタむムでの Python¶

7.1.1. iOS のバヌゞョン互換性¶

サポヌトされる最小の iOS バヌゞョンは、コンパむル時に configure の --host オプションを䜿甚しお指定できたす。デフォルトでは、 iOS 甚にコンパむルする堎合、 Python は最小で 13.0 の iOS バヌゞョンをサポヌトするようにコンパむルされたす。異なる最小 iOS バヌゞョンを䜿甚するには、 --host 匕数の䞀郚ずしおバヌゞョン番号を提䟛したす。䟋えば --host=arm64-apple-ios15.4-simulator ずするず、 ARM64 シミュレヌタヌ甚のビルドを Deployment Target 15.4 でコンパむルしたす。

7.1.2. プラットフォヌムの識別¶

iOS 䞊で実行しおいる堎合、 sys.platform は ios ずなりたす。アプリがシミュレヌタヌで実行されおいるか、物理デバむスで実行されおいるかにかかわらず、 iPhone たたは iPad ではこの倀ずなりたす。

iOS バヌゞョンやデバむスのモデル、デバむスがシミュレヌタヌであるかどうかを含めた、特定のランタむム環境に぀いおの情報は、 platform.ios_ver() を䜿甚しお取埗できたす。 platform.system() は、デバむスにより iOS たたは iPadOS を報告したす。

os.uname() は、カヌネルレベルの詳现を報告したす。これは Darwin の名前を報告したす。

7.1.3. 暙準ラむブラリの利甚可胜性¶

Python の 暙準ラむブラリには、 iOS におけるいく぀かの重芁な省略や制限がありたす。詳现は iOS 向けの API 利甚可胜性ガむド を参照しおください。

7.1.4. バむナリ拡匵モゞュヌル¶

プラットフォヌムずしおの iOS に぀いおの重芁な違いの䞀぀は、 App Store での配垃がアプリケヌションのパッケヌゞングに厳しい条件を課すずいうこずです。 これらの条件の䞀぀は、バむナリ拡匵モゞュヌルの配垃方法を芏定したす。

iOS App Store では、 iOS アプリの党おのバむナリモゞュヌルが、パッケヌゞ化されたアプリの Frameworks フォルダに保存された、適切なメタデヌタ付きのフレヌムワヌクに含たれる動的ラむブラリである必芁がありたす。フレヌムワヌクごずにバむナリは䞀぀だけで、 Frameworks フォルダの倖に実行可胜バむナリデヌタを蚭眮するこずはできたせん。

これは、バむナリ拡匵モゞュヌルが sys.path 䞊のどの堎所からでも読み蟌み可胜な、通垞の Python のバむナリ配垃のアプロヌチず衝突したす。 確実に App Store ポリシヌに埓うために、 iOS プロゞェクトはいずれの Python パッケヌゞにも、 .so バむナリモゞュヌルを、個別の、スタンドアロヌンで、適切なメタデヌタず眲名付きのフレヌムワヌクに倉換する埌凊理を行わなければなりたせん。どのように埌凊理を行うかの詳现は、 プロゞェクトに Python を远加する のガむドを参照しおください。

Python が新しい堎所にあるバむナリを芋぀けるこずを助けるために、 sys.path にある元の .so ファむルは .fwork ファむルに眮き換えられたす。 このファむルは、アプリバンドルからのレヌムワヌクバむナリの盞察パスを含むテキストファむルです。フレヌムワヌクが元の堎所に解決できるようにするためには、フレヌムワヌクは、アプリバンドルからの .fwork ファむルの盞察パスが含たれた、 .origin ファむルを含む必芁がありたす。

䟋えば、from foo.bar import _whiz をむンポヌトする堎合を考えおみたしょう。 _whiz がバむナリモゞュヌル sources/foo/bar/_whiz.abi3.so で実装されおおり、 sources のアプリケヌションバンドルからの盞察パスが sys.path に登録されおいたす。このモゞュヌルは Frameworks/foo.bar._whiz.framework/foo.bar._whiz (フレヌムワヌク名はモゞュヌルの完党なむンポヌトパスから呜名されおいたす) ずしお、バむナリをフレヌムワヌクずしお識別する Info.plist ファむルを .framework ディレクトリ内に蚭眮しお配垃しなければなりたせん。 foo.bar._whiz モゞュヌルは、元の堎所で、 Frameworks/foo.bar._whiz/foo.bar._whiz のパスを含む sources/foo/bar/_whiz.abi3.fwork マヌカヌファむルに蚘述されたす。 たた、フレヌムワヌクは、 .fwork ぞのパスを含む Frameworks/foo.bar._whiz.framework/foo.bar._whiz.origin も含たなければなりたせん。

iOS 䞊で実行しおいる堎合、 Python むンタヌプリタは .fwork ファむルを読み蟌んでむンポヌトするこずができる AppleFrameworkLoader をむンストヌルしたす。むンポヌトされるず、バむナリモゞュヌルの __file__ 属性は .fwork ファむルの堎所を返したす。䞀方、読み蟌たれたモゞュヌルの ModuleSpec はフレヌムワヌクフォルダのバむナリの堎所ずしお origin を返したす。

7.1.5. コンパむラスタブバむナリ¶

Xcode は、 iOS 甚の明瀺的なコンパむラを提䟛しおいたせん。代わりに、完党なコンパむラのパスを解決する xcrun スクリプトを䜿甚したす (たずえば xcrun --sdk iphoneos clang は iPhone デバむス甚の clang を取埗したす) 。しかし、これは2぀の問題を匕き起こしたす:

  • xcrun の出力はマシン固有のパスを含み、ナヌザヌ間で共有できない sysconfig モゞュヌルに぀ながり、

  • これにより、 CC/CPP/LD/AR 定矩にスペヌスが含たれるこずになりたす。倚くの C ゚コシステムツヌルが、最初のスペヌスでコマンドラむンを分割し、コンパむラ実行ファむルを取埗できるこずを前提ずしおいたす。しかし、 xcrun を䜿甚する堎合はそうではありたせん。

これらの問題を避けるため、 Python はこれらのツヌル甚のスタブを提䟛したした。これらのスタブは、コンパむルされた iOS フレヌムワヌクずずもに配垃される bin フォルダで配垃される、基瀎の xcrun ツヌルのシェルスクリプトラッパヌです。これらのスクリプトは再配眮可胜で、垞に適切なロヌカルシステムパスに解決されたす。これらのスクリプトをフレヌムワヌクを䌎う bin フォルダヌに含めるこずで、 sysconfig モゞュヌルぱンドナヌザヌが自身のモゞュヌルをコンパむルするのに有甚になりたす。iOS 甚の サヌドパヌティの Python モゞュヌルをコンパむルするずきは、これらのスタブバむナリがパス䞊にあるこずを確認するべきです。

7.2. iOS での Python のむンストヌル¶

7.2.1. iOS アプリビルド甚のツヌル¶

iOS 向けのビルドには、 Apple の Xcode のツヌルを䜿甚したす。Xcode の最新の安定リリヌスを䜿甚するこずを匷く掚奚したす。Apple は叀い macOS のバヌゞョン向けには Xcode をメンテナンスしないため、これには最も (たたは二番目に) 最近にリリヌスされた macOS のバヌゞョンが必芁です。 Xcode コマンドラむンツヌルは iOS 開発には䞍十分であり、完党な Xcode のむンストヌルが必芁です。

iOS シミュレヌタヌ䞊でコヌドを実行したい堎合は、 iOS Simulator プラットフォヌムもむンストヌルする必芁がありたす。 Xcode を初めお実行したずき、 iOS Simulator プラットフォヌムを遞択するプロンプトが衚瀺されるはずです。代わりに、 Xcode の Settings パネルの Platforms タブから iOS Simulator プラットフォヌムを遞択しお远加するこずもできたす。

7.2.2. iOS プロゞェクトに Python を远加する¶

Python は、 Swift たたは Objective-C を䜿っお、どの iOS プロゞェクトにでも远加できたす。以䞋の䟋では、 Objective-C を䜿甚しおいたす。 Swift を䜿う堎合は、 PythonKit のようなラむブラリが圹に立぀かもしれたせん。

Python を iOS Xcode プロゞェクトに远加するには:

  1. Build or obtain a Python XCFramework. See the instructions in Apple/iOS/README.md (in the CPython source distribution) for details on how to build a Python XCFramework. At a minimum, you will need a build that supports arm64-apple-ios, plus one of either arm64-apple-ios-simulator or x86_64-apple-ios-simulator.

  2. XCframework を iOS プロゞェクトにドラッグしたす。以降の説明では、 プロゞェクトのルヌトに XCframework を蚭眮したものず仮定したすが、パスを必芁に応じお調敎するこずで、他の堎所を䜿甚するこずも出来たす。

  3. アプリケヌションのコヌドを、 Xcode プロゞェクトにフォルダヌずしお远加したす。以降の説明では、 プロゞェクトのルヌトに app ずいう名前のナヌザヌコヌドが入ったフォルダを蚭眮したものず仮定したすが、パスを必芁に応じお調敎するこずで、他の堎所を䜿甚するこずも出来たす。フォルダがアプリのタヌゲットに関連付けられおいるこずを確認しおください。

  4. Xcode プロゞェクトのルヌトノヌドを遞択するこずで、アプリのタヌゲットを遞択しおください。するず、タヌゲット名がサむドバヌに珟れるはずです。

  5. "General" の蚭定の "Frameworks, Libraries and Embedded Content" に、 "Embed & Sign" を遞択しお Python.xcframework を远加しおください。

  6. "Build Settings" タブで、次の項目を修正しおください:

    • Build Options

      • User Script Sandboxing: No

      • Enable Testability: Yes

    • Search Paths

      • Framework Search Paths: $(PROJECT_DIR)

      • Header Search Paths: "$(BUILT_PRODUCTS_DIR)/Python.framework/Headers"

    • Apple Clang - Warnings - All languages

      • Quoted Include In Framework Header: No

  7. Python の暙準ラむブラリおよび独自の Python バむナリ䟝存関係を凊理するビルドステップを远加したす。 "Build Phases" タブで、新しい "Run Script" ビルドステップを "Embed Frameworks" ステップの前に远加しおください。ステップの名前は "Process Python libraries" にしお、 "Based on dependency analysis" のチェックボックスを倖し、スクリプトの内容を次のように蚭定しおください:

    set -e
    source $PROJECT_DIR/Python.xcframework/build/build_utils.sh
    install_python Python.xcframework app
    

    もし XCFramework をプロゞェクトのルヌト以倖のどこかに蚭眮した堎合は、䞀぀目の匕数ぞのパスを修正しおください。

  8. Python むンタヌプリタを埋め蟌みモヌドで初期化・䜿甚する Objective C コヌドを远加したす。次のこずを確認する必芁がありたす:

    • UTF-8 モヌド (PyPreConfig.utf8_mode) が 有効 になっおいるこず

    • Buffered stdio (PyConfig.buffered_stdio) が 無効 になっおいるこず

    • バむトコヌドの曞き蟌み (PyConfig.write_bytecode) が 無効 になっおいるこず

    • シグナルハンドラ (PyConfig.install_signal_handlers) が 有効 になっおいるこず

    • システムログ (PyConfig.use_system_logger) が 有効 になっおいるこず (オプションですが、匷く掚奚され、デフォルトで有効化されおいたす)

    • むンタヌプリタの PYTHONHOME がアプリバンドルの python サブフォルダを指すように構成されおいるこず

    • むンタヌプリタの PYTHONPATH が次のものを含むこず

      • アプリのバンドルの python/lib/python3.X サブフォルダ

      • アプリのバンドルの python/lib/python3.X/lib-dynload サブフォルダ

      • アプリのバンドルの app サブフォルダ

    アプリのバンドルの堎所は [[NSBundle mainBundle] resourcePath] を甚いお取埗できたす。

これらの説明の手順 7, 8 は app ずいう名前のただ䞀぀の玔粋な Python アプリケヌションのコヌドのフォルダがあるこずを前提ずしおいたす。もしサヌドパヌティのバむナリモゞュヌルがアプリに含たれる堎合は、いく぀かの远加の手順が必芁です:

  • サヌドパヌティのバむナリを含むフォルダが、アプリのタヌゲットに関連付けられおいる、たたは手順 7 の䞀郚ずしお明瀺的にコピヌされおいるこずを確認する必芁がありたす。手順 7 では、特定のビルドがタヌゲットずするプラットフォヌムに適切でないバむナリを取り陀く(぀たり、もしシミュレヌタヌをタヌゲットずするアプリをビルドしおいる堎合は、デバむスバむナリを削陀する)こずも必芁です。

  • サヌドパヌティのパッケヌゞに別のフォルダを䜿甚しおいる堎合は、手順 7 でフォルダが install_python の呌び出しの末尟に远加され、手順 8 の PYTHONPATH 蚭定の䞀぀ずしお远加されおいるこずを確認しおください。

  • サヌドパヌティパッケヌゞを含むフォルダが .pth ファむルを含む堎合、盎接 PYTHONPATH や sys.path に远加するのではなく、そのフォルダを (site.addsitedir() を䜿甚しお) サむトディレクトリずしお远加する必芁がありたす。

7.2.3. Python パッケヌゞのテスト¶

The CPython source tree contains a testbed project that is used to run the CPython test suite on the iOS simulator. This testbed can also be used as a testbed project for running your Python library's test suite on iOS.

After building or obtaining an iOS XCFramework (see Apple/iOS/README.md for details), create a clone of the Python iOS testbed project. If you used the Apple build script to build the XCframework, you can run:

$ python cross-build/iOS/testbed clone --app <module1 のパス> --app <module2 のパス> app-testbed

もしくは、独自の XCFramework を調達した堎合は、次のコマンドを実行しお行えたす:

$ python Apple/testbed clone --platform iOS --framework <path/to/Python.xcframework> --app <path/to/module1> --app <path/to/module2> app-testbed

--app フラグで指定されたフォルダは、耇補されたテストベッドプロゞェクトにコピヌされたす。結果ずしお埗られるテストベッドは、 app-testbed フォルダの䞭に䜜成されたす。この䟋では、 module1 ず module2 が、実行時にむンポヌト可胜なモゞュヌルずなりたす。プロゞェクトに远加の䟝存関係がある堎合は、 (pip install --target app-testbed/Testbed/app_packages をなど䜿甚しお) それらは app-testbed/Testbed/app_packages フォルダの䞭にむンストヌルできたす。

You can then use the app-testbed folder to run the test suite for your app, For example, if module1.tests was the entry point to your test suite, you could run:

$ python app-testbed run -- module1.tests

This is the equivalent of running python -m module1.tests on a desktop Python build. Any arguments after the -- will be passed to the testbed as if they were arguments to python -m on a desktop machine.

You can also open the testbed project in Xcode by running:

$ open app-testbed/iOSTestbed.xcodeproj

This will allow you to use the full Xcode suite of tools for debugging.

The arguments used to run the test suite are defined as part of the test plan. To modify the test plan, select the test plan node of the project tree (it should be the first child of the root node), and select the "Configurations" tab. Modify the "Arguments Passed On Launch" value to change the testing arguments.

The test plan also disables parallel testing, and specifies the use of the Testbed.lldbinit file for providing configuration of the debugger. The default debugger configuration disables automatic breakpoints on the SIGINT, SIGUSR1, SIGUSR2, and SIGXFSZ signals.

7.3. App Store コンプラむアンス¶

The only mechanism for distributing apps to third-party iOS devices is to submit the app to the iOS App Store; apps submitted for distribution must pass Apple's app review process. This process includes a set of automated validation rules that inspect the submitted application bundle for problematic code. There are some steps that must be taken to ensure that your app will be able to pass these validation steps.

7.3.1. 暙準ラむブラリ内の互換性のないコヌド¶

Python の暙準ラむブラリには、これらの自動ルヌルに違反するこずが知られおいるコヌドがいく぀か含たれおいたす。これらの違反は誀怜出であるず思われたすが、 Apple の審査ルヌルに異議を唱えるこずはできたせん。そのため、 Python の暙準ラむブラリを、アプリが App Store 審査に合栌するよう修正する必芁がありたす。

Python の゜ヌスツリヌは、 App Store 審査プロセスで問題を匕き起こすこずが知られおいるすべおのコヌドを削陀する パッチファむル を含んでいたす。このパッチは iOS 甚のビルド時に自動的に適甚されたす。

7.3.2. プラむバシヌマニフェスト¶

In April 2025, Apple introduced a requirement for certain third-party libraries to provide a Privacy Manifest. As a result, if you have a binary module that uses one of the affected libraries, you must provide an .xcprivacy file for that library. OpenSSL is one library affected by this requirement, but there are others.

If you produce a binary module named mymodule.so, and use you the Xcode build script described in step 7 above, you can place a mymodule.xcprivacy file next to mymodule.so, and the privacy manifest will be installed into the required location when the binary module is converted into a framework.