704 lines
55 KiB
HTML
704 lines
55 KiB
HTML
<!DOCTYPE html>
|
||
|
||
<html lang="en" data-content_root="../">
|
||
<head>
|
||
<meta charset="utf-8" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="viewport" content="width=device-width, initial-scale=1" />
|
||
<meta property="og:title" content="7. Using Python on iOS" />
|
||
<meta property="og:type" content="website" />
|
||
<meta property="og:url" content="https://docs.python.org/3/using/ios.html" />
|
||
<meta property="og:site_name" content="Python documentation" />
|
||
<meta property="og:description" content="Authors, Russell Keith-Magee (2024-03),. Python on iOS is unlike Python on desktop platforms. On a desktop platform, Python is generally installed as a system resource that can be used by any user ..." />
|
||
<meta property="og:image" content="https://docs.python.org/3/_static/og-image.png" />
|
||
<meta property="og:image:alt" content="Python documentation" />
|
||
<meta name="description" content="Authors, Russell Keith-Magee (2024-03),. Python on iOS is unlike Python on desktop platforms. On a desktop platform, Python is generally installed as a system resource that can be used by any user ..." />
|
||
<meta property="og:image:width" content="200">
|
||
<meta property="og:image:height" content="200">
|
||
<meta name="theme-color" content="#3776ab">
|
||
|
||
<title>7. Using Python on iOS — Python 3.13.3 documentation</title><meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
|
||
<link rel="stylesheet" type="text/css" href="../_static/pygments.css?v=b86133f3" />
|
||
<link rel="stylesheet" type="text/css" href="../_static/pydoctheme.css?v=23252803" />
|
||
<link id="pygments_dark_css" media="(prefers-color-scheme: dark)" rel="stylesheet" type="text/css" href="../_static/pygments_dark.css?v=5349f25f" />
|
||
|
||
<script src="../_static/documentation_options.js?v=5d57ca2d"></script>
|
||
<script src="../_static/doctools.js?v=9bcbadda"></script>
|
||
<script src="../_static/sphinx_highlight.js?v=dc90522c"></script>
|
||
|
||
<script src="../_static/sidebar.js"></script>
|
||
|
||
<link rel="search" type="application/opensearchdescription+xml"
|
||
title="Search within Python 3.13.3 documentation"
|
||
href="../_static/opensearch.xml"/>
|
||
<link rel="author" title="About these documents" href="../about.html" />
|
||
<link rel="index" title="Index" href="../genindex.html" />
|
||
<link rel="search" title="Search" href="../search.html" />
|
||
<link rel="copyright" title="Copyright" href="../copyright.html" />
|
||
<link rel="next" title="8. Editors and IDEs" href="editors.html" />
|
||
<link rel="prev" title="6. Using Python on Android" href="android.html" />
|
||
|
||
<link rel="canonical" href="https://docs.python.org/3/using/ios.html">
|
||
|
||
|
||
|
||
|
||
|
||
<style>
|
||
@media only screen {
|
||
table.full-width-table {
|
||
width: 100%;
|
||
}
|
||
}
|
||
</style>
|
||
<link rel="stylesheet" href="../_static/pydoctheme_dark.css" media="(prefers-color-scheme: dark)" id="pydoctheme_dark_css">
|
||
<link rel="shortcut icon" type="image/png" href="../_static/py.svg" />
|
||
<script type="text/javascript" src="../_static/copybutton.js"></script>
|
||
<script type="text/javascript" src="../_static/menu.js"></script>
|
||
<script type="text/javascript" src="../_static/search-focus.js"></script>
|
||
<script type="text/javascript" src="../_static/themetoggle.js"></script>
|
||
<script type="text/javascript" src="../_static/rtd_switcher.js"></script>
|
||
<meta name="readthedocs-addons-api-version" content="1">
|
||
|
||
</head>
|
||
<body>
|
||
<div class="mobile-nav">
|
||
<input type="checkbox" id="menuToggler" class="toggler__input" aria-controls="navigation"
|
||
aria-pressed="false" aria-expanded="false" role="button" aria-label="Menu" />
|
||
<nav class="nav-content" role="navigation">
|
||
<label for="menuToggler" class="toggler__label">
|
||
<span></span>
|
||
</label>
|
||
<span class="nav-items-wrapper">
|
||
<a href="https://www.python.org/" class="nav-logo">
|
||
<img src="../_static/py.svg" alt="Python logo"/>
|
||
</a>
|
||
<span class="version_switcher_placeholder"></span>
|
||
<form role="search" class="search" action="../search.html" method="get">
|
||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" class="search-icon">
|
||
<path fill-rule="nonzero" fill="currentColor" d="M15.5 14h-.79l-.28-.27a6.5 6.5 0 001.48-5.34c-.47-2.78-2.79-5-5.59-5.34a6.505 6.505 0 00-7.27 7.27c.34 2.8 2.56 5.12 5.34 5.59a6.5 6.5 0 005.34-1.48l.27.28v.79l4.25 4.25c.41.41 1.08.41 1.49 0 .41-.41.41-1.08 0-1.49L15.5 14zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"></path>
|
||
</svg>
|
||
<input placeholder="Quick search" aria-label="Quick search" type="search" name="q" />
|
||
<input type="submit" value="Go"/>
|
||
</form>
|
||
</span>
|
||
</nav>
|
||
<div class="menu-wrapper">
|
||
<nav class="menu" role="navigation" aria-label="main navigation">
|
||
<div class="language_switcher_placeholder"></div>
|
||
|
||
<label class="theme-selector-label">
|
||
Theme
|
||
<select class="theme-selector" oninput="activateTheme(this.value)">
|
||
<option value="auto" selected>Auto</option>
|
||
<option value="light">Light</option>
|
||
<option value="dark">Dark</option>
|
||
</select>
|
||
</label>
|
||
<div>
|
||
<h3><a href="../contents.html">Table of Contents</a></h3>
|
||
<ul>
|
||
<li><a class="reference internal" href="#">7. Using Python on iOS</a><ul>
|
||
<li><a class="reference internal" href="#python-at-runtime-on-ios">7.1. Python at runtime on iOS</a><ul>
|
||
<li><a class="reference internal" href="#ios-version-compatibility">7.1.1. iOS version compatibility</a></li>
|
||
<li><a class="reference internal" href="#platform-identification">7.1.2. Platform identification</a></li>
|
||
<li><a class="reference internal" href="#standard-library-availability">7.1.3. Standard library availability</a></li>
|
||
<li><a class="reference internal" href="#binary-extension-modules">7.1.4. Binary extension modules</a></li>
|
||
<li><a class="reference internal" href="#compiler-stub-binaries">7.1.5. Compiler stub binaries</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#installing-python-on-ios">7.2. Installing Python on iOS</a><ul>
|
||
<li><a class="reference internal" href="#tools-for-building-ios-apps">7.2.1. Tools for building iOS apps</a></li>
|
||
<li><a class="reference internal" href="#adding-python-to-an-ios-project">7.2.2. Adding Python to an iOS project</a></li>
|
||
<li><a class="reference internal" href="#testing-a-python-package">7.2.3. Testing a Python package</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#app-store-compliance">7.3. App Store Compliance</a></li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
|
||
</div>
|
||
<div>
|
||
<h4>Previous topic</h4>
|
||
<p class="topless"><a href="android.html"
|
||
title="previous chapter"><span class="section-number">6. </span>Using Python on Android</a></p>
|
||
</div>
|
||
<div>
|
||
<h4>Next topic</h4>
|
||
<p class="topless"><a href="editors.html"
|
||
title="next chapter"><span class="section-number">8. </span>Editors and IDEs</a></p>
|
||
</div>
|
||
<div role="note" aria-label="source link">
|
||
<h3>This Page</h3>
|
||
<ul class="this-page-menu">
|
||
<li><a href="../bugs.html">Report a Bug</a></li>
|
||
<li>
|
||
<a href="https://github.com/python/cpython/blob/main/Doc/using/ios.rst"
|
||
rel="nofollow">Show Source
|
||
</a>
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
</nav>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
<div class="related" role="navigation" aria-label="Related">
|
||
<h3>Navigation</h3>
|
||
<ul>
|
||
<li class="right" style="margin-right: 10px">
|
||
<a href="../genindex.html" title="General Index"
|
||
accesskey="I">index</a></li>
|
||
<li class="right" >
|
||
<a href="../py-modindex.html" title="Python Module Index"
|
||
>modules</a> |</li>
|
||
<li class="right" >
|
||
<a href="editors.html" title="8. Editors and IDEs"
|
||
accesskey="N">next</a> |</li>
|
||
<li class="right" >
|
||
<a href="android.html" title="6. Using Python on Android"
|
||
accesskey="P">previous</a> |</li>
|
||
|
||
<li><img src="../_static/py.svg" alt="Python logo" style="vertical-align: middle; margin-top: -1px"/></li>
|
||
<li><a href="https://www.python.org/">Python</a> »</li>
|
||
<li class="switchers">
|
||
<div class="language_switcher_placeholder"></div>
|
||
<div class="version_switcher_placeholder"></div>
|
||
</li>
|
||
<li>
|
||
|
||
</li>
|
||
<li id="cpython-language-and-version">
|
||
<a href="../index.html">3.13.3 Documentation</a> »
|
||
</li>
|
||
|
||
<li class="nav-item nav-item-1"><a href="index.html" accesskey="U">Python Setup and Usage</a> »</li>
|
||
<li class="nav-item nav-item-this"><a href=""><span class="section-number">7. </span>Using Python on iOS</a></li>
|
||
<li class="right">
|
||
|
||
|
||
<div class="inline-search" role="search">
|
||
<form class="inline-search" action="../search.html" method="get">
|
||
<input placeholder="Quick search" aria-label="Quick search" type="search" name="q" id="search-box" />
|
||
<input type="submit" value="Go" />
|
||
</form>
|
||
</div>
|
||
|
|
||
</li>
|
||
<li class="right">
|
||
<label class="theme-selector-label">
|
||
Theme
|
||
<select class="theme-selector" oninput="activateTheme(this.value)">
|
||
<option value="auto" selected>Auto</option>
|
||
<option value="light">Light</option>
|
||
<option value="dark">Dark</option>
|
||
</select>
|
||
</label> |</li>
|
||
|
||
</ul>
|
||
</div>
|
||
|
||
<div class="document">
|
||
<div class="documentwrapper">
|
||
<div class="bodywrapper">
|
||
<div class="body" role="main">
|
||
|
||
<section id="using-python-on-ios">
|
||
<span id="using-ios"></span><h1><span class="section-number">7. </span>Using Python on iOS<a class="headerlink" href="#using-python-on-ios" title="Link to this heading">¶</a></h1>
|
||
<dl class="field-list simple">
|
||
<dt class="field-odd">Authors<span class="colon">:</span></dt>
|
||
<dd class="field-odd"><p>Russell Keith-Magee (2024-03)</p>
|
||
</dd>
|
||
</dl>
|
||
<p>Python on iOS is unlike Python on desktop platforms. On a desktop platform,
|
||
Python is generally installed as a system resource that can be used by any user
|
||
of that computer. Users then interact with Python by running a <strong class="program">python</strong>
|
||
executable and entering commands at an interactive prompt, or by running a
|
||
Python script.</p>
|
||
<p>On iOS, there is no concept of installing as a system resource. The only unit
|
||
of software distribution is an “app”. There is also no console where you could
|
||
run a <strong class="program">python</strong> executable, or interact with a Python REPL.</p>
|
||
<p>As a result, the only way you can use Python on iOS is in embedded mode - that
|
||
is, by writing a native iOS application, and embedding a Python interpreter
|
||
using <code class="docutils literal notranslate"><span class="pre">libPython</span></code>, and invoking Python code using the <a class="reference internal" href="../extending/embedding.html#embedding"><span class="std std-ref">Python embedding
|
||
API</span></a>. The full Python interpreter, the standard library, and all
|
||
your Python code is then packaged as a standalone bundle that can be
|
||
distributed via the iOS App Store.</p>
|
||
<p>If you’re looking to experiment for the first time with writing an iOS app in
|
||
Python, projects such as <a class="reference external" href="https://beeware.org">BeeWare</a> and <a class="reference external" href="https://kivy.org">Kivy</a> will provide a much more approachable user experience.
|
||
These projects manage the complexities associated with getting an iOS project
|
||
running, so you only need to deal with the Python code itself.</p>
|
||
<section id="python-at-runtime-on-ios">
|
||
<h2><span class="section-number">7.1. </span>Python at runtime on iOS<a class="headerlink" href="#python-at-runtime-on-ios" title="Link to this heading">¶</a></h2>
|
||
<section id="ios-version-compatibility">
|
||
<h3><span class="section-number">7.1.1. </span>iOS version compatibility<a class="headerlink" href="#ios-version-compatibility" title="Link to this heading">¶</a></h3>
|
||
<p>The minimum supported iOS version is specified at compile time, using the
|
||
<a class="reference internal" href="configure.html#cmdoption-host"><code class="xref std std-option docutils literal notranslate"><span class="pre">--host</span></code></a> option to <code class="docutils literal notranslate"><span class="pre">configure</span></code>. By default, when compiled for iOS,
|
||
Python will be compiled with a minimum supported iOS version of 13.0. To use a
|
||
different minimum iOS version, provide the version number as part of the
|
||
<code class="xref std std-option docutils literal notranslate"><span class="pre">--host</span></code> argument - for example,
|
||
<code class="docutils literal notranslate"><span class="pre">--host=arm64-apple-ios15.4-simulator</span></code> would compile an ARM64 simulator build
|
||
with a deployment target of 15.4.</p>
|
||
</section>
|
||
<section id="platform-identification">
|
||
<h3><span class="section-number">7.1.2. </span>Platform identification<a class="headerlink" href="#platform-identification" title="Link to this heading">¶</a></h3>
|
||
<p>When executing on iOS, <code class="docutils literal notranslate"><span class="pre">sys.platform</span></code> will report as <code class="docutils literal notranslate"><span class="pre">ios</span></code>. This value will
|
||
be returned on an iPhone or iPad, regardless of whether the app is running on
|
||
the simulator or a physical device.</p>
|
||
<p>Information about the specific runtime environment, including the iOS version,
|
||
device model, and whether the device is a simulator, can be obtained using
|
||
<a class="reference internal" href="../library/platform.html#platform.ios_ver" title="platform.ios_ver"><code class="xref py py-func docutils literal notranslate"><span class="pre">platform.ios_ver()</span></code></a>. <a class="reference internal" href="../library/platform.html#platform.system" title="platform.system"><code class="xref py py-func docutils literal notranslate"><span class="pre">platform.system()</span></code></a> will report <code class="docutils literal notranslate"><span class="pre">iOS</span></code> or
|
||
<code class="docutils literal notranslate"><span class="pre">iPadOS</span></code>, depending on the device.</p>
|
||
<p><a class="reference internal" href="../library/os.html#os.uname" title="os.uname"><code class="xref py py-func docutils literal notranslate"><span class="pre">os.uname()</span></code></a> reports kernel-level details; it will report a name of
|
||
<code class="docutils literal notranslate"><span class="pre">Darwin</span></code>.</p>
|
||
</section>
|
||
<section id="standard-library-availability">
|
||
<h3><span class="section-number">7.1.3. </span>Standard library availability<a class="headerlink" href="#standard-library-availability" title="Link to this heading">¶</a></h3>
|
||
<p>The Python standard library has some notable omissions and restrictions on
|
||
iOS. See the <a class="reference internal" href="../library/intro.html#mobile-availability"><span class="std std-ref">API availability guide for iOS</span></a> for
|
||
details.</p>
|
||
</section>
|
||
<section id="binary-extension-modules">
|
||
<h3><span class="section-number">7.1.4. </span>Binary extension modules<a class="headerlink" href="#binary-extension-modules" title="Link to this heading">¶</a></h3>
|
||
<p>One notable difference about iOS as a platform is that App Store distribution
|
||
imposes hard requirements on the packaging of an application. One of these
|
||
requirements governs how binary extension modules are distributed.</p>
|
||
<p>The iOS App Store requires that <em>all</em> binary modules in an iOS app must be
|
||
dynamic libraries, contained in a framework with appropriate metadata, stored
|
||
in the <code class="docutils literal notranslate"><span class="pre">Frameworks</span></code> folder of the packaged app. There can be only a single
|
||
binary per framework, and there can be no executable binary material outside
|
||
the <code class="docutils literal notranslate"><span class="pre">Frameworks</span></code> folder.</p>
|
||
<p>This conflicts with the usual Python approach for distributing binaries, which
|
||
allows a binary extension module to be loaded from any location on
|
||
<code class="docutils literal notranslate"><span class="pre">sys.path</span></code>. To ensure compliance with App Store policies, an iOS project must
|
||
post-process any Python packages, converting <code class="docutils literal notranslate"><span class="pre">.so</span></code> binary modules into
|
||
individual standalone frameworks with appropriate metadata and signing. For
|
||
details on how to perform this post-processing, see the guide for <a class="reference internal" href="#adding-ios"><span class="std std-ref">adding
|
||
Python to your project</span></a>.</p>
|
||
<p>To help Python discover binaries in their new location, the original <code class="docutils literal notranslate"><span class="pre">.so</span></code>
|
||
file on <code class="docutils literal notranslate"><span class="pre">sys.path</span></code> is replaced with a <code class="docutils literal notranslate"><span class="pre">.fwork</span></code> file. This file is a text
|
||
file containing the location of the framework binary, relative to the app
|
||
bundle. To allow the framework to resolve back to the original location, the
|
||
framework must contain a <code class="docutils literal notranslate"><span class="pre">.origin</span></code> file that contains the location of the
|
||
<code class="docutils literal notranslate"><span class="pre">.fwork</span></code> file, relative to the app bundle.</p>
|
||
<p>For example, consider the case of an import <code class="docutils literal notranslate"><span class="pre">from</span> <span class="pre">foo.bar</span> <span class="pre">import</span> <span class="pre">_whiz</span></code>,
|
||
where <code class="docutils literal notranslate"><span class="pre">_whiz</span></code> is implemented with the binary module
|
||
<code class="docutils literal notranslate"><span class="pre">sources/foo/bar/_whiz.abi3.so</span></code>, with <code class="docutils literal notranslate"><span class="pre">sources</span></code> being the location
|
||
registered on <code class="docutils literal notranslate"><span class="pre">sys.path</span></code>, relative to the application bundle. This module
|
||
<em>must</em> be distributed as <code class="docutils literal notranslate"><span class="pre">Frameworks/foo.bar._whiz.framework/foo.bar._whiz</span></code>
|
||
(creating the framework name from the full import path of the module), with an
|
||
<code class="docutils literal notranslate"><span class="pre">Info.plist</span></code> file in the <code class="docutils literal notranslate"><span class="pre">.framework</span></code> directory identifying the binary as a
|
||
framework. The <code class="docutils literal notranslate"><span class="pre">foo.bar._whiz</span></code> module would be represented in the original
|
||
location with a <code class="docutils literal notranslate"><span class="pre">sources/foo/bar/_whiz.abi3.fwork</span></code> marker file, containing
|
||
the path <code class="docutils literal notranslate"><span class="pre">Frameworks/foo.bar._whiz/foo.bar._whiz</span></code>. The framework would also
|
||
contain <code class="docutils literal notranslate"><span class="pre">Frameworks/foo.bar._whiz.framework/foo.bar._whiz.origin</span></code>, containing
|
||
the path to the <code class="docutils literal notranslate"><span class="pre">.fwork</span></code> file.</p>
|
||
<p>When running on iOS, the Python interpreter will install an
|
||
<a class="reference internal" href="../library/importlib.html#importlib.machinery.AppleFrameworkLoader" title="importlib.machinery.AppleFrameworkLoader"><code class="xref py py-class docutils literal notranslate"><span class="pre">AppleFrameworkLoader</span></code></a> that is able to read and
|
||
import <code class="docutils literal notranslate"><span class="pre">.fwork</span></code> files. Once imported, the <code class="docutils literal notranslate"><span class="pre">__file__</span></code> attribute of the
|
||
binary module will report as the location of the <code class="docutils literal notranslate"><span class="pre">.fwork</span></code> file. However, the
|
||
<a class="reference internal" href="../library/importlib.html#importlib.machinery.ModuleSpec" title="importlib.machinery.ModuleSpec"><code class="xref py py-class docutils literal notranslate"><span class="pre">ModuleSpec</span></code></a> for the loaded module will report the
|
||
<code class="docutils literal notranslate"><span class="pre">origin</span></code> as the location of the binary in the framework folder.</p>
|
||
</section>
|
||
<section id="compiler-stub-binaries">
|
||
<h3><span class="section-number">7.1.5. </span>Compiler stub binaries<a class="headerlink" href="#compiler-stub-binaries" title="Link to this heading">¶</a></h3>
|
||
<p>Xcode doesn’t expose explicit compilers for iOS; instead, it uses an <code class="docutils literal notranslate"><span class="pre">xcrun</span></code>
|
||
script that resolves to a full compiler path (e.g., <code class="docutils literal notranslate"><span class="pre">xcrun</span> <span class="pre">--sdk</span> <span class="pre">iphoneos</span>
|
||
<span class="pre">clang</span></code> to get the <code class="docutils literal notranslate"><span class="pre">clang</span></code> for an iPhone device). However, using this script
|
||
poses two problems:</p>
|
||
<ul class="simple">
|
||
<li><p>The output of <code class="docutils literal notranslate"><span class="pre">xcrun</span></code> includes paths that are machine specific, resulting
|
||
in a sysconfig module that cannot be shared between users; and</p></li>
|
||
<li><p>It results in <code class="docutils literal notranslate"><span class="pre">CC</span></code>/<code class="docutils literal notranslate"><span class="pre">CPP</span></code>/<code class="docutils literal notranslate"><span class="pre">LD</span></code>/<code class="docutils literal notranslate"><span class="pre">AR</span></code> definitions that include spaces.
|
||
There is a lot of C ecosystem tooling that assumes that you can split a
|
||
command line at the first space to get the path to the compiler executable;
|
||
this isn’t the case when using <code class="docutils literal notranslate"><span class="pre">xcrun</span></code>.</p></li>
|
||
</ul>
|
||
<p>To avoid these problems, Python provided stubs for these tools. These stubs are
|
||
shell script wrappers around the underingly <code class="docutils literal notranslate"><span class="pre">xcrun</span></code> tools, distributed in a
|
||
<code class="docutils literal notranslate"><span class="pre">bin</span></code> folder distributed alongside the compiled iOS framework. These scripts
|
||
are relocatable, and will always resolve to the appropriate local system paths.
|
||
By including these scripts in the bin folder that accompanies a framework, the
|
||
contents of the <code class="docutils literal notranslate"><span class="pre">sysconfig</span></code> module becomes useful for end-users to compile
|
||
their own modules. When compiling third-party Python modules for iOS, you
|
||
should ensure these stub binaries are on your path.</p>
|
||
</section>
|
||
</section>
|
||
<section id="installing-python-on-ios">
|
||
<h2><span class="section-number">7.2. </span>Installing Python on iOS<a class="headerlink" href="#installing-python-on-ios" title="Link to this heading">¶</a></h2>
|
||
<section id="tools-for-building-ios-apps">
|
||
<h3><span class="section-number">7.2.1. </span>Tools for building iOS apps<a class="headerlink" href="#tools-for-building-ios-apps" title="Link to this heading">¶</a></h3>
|
||
<p>Building for iOS requires the use of Apple’s Xcode tooling. It is strongly
|
||
recommended that you use the most recent stable release of Xcode. This will
|
||
require the use of the most (or second-most) recently released macOS version,
|
||
as Apple does not maintain Xcode for older macOS versions. The Xcode Command
|
||
Line Tools are not sufficient for iOS development; you need a <em>full</em> Xcode
|
||
install.</p>
|
||
<p>If you want to run your code on the iOS simulator, you’ll also need to install
|
||
an iOS Simulator Platform. You should be prompted to select an iOS Simulator
|
||
Platform when you first run Xcode. Alternatively, you can add an iOS Simulator
|
||
Platform by selecting from the Platforms tab of the Xcode Settings panel.</p>
|
||
</section>
|
||
<section id="adding-python-to-an-ios-project">
|
||
<span id="adding-ios"></span><h3><span class="section-number">7.2.2. </span>Adding Python to an iOS project<a class="headerlink" href="#adding-python-to-an-ios-project" title="Link to this heading">¶</a></h3>
|
||
<p>Python can be added to any iOS project, using either Swift or Objective C. The
|
||
following examples will use Objective C; if you are using Swift, you may find a
|
||
library like <a class="reference external" href="https://github.com/pvieito/PythonKit">PythonKit</a> to be
|
||
helpful.</p>
|
||
<p>To add Python to an iOS Xcode project:</p>
|
||
<ol class="arabic">
|
||
<li><p>Build or obtain a Python <code class="docutils literal notranslate"><span class="pre">XCFramework</span></code>. See the instructions in
|
||
<a class="extlink-source reference external" href="https://github.com/python/cpython/tree/3.13/iOS/README.rst">iOS/README.rst</a> (in the CPython source distribution) for details on
|
||
how to build a Python <code class="docutils literal notranslate"><span class="pre">XCFramework</span></code>. At a minimum, you will need a build
|
||
that supports <code class="docutils literal notranslate"><span class="pre">arm64-apple-ios</span></code>, plus one of either
|
||
<code class="docutils literal notranslate"><span class="pre">arm64-apple-ios-simulator</span></code> or <code class="docutils literal notranslate"><span class="pre">x86_64-apple-ios-simulator</span></code>.</p></li>
|
||
<li><p>Drag the <code class="docutils literal notranslate"><span class="pre">XCframework</span></code> into your iOS project. In the following
|
||
instructions, we’ll assume you’ve dropped the <code class="docutils literal notranslate"><span class="pre">XCframework</span></code> into the root
|
||
of your project; however, you can use any other location that you want by
|
||
adjusting paths as needed.</p></li>
|
||
<li><p>Drag the <code class="docutils literal notranslate"><span class="pre">iOS/Resources/dylib-Info-template.plist</span></code> file into your project,
|
||
and ensure it is associated with the app target.</p></li>
|
||
<li><p>Add your application code as a folder in your Xcode project. In the
|
||
following instructions, we’ll assume that your user code is in a folder
|
||
named <code class="docutils literal notranslate"><span class="pre">app</span></code> in the root of your project; you can use any other location by
|
||
adjusting paths as needed. Ensure that this folder is associated with your
|
||
app target.</p></li>
|
||
<li><p>Select the app target by selecting the root node of your Xcode project, then
|
||
the target name in the sidebar that appears.</p></li>
|
||
<li><p>In the “General” settings, under “Frameworks, Libraries and Embedded
|
||
Content”, add <code class="docutils literal notranslate"><span class="pre">Python.xcframework</span></code>, with “Embed & Sign” selected.</p></li>
|
||
<li><p>In the “Build Settings” tab, modify the following:</p>
|
||
<ul class="simple">
|
||
<li><p>Build Options</p>
|
||
<ul>
|
||
<li><p>User Script Sandboxing: No</p></li>
|
||
<li><p>Enable Testability: Yes</p></li>
|
||
</ul>
|
||
</li>
|
||
<li><p>Search Paths</p>
|
||
<ul>
|
||
<li><p>Framework Search Paths: <code class="docutils literal notranslate"><span class="pre">$(PROJECT_DIR)</span></code></p></li>
|
||
<li><p>Header Search Paths: <code class="docutils literal notranslate"><span class="pre">"$(BUILT_PRODUCTS_DIR)/Python.framework/Headers"</span></code></p></li>
|
||
</ul>
|
||
</li>
|
||
<li><p>Apple Clang - Warnings - All languages</p>
|
||
<ul>
|
||
<li><p>Quoted Include In Framework Header: No</p></li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
</li>
|
||
<li><p>Add a build step that copies the Python standard library into your app. In
|
||
the “Build Phases” tab, add a new “Run Script” build step <em>before</em> the
|
||
“Embed Frameworks” step, but <em>after</em> the “Copy Bundle Resources” step. Name
|
||
the step “Install Target Specific Python Standard Library”, disable the
|
||
“Based on dependency analysis” checkbox, and set the script content to:</p>
|
||
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span><span class="nb">set</span><span class="w"> </span>-e
|
||
|
||
mkdir<span class="w"> </span>-p<span class="w"> </span><span class="s2">"</span><span class="nv">$CODESIGNING_FOLDER_PATH</span><span class="s2">/python/lib"</span>
|
||
<span class="k">if</span><span class="w"> </span><span class="o">[</span><span class="w"> </span><span class="s2">"</span><span class="nv">$EFFECTIVE_PLATFORM_NAME</span><span class="s2">"</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"-iphonesimulator"</span><span class="w"> </span><span class="o">]</span><span class="p">;</span><span class="w"> </span><span class="k">then</span>
|
||
<span class="w"> </span><span class="nb">echo</span><span class="w"> </span><span class="s2">"Installing Python modules for iOS Simulator"</span>
|
||
<span class="w"> </span>rsync<span class="w"> </span>-au<span class="w"> </span>--delete<span class="w"> </span><span class="s2">"</span><span class="nv">$PROJECT_DIR</span><span class="s2">/Python.xcframework/ios-arm64_x86_64-simulator/lib/"</span><span class="w"> </span><span class="s2">"</span><span class="nv">$CODESIGNING_FOLDER_PATH</span><span class="s2">/python/lib/"</span>
|
||
<span class="k">else</span>
|
||
<span class="w"> </span><span class="nb">echo</span><span class="w"> </span><span class="s2">"Installing Python modules for iOS Device"</span>
|
||
<span class="w"> </span>rsync<span class="w"> </span>-au<span class="w"> </span>--delete<span class="w"> </span><span class="s2">"</span><span class="nv">$PROJECT_DIR</span><span class="s2">/Python.xcframework/ios-arm64/lib/"</span><span class="w"> </span><span class="s2">"</span><span class="nv">$CODESIGNING_FOLDER_PATH</span><span class="s2">/python/lib/"</span>
|
||
<span class="k">fi</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Note that the name of the simulator “slice” in the XCframework may be
|
||
different, depending the CPU architectures your <code class="docutils literal notranslate"><span class="pre">XCFramework</span></code> supports.</p>
|
||
</li>
|
||
<li><p>Add a second build step that processes the binary extension modules in the
|
||
standard library into “Framework” format. Add a “Run Script” build step
|
||
<em>directly after</em> the one you added in step 8, named “Prepare Python Binary
|
||
Modules”. It should also have “Based on dependency analysis” unchecked, with
|
||
the following script content:</p>
|
||
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span><span class="nb">set</span><span class="w"> </span>-e
|
||
|
||
install_dylib<span class="w"> </span><span class="o">()</span><span class="w"> </span><span class="o">{</span>
|
||
<span class="w"> </span><span class="nv">INSTALL_BASE</span><span class="o">=</span><span class="nv">$1</span>
|
||
<span class="w"> </span><span class="nv">FULL_EXT</span><span class="o">=</span><span class="nv">$2</span>
|
||
|
||
<span class="w"> </span><span class="c1"># The name of the extension file</span>
|
||
<span class="w"> </span><span class="nv">EXT</span><span class="o">=</span><span class="k">$(</span>basename<span class="w"> </span><span class="s2">"</span><span class="nv">$FULL_EXT</span><span class="s2">"</span><span class="k">)</span>
|
||
<span class="w"> </span><span class="c1"># The location of the extension file, relative to the bundle</span>
|
||
<span class="w"> </span><span class="nv">RELATIVE_EXT</span><span class="o">=</span><span class="si">${</span><span class="nv">FULL_EXT</span><span class="p">#</span><span class="nv">$CODESIGNING_FOLDER_PATH</span><span class="p">/</span><span class="si">}</span>
|
||
<span class="w"> </span><span class="c1"># The path to the extension file, relative to the install base</span>
|
||
<span class="w"> </span><span class="nv">PYTHON_EXT</span><span class="o">=</span><span class="si">${</span><span class="nv">RELATIVE_EXT</span><span class="p">/</span><span class="nv">$INSTALL_BASE</span><span class="p">/</span><span class="si">}</span>
|
||
<span class="w"> </span><span class="c1"># The full dotted name of the extension module, constructed from the file path.</span>
|
||
<span class="w"> </span><span class="nv">FULL_MODULE_NAME</span><span class="o">=</span><span class="k">$(</span><span class="nb">echo</span><span class="w"> </span><span class="nv">$PYTHON_EXT</span><span class="w"> </span><span class="p">|</span><span class="w"> </span>cut<span class="w"> </span>-d<span class="w"> </span><span class="s2">"."</span><span class="w"> </span>-f<span class="w"> </span><span class="m">1</span><span class="w"> </span><span class="p">|</span><span class="w"> </span>tr<span class="w"> </span><span class="s2">"/"</span><span class="w"> </span><span class="s2">"."</span><span class="k">)</span><span class="p">;</span>
|
||
<span class="w"> </span><span class="c1"># A bundle identifier; not actually used, but required by Xcode framework packaging</span>
|
||
<span class="w"> </span><span class="nv">FRAMEWORK_BUNDLE_ID</span><span class="o">=</span><span class="k">$(</span><span class="nb">echo</span><span class="w"> </span><span class="nv">$PRODUCT_BUNDLE_IDENTIFIER</span>.<span class="nv">$FULL_MODULE_NAME</span><span class="w"> </span><span class="p">|</span><span class="w"> </span>tr<span class="w"> </span><span class="s2">"_"</span><span class="w"> </span><span class="s2">"-"</span><span class="k">)</span>
|
||
<span class="w"> </span><span class="c1"># The name of the framework folder.</span>
|
||
<span class="w"> </span><span class="nv">FRAMEWORK_FOLDER</span><span class="o">=</span><span class="s2">"Frameworks/</span><span class="nv">$FULL_MODULE_NAME</span><span class="s2">.framework"</span>
|
||
|
||
<span class="w"> </span><span class="c1"># If the framework folder doesn't exist, create it.</span>
|
||
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="o">[</span><span class="w"> </span>!<span class="w"> </span>-d<span class="w"> </span><span class="s2">"</span><span class="nv">$CODESIGNING_FOLDER_PATH</span><span class="s2">/</span><span class="nv">$FRAMEWORK_FOLDER</span><span class="s2">"</span><span class="w"> </span><span class="o">]</span><span class="p">;</span><span class="w"> </span><span class="k">then</span>
|
||
<span class="w"> </span><span class="nb">echo</span><span class="w"> </span><span class="s2">"Creating framework for </span><span class="nv">$RELATIVE_EXT</span><span class="s2">"</span>
|
||
<span class="w"> </span>mkdir<span class="w"> </span>-p<span class="w"> </span><span class="s2">"</span><span class="nv">$CODESIGNING_FOLDER_PATH</span><span class="s2">/</span><span class="nv">$FRAMEWORK_FOLDER</span><span class="s2">"</span>
|
||
<span class="w"> </span>cp<span class="w"> </span><span class="s2">"</span><span class="nv">$CODESIGNING_FOLDER_PATH</span><span class="s2">/dylib-Info-template.plist"</span><span class="w"> </span><span class="s2">"</span><span class="nv">$CODESIGNING_FOLDER_PATH</span><span class="s2">/</span><span class="nv">$FRAMEWORK_FOLDER</span><span class="s2">/Info.plist"</span>
|
||
<span class="w"> </span>plutil<span class="w"> </span>-replace<span class="w"> </span>CFBundleExecutable<span class="w"> </span>-string<span class="w"> </span><span class="s2">"</span><span class="nv">$FULL_MODULE_NAME</span><span class="s2">"</span><span class="w"> </span><span class="s2">"</span><span class="nv">$CODESIGNING_FOLDER_PATH</span><span class="s2">/</span><span class="nv">$FRAMEWORK_FOLDER</span><span class="s2">/Info.plist"</span>
|
||
<span class="w"> </span>plutil<span class="w"> </span>-replace<span class="w"> </span>CFBundleIdentifier<span class="w"> </span>-string<span class="w"> </span><span class="s2">"</span><span class="nv">$FRAMEWORK_BUNDLE_ID</span><span class="s2">"</span><span class="w"> </span><span class="s2">"</span><span class="nv">$CODESIGNING_FOLDER_PATH</span><span class="s2">/</span><span class="nv">$FRAMEWORK_FOLDER</span><span class="s2">/Info.plist"</span>
|
||
<span class="w"> </span><span class="k">fi</span>
|
||
|
||
<span class="w"> </span><span class="nb">echo</span><span class="w"> </span><span class="s2">"Installing binary for </span><span class="nv">$FRAMEWORK_FOLDER</span><span class="s2">/</span><span class="nv">$FULL_MODULE_NAME</span><span class="s2">"</span>
|
||
<span class="w"> </span>mv<span class="w"> </span><span class="s2">"</span><span class="nv">$FULL_EXT</span><span class="s2">"</span><span class="w"> </span><span class="s2">"</span><span class="nv">$CODESIGNING_FOLDER_PATH</span><span class="s2">/</span><span class="nv">$FRAMEWORK_FOLDER</span><span class="s2">/</span><span class="nv">$FULL_MODULE_NAME</span><span class="s2">"</span>
|
||
<span class="w"> </span><span class="c1"># Create a placeholder .fwork file where the .so was</span>
|
||
<span class="w"> </span><span class="nb">echo</span><span class="w"> </span><span class="s2">"</span><span class="nv">$FRAMEWORK_FOLDER</span><span class="s2">/</span><span class="nv">$FULL_MODULE_NAME</span><span class="s2">"</span><span class="w"> </span>><span class="w"> </span><span class="si">${</span><span class="nv">FULL_EXT</span><span class="p">%.so</span><span class="si">}</span>.fwork
|
||
<span class="w"> </span><span class="c1"># Create a back reference to the .so file location in the framework</span>
|
||
<span class="w"> </span><span class="nb">echo</span><span class="w"> </span><span class="s2">"</span><span class="si">${</span><span class="nv">RELATIVE_EXT</span><span class="p">%.so</span><span class="si">}</span><span class="s2">.fwork"</span><span class="w"> </span>><span class="w"> </span><span class="s2">"</span><span class="nv">$CODESIGNING_FOLDER_PATH</span><span class="s2">/</span><span class="nv">$FRAMEWORK_FOLDER</span><span class="s2">/</span><span class="nv">$FULL_MODULE_NAME</span><span class="s2">.origin"</span>
|
||
<span class="w"> </span><span class="o">}</span>
|
||
|
||
<span class="w"> </span><span class="nv">PYTHON_VER</span><span class="o">=</span><span class="k">$(</span>ls<span class="w"> </span>-1<span class="w"> </span><span class="s2">"</span><span class="nv">$CODESIGNING_FOLDER_PATH</span><span class="s2">/python/lib"</span><span class="k">)</span>
|
||
<span class="w"> </span><span class="nb">echo</span><span class="w"> </span><span class="s2">"Install Python </span><span class="nv">$PYTHON_VER</span><span class="s2"> standard library extension modules..."</span>
|
||
<span class="w"> </span>find<span class="w"> </span><span class="s2">"</span><span class="nv">$CODESIGNING_FOLDER_PATH</span><span class="s2">/python/lib/</span><span class="nv">$PYTHON_VER</span><span class="s2">/lib-dynload"</span><span class="w"> </span>-name<span class="w"> </span><span class="s2">"*.so"</span><span class="w"> </span><span class="p">|</span><span class="w"> </span><span class="k">while</span><span class="w"> </span><span class="nb">read</span><span class="w"> </span>FULL_EXT<span class="p">;</span><span class="w"> </span><span class="k">do</span>
|
||
<span class="w"> </span>install_dylib<span class="w"> </span>python/lib/<span class="nv">$PYTHON_VER</span>/lib-dynload/<span class="w"> </span><span class="s2">"</span><span class="nv">$FULL_EXT</span><span class="s2">"</span>
|
||
<span class="w"> </span><span class="k">done</span>
|
||
|
||
<span class="w"> </span><span class="c1"># Clean up dylib template</span>
|
||
<span class="w"> </span>rm<span class="w"> </span>-f<span class="w"> </span><span class="s2">"</span><span class="nv">$CODESIGNING_FOLDER_PATH</span><span class="s2">/dylib-Info-template.plist"</span>
|
||
|
||
<span class="w"> </span><span class="nb">echo</span><span class="w"> </span><span class="s2">"Signing frameworks as </span><span class="nv">$EXPANDED_CODE_SIGN_IDENTITY_NAME</span><span class="s2"> (</span><span class="nv">$EXPANDED_CODE_SIGN_IDENTITY</span><span class="s2">)..."</span>
|
||
<span class="w"> </span>find<span class="w"> </span><span class="s2">"</span><span class="nv">$CODESIGNING_FOLDER_PATH</span><span class="s2">/Frameworks"</span><span class="w"> </span>-name<span class="w"> </span><span class="s2">"*.framework"</span><span class="w"> </span>-exec<span class="w"> </span>/usr/bin/codesign<span class="w"> </span>--force<span class="w"> </span>--sign<span class="w"> </span><span class="s2">"</span><span class="nv">$EXPANDED_CODE_SIGN_IDENTITY</span><span class="s2">"</span><span class="w"> </span><span class="si">${</span><span class="nv">OTHER_CODE_SIGN_FLAGS</span><span class="k">:-</span><span class="si">}</span><span class="w"> </span>-o<span class="w"> </span>runtime<span class="w"> </span>--timestamp<span class="o">=</span>none<span class="w"> </span>--preserve-metadata<span class="o">=</span>identifier,entitlements,flags<span class="w"> </span>--generate-entitlement-der<span class="w"> </span><span class="s2">"{}"</span><span class="w"> </span><span class="se">\;</span>
|
||
</pre></div>
|
||
</div>
|
||
</li>
|
||
<li><p>Add Objective C code to initialize and use a Python interpreter in embedded
|
||
mode. You should ensure that:</p></li>
|
||
</ol>
|
||
<blockquote>
|
||
<div><ul class="simple">
|
||
<li><p>UTF-8 mode (<a class="reference internal" href="../c-api/init_config.html#c.PyPreConfig.utf8_mode" title="PyPreConfig.utf8_mode"><code class="xref c c-member docutils literal notranslate"><span class="pre">PyPreConfig.utf8_mode</span></code></a>) is <em>enabled</em>;</p></li>
|
||
<li><p>Buffered stdio (<a class="reference internal" href="../c-api/init_config.html#c.PyConfig.buffered_stdio" title="PyConfig.buffered_stdio"><code class="xref c c-member docutils literal notranslate"><span class="pre">PyConfig.buffered_stdio</span></code></a>) is <em>disabled</em>;</p></li>
|
||
<li><p>Writing bytecode (<a class="reference internal" href="../c-api/init_config.html#c.PyConfig.write_bytecode" title="PyConfig.write_bytecode"><code class="xref c c-member docutils literal notranslate"><span class="pre">PyConfig.write_bytecode</span></code></a>) is <em>disabled</em>;</p></li>
|
||
<li><p>Signal handlers (<a class="reference internal" href="../c-api/init_config.html#c.PyConfig.install_signal_handlers" title="PyConfig.install_signal_handlers"><code class="xref c c-member docutils literal notranslate"><span class="pre">PyConfig.install_signal_handlers</span></code></a>) are <em>enabled</em>;</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">PYTHONHOME</span></code> for the interpreter is configured to point at the
|
||
<code class="docutils literal notranslate"><span class="pre">python</span></code> subfolder of your app’s bundle; and</p></li>
|
||
<li><p>The <code class="docutils literal notranslate"><span class="pre">PYTHONPATH</span></code> for the interpreter includes:</p>
|
||
<ul>
|
||
<li><p>the <code class="docutils literal notranslate"><span class="pre">python/lib/python3.X</span></code> subfolder of your app’s bundle,</p></li>
|
||
<li><p>the <code class="docutils literal notranslate"><span class="pre">python/lib/python3.X/lib-dynload</span></code> subfolder of your app’s bundle, and</p></li>
|
||
<li><p>the <code class="docutils literal notranslate"><span class="pre">app</span></code> subfolder of your app’s bundle</p></li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
<p>Your app’s bundle location can be determined using <code class="docutils literal notranslate"><span class="pre">[[NSBundle</span> <span class="pre">mainBundle]</span>
|
||
<span class="pre">resourcePath]</span></code>.</p>
|
||
</div></blockquote>
|
||
<p>Steps 8, 9 and 10 of these instructions assume that you have a single folder of
|
||
pure Python application code, named <code class="docutils literal notranslate"><span class="pre">app</span></code>. If you have third-party binary
|
||
modules in your app, some additional steps will be required:</p>
|
||
<ul class="simple">
|
||
<li><p>You need to ensure that any folders containing third-party binaries are
|
||
either associated with the app target, or copied in as part of step 8. Step 8
|
||
should also purge any binaries that are not appropriate for the platform a
|
||
specific build is targeting (i.e., delete any device binaries if you’re
|
||
building an app targeting the simulator).</p></li>
|
||
<li><p>Any folders that contain third-party binaries must be processed into
|
||
framework form by step 9. The invocation of <code class="docutils literal notranslate"><span class="pre">install_dylib</span></code> that processes
|
||
the <code class="docutils literal notranslate"><span class="pre">lib-dynload</span></code> folder can be copied and adapted for this purpose.</p></li>
|
||
<li><p>If you’re using a separate folder for third-party packages, ensure that folder
|
||
is included as part of the <code class="docutils literal notranslate"><span class="pre">PYTHONPATH</span></code> configuration in step 10.</p></li>
|
||
</ul>
|
||
</section>
|
||
<section id="testing-a-python-package">
|
||
<h3><span class="section-number">7.2.3. </span>Testing a Python package<a class="headerlink" href="#testing-a-python-package" title="Link to this heading">¶</a></h3>
|
||
<p>The CPython source tree contains <a class="extlink-source reference external" href="https://github.com/python/cpython/tree/3.13/iOS/testbed">a testbed project</a> 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.</p>
|
||
<p>After building or obtaining an iOS XCFramework (See <a class="extlink-source reference external" href="https://github.com/python/cpython/tree/3.13/iOS/README.rst">iOS/README.rst</a>
|
||
for details), create a clone of the Python iOS testbed project by running:</p>
|
||
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>$<span class="w"> </span>python<span class="w"> </span>iOS/testbed<span class="w"> </span>clone<span class="w"> </span>--framework<span class="w"> </span><path/to/Python.xcframework><span class="w"> </span>--app<span class="w"> </span><path/to/module1><span class="w"> </span>--app<span class="w"> </span><path/to/module2><span class="w"> </span>app-testbed
|
||
</pre></div>
|
||
</div>
|
||
<p>You will need to modify the <code class="docutils literal notranslate"><span class="pre">iOS/testbed</span></code> reference to point to that
|
||
directory in the CPython source tree; any folders specified with the <code class="docutils literal notranslate"><span class="pre">--app</span></code>
|
||
flag will be copied into the cloned testbed project. The resulting testbed will
|
||
be created in the <code class="docutils literal notranslate"><span class="pre">app-testbed</span></code> folder. In this example, the <code class="docutils literal notranslate"><span class="pre">module1</span></code> and
|
||
<code class="docutils literal notranslate"><span class="pre">module2</span></code> would be importable modules at runtime. If your project has
|
||
additional dependencies, they can be installed into the
|
||
<code class="docutils literal notranslate"><span class="pre">app-testbed/iOSTestbed/app_packages</span></code> folder (using <code class="docutils literal notranslate"><span class="pre">pip</span> <span class="pre">install</span> <span class="pre">--target</span>
|
||
<span class="pre">app-testbed/iOSTestbed/app_packages</span></code> or similar).</p>
|
||
<p>You can then use the <code class="docutils literal notranslate"><span class="pre">app-testbed</span></code> folder to run the test suite for your app,
|
||
For example, if <code class="docutils literal notranslate"><span class="pre">module1.tests</span></code> was the entry point to your test suite, you
|
||
could run:</p>
|
||
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>$<span class="w"> </span>python<span class="w"> </span>app-testbed<span class="w"> </span>run<span class="w"> </span>--<span class="w"> </span>module1.tests
|
||
</pre></div>
|
||
</div>
|
||
<p>This is the equivalent of running <code class="docutils literal notranslate"><span class="pre">python</span> <span class="pre">-m</span> <span class="pre">module1.tests</span></code> on a desktop
|
||
Python build. Any arguments after the <code class="docutils literal notranslate"><span class="pre">--</span></code> will be passed to the testbed as
|
||
if they were arguments to <code class="docutils literal notranslate"><span class="pre">python</span> <span class="pre">-m</span></code> on a desktop machine.</p>
|
||
<p>You can also open the testbed project in Xcode by running:</p>
|
||
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>$<span class="w"> </span>open<span class="w"> </span>app-testbed/iOSTestbed.xcodeproj
|
||
</pre></div>
|
||
</div>
|
||
<p>This will allow you to use the full Xcode suite of tools for debugging.</p>
|
||
</section>
|
||
</section>
|
||
<section id="app-store-compliance">
|
||
<h2><span class="section-number">7.3. </span>App Store Compliance<a class="headerlink" href="#app-store-compliance" title="Link to this heading">¶</a></h2>
|
||
<p>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.</p>
|
||
<p>The Python standard library contains some code that is known to violate these
|
||
automated rules. While these violations appear to be false positives, Apple’s
|
||
review rules cannot be challenged; so, it is necessary to modify the Python
|
||
standard library for an app to pass App Store review.</p>
|
||
<p>The Python source tree contains
|
||
<a class="extlink-source reference external" href="https://github.com/python/cpython/tree/3.13/Mac/Resources/app-store-compliance.patch">a patch file</a> that will remove
|
||
all code that is known to cause issues with the App Store review process. This
|
||
patch is applied automatically when building for iOS.</p>
|
||
</section>
|
||
</section>
|
||
|
||
|
||
<div class="clearer"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sphinxsidebar" role="navigation" aria-label="Main">
|
||
<div class="sphinxsidebarwrapper">
|
||
<div>
|
||
<h3><a href="../contents.html">Table of Contents</a></h3>
|
||
<ul>
|
||
<li><a class="reference internal" href="#">7. Using Python on iOS</a><ul>
|
||
<li><a class="reference internal" href="#python-at-runtime-on-ios">7.1. Python at runtime on iOS</a><ul>
|
||
<li><a class="reference internal" href="#ios-version-compatibility">7.1.1. iOS version compatibility</a></li>
|
||
<li><a class="reference internal" href="#platform-identification">7.1.2. Platform identification</a></li>
|
||
<li><a class="reference internal" href="#standard-library-availability">7.1.3. Standard library availability</a></li>
|
||
<li><a class="reference internal" href="#binary-extension-modules">7.1.4. Binary extension modules</a></li>
|
||
<li><a class="reference internal" href="#compiler-stub-binaries">7.1.5. Compiler stub binaries</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#installing-python-on-ios">7.2. Installing Python on iOS</a><ul>
|
||
<li><a class="reference internal" href="#tools-for-building-ios-apps">7.2.1. Tools for building iOS apps</a></li>
|
||
<li><a class="reference internal" href="#adding-python-to-an-ios-project">7.2.2. Adding Python to an iOS project</a></li>
|
||
<li><a class="reference internal" href="#testing-a-python-package">7.2.3. Testing a Python package</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#app-store-compliance">7.3. App Store Compliance</a></li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
|
||
</div>
|
||
<div>
|
||
<h4>Previous topic</h4>
|
||
<p class="topless"><a href="android.html"
|
||
title="previous chapter"><span class="section-number">6. </span>Using Python on Android</a></p>
|
||
</div>
|
||
<div>
|
||
<h4>Next topic</h4>
|
||
<p class="topless"><a href="editors.html"
|
||
title="next chapter"><span class="section-number">8. </span>Editors and IDEs</a></p>
|
||
</div>
|
||
<div role="note" aria-label="source link">
|
||
<h3>This Page</h3>
|
||
<ul class="this-page-menu">
|
||
<li><a href="../bugs.html">Report a Bug</a></li>
|
||
<li>
|
||
<a href="https://github.com/python/cpython/blob/main/Doc/using/ios.rst"
|
||
rel="nofollow">Show Source
|
||
</a>
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
<div id="sidebarbutton" title="Collapse sidebar">
|
||
<span>«</span>
|
||
</div>
|
||
|
||
</div>
|
||
<div class="clearer"></div>
|
||
</div>
|
||
<div class="related" role="navigation" aria-label="Related">
|
||
<h3>Navigation</h3>
|
||
<ul>
|
||
<li class="right" style="margin-right: 10px">
|
||
<a href="../genindex.html" title="General Index"
|
||
>index</a></li>
|
||
<li class="right" >
|
||
<a href="../py-modindex.html" title="Python Module Index"
|
||
>modules</a> |</li>
|
||
<li class="right" >
|
||
<a href="editors.html" title="8. Editors and IDEs"
|
||
>next</a> |</li>
|
||
<li class="right" >
|
||
<a href="android.html" title="6. Using Python on Android"
|
||
>previous</a> |</li>
|
||
|
||
<li><img src="../_static/py.svg" alt="Python logo" style="vertical-align: middle; margin-top: -1px"/></li>
|
||
<li><a href="https://www.python.org/">Python</a> »</li>
|
||
<li class="switchers">
|
||
<div class="language_switcher_placeholder"></div>
|
||
<div class="version_switcher_placeholder"></div>
|
||
</li>
|
||
<li>
|
||
|
||
</li>
|
||
<li id="cpython-language-and-version">
|
||
<a href="../index.html">3.13.3 Documentation</a> »
|
||
</li>
|
||
|
||
<li class="nav-item nav-item-1"><a href="index.html" >Python Setup and Usage</a> »</li>
|
||
<li class="nav-item nav-item-this"><a href=""><span class="section-number">7. </span>Using Python on iOS</a></li>
|
||
<li class="right">
|
||
|
||
|
||
<div class="inline-search" role="search">
|
||
<form class="inline-search" action="../search.html" method="get">
|
||
<input placeholder="Quick search" aria-label="Quick search" type="search" name="q" id="search-box" />
|
||
<input type="submit" value="Go" />
|
||
</form>
|
||
</div>
|
||
|
|
||
</li>
|
||
<li class="right">
|
||
<label class="theme-selector-label">
|
||
Theme
|
||
<select class="theme-selector" oninput="activateTheme(this.value)">
|
||
<option value="auto" selected>Auto</option>
|
||
<option value="light">Light</option>
|
||
<option value="dark">Dark</option>
|
||
</select>
|
||
</label> |</li>
|
||
|
||
</ul>
|
||
</div>
|
||
<div class="footer">
|
||
©
|
||
<a href="../copyright.html">
|
||
|
||
Copyright
|
||
|
||
</a>
|
||
2001-2025, Python Software Foundation.
|
||
<br />
|
||
This page is licensed under the Python Software Foundation License Version 2.
|
||
<br />
|
||
Examples, recipes, and other code in the documentation are additionally licensed under the Zero Clause BSD License.
|
||
<br />
|
||
|
||
See <a href="/license.html">History and License</a> for more information.<br />
|
||
|
||
|
||
<br />
|
||
|
||
The Python Software Foundation is a non-profit corporation.
|
||
<a href="https://www.python.org/psf/donations/">Please donate.</a>
|
||
<br />
|
||
<br />
|
||
Last updated on Apr 08, 2025 (14:33 UTC).
|
||
|
||
<a href="/bugs.html">Found a bug</a>?
|
||
|
||
<br />
|
||
|
||
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 8.2.3.
|
||
</div>
|
||
|
||
</body>
|
||
</html> |