Downloads and caches a Chaquopy CPython distribution so Android builds can embed Python.
Why Chaquopy
Chaquopy is currently the only actively-maintained source of pre-built
CPython binaries for Android. BeeWare's Python-Android-support
(the iOS sibling we already use) hasn't shipped a Python 3.11+ release.
Chaquopy is Apache 2.0 (since 2025), publishes to Maven Central, and
ships exactly the .so files we need:
target-VSN-arm64-v8a.zip:
jniLibs/arm64-v8a/libpython3.13.so ← interpreter
jniLibs/arm64-v8a/libcrypto_python.so ← OpenSSL crypto
jniLibs/arm64-v8a/libssl_python.so ← OpenSSL SSL
jniLibs/arm64-v8a/libsqlite3_python.so ← bundled SQLite
lib-dynload/arm64-v8a/*.so ← C extensions
include/python3.13/ ← headers (NIF compile)
target-VSN-stdlib.zip:
os.py, urllib/, email/, … ← shared pure-Python
target-VSN-x86_64.zip:
Same as arm64-v8a but for x86_64 emulator slice.We only use these binaries — Chaquopy's Java<->Python bridge is bypassed. Pythonx's NIF dlopens libpython3.13.so directly via the same path contract as iOS, just with Android paths.
Architectures
arm64-v8a— modern Android phones. Required.x86_64— Android emulators on Intel/AMD development machines. Required for sim development.armeabi-v7a(32-bit) — NOT supported. Chaquopy dropped 32-bit Android Python a few releases back. iOS-era 32-bit Android phones (~2017 and earlier) cannot run Pythonx-enabled Mob apps.
Mirrors PythonAppleSupport
Same caching pattern: ~/.mob/cache/python-android-support-<version>/,
valid_dir?/1 for layout validation, downloads on-demand via
MobDev.NativeBuild when Pythonx is in the user's project.
Summary
Functions
Supported ABIs (the per-arch artifacts we extract).
URL the per-variant artifact is fetched from.
Ensures Chaquopy's Python distribution is cached and extracted.
Returns {:ok, extracted_dir} or {:error, reason}.
Returns the cached extraction directory path.
Per-abi C headers for cross-compiling NIFs (pythonx, etc.) against the bundled libpython.
Per-abi jniLibs/<abi> subtree containing libpython.so + its
bundled OpenSSL/SQLite dependencies.
Per-abi lib-dynload/<abi> subtree with arch-specific Python C
extensions (_ssl, _ctypes, _hashlib, …).
Path to libpython3.13.so for a given ABI.
Pinned Python version (3.13).
Pinned Chaquopy target version (3.13.9-0, …).
Shared (slice-independent) Python standard library directory.
Tarball file name for a given variant (arm64-v8a / x86_64 / stdlib).
Validates the extracted bundle has the expected layout: per-abi jniLibs/<abi>/libpython3.13.so, lib-dynload/<abi>/, headers, and the shared stdlib.
Functions
@spec abis() :: [String.t()]
Supported ABIs (the per-arch artifacts we extract).
URL the per-variant artifact is fetched from.
Ensures Chaquopy's Python distribution is cached and extracted.
Returns {:ok, extracted_dir} or {:error, reason}.
Three artifacts get downloaded: per-abi binary zips for arm64-v8a
and x86_64, plus the shared stdlib zip.
@spec extracted_dir() :: String.t()
Returns the cached extraction directory path.
Per-abi C headers for cross-compiling NIFs (pythonx, etc.) against the bundled libpython.
Per-abi jniLibs/<abi> subtree containing libpython.so + its
bundled OpenSSL/SQLite dependencies.
Per-abi lib-dynload/<abi> subtree with arch-specific Python C
extensions (_ssl, _ctypes, _hashlib, …).
Path to libpython3.13.so for a given ABI.
@spec python_version() :: String.t()
Pinned Python version (3.13).
@spec release_tag() :: String.t()
Pinned Chaquopy target version (3.13.9-0, …).
Shared (slice-independent) Python standard library directory.
Tarball file name for a given variant (arm64-v8a / x86_64 / stdlib).
Validates the extracted bundle has the expected layout: per-abi jniLibs/<abi>/libpython3.13.so, lib-dynload/<abi>/, headers, and the shared stdlib.
Public for testing (per AGENTS.md convention).