mirror of
				https://github.com/bunny-lab-io/Borealis.git
				synced 2025-11-03 19:41:57 -07:00 
			
		
		
		
	
		
			
				
	
	
		
			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> |