Skip to content

Building Kivy Wheels

ksproject's default bootstraps target Kivy 2.3.x and Kivy 3.0.0. Pre-built wheels are published on the KivySchool indexes — but you don't have to wait for them. Both source trees build with cibuildwheel, so you can produce the exact platform wheels you need yourself, then drop them into your app's wheelhouse.

Typical reasons to do this:

  • You patched Kivy and want your fork on device
  • You want to track Kivy master ahead of published wheels
  • You need an arch or platform combination that isn't published yet

Prerequisites

Add cibuildwheel (3.2 or newer — the first release supporting both iOS and Android targets) to your app's dev dependencies. Like ksproject itself, it lives in your project — dev-group dependencies stay on your dev machine and are never installed into the app's on-device site-packages:

# in your ksproject app root
uv add cibuildwheel --dev

The build commands below run from inside the Kivy clone, so they invoke cibuildwheel through your app's environment with uv run --project ../myapp — adjust that path to wherever your app actually lives.

What you can build depends on your host machine:

Target Host requirement
iOS macOS with Xcode
Android Linux or macOS, with an Android NDK
macOS macOS with Xcode command line tools
Linux Linux (or any host with Docker)
Windows Windows

Build only the Python version you ship

ksproject bundles CPython 3.13. Restrict cibuildwheel to it and skip the rest:

export CIBW_BUILD="cp313-*"

Kivy 2.3.x (kivy2x)

kivy-school/kivy2x is the maintained Kivy 2.3.x tree with cibuildwheel configuration baked in — no extra environment setup beyond the Android NDK.

git clone https://github.com/kivy-school/kivy2x
cd kivy2x
uv run --project ../myapp cibuildwheel --platform ios --archs all --output-dir ./wheelhouse

--archs all builds device (arm64_iphoneos) and simulator (arm64_iphonesimulator, x86_64_iphonesimulator) wheels.

ksproject already manages an NDK — ask it for the path. Run the export from your app's root with uv run, then switch to the kivy2x clone:

# in your ksproject app root
export ANDROID_NDK_HOME=$(uv run ksproject android get-path ndk)

cd ../kivy2x   # wherever you cloned it
uv run --project ../myapp cibuildwheel --platform android --archs all --output-dir ./wheelhouse

--archs all builds arm64_v8a and x86_64 wheels.

uv run --project ../myapp cibuildwheel --platform macos --archs all --output-dir ./wheelhouse

(--platform can be omitted on a macOS host — it defaults to the host platform.)

uv run --project ../myapp cibuildwheel --platform linux --archs all --output-dir ./wheelhouse

(--platform can be omitted on a Linux host.)

uv run --project ..\myapp cibuildwheel --platform windows --archs all --output-dir ./wheelhouse

(--platform can be omitted on a Windows host.)

The wheels land in ./wheelhouse inside the clone — copy them into your app afterwards (see Using the wheels).


Kivy 3.0.0 (master)

Kivy 3.0.0 builds from the official kivy/kivy master branch. Unlike kivy2x, its native dependencies (SDL3 and friends) must be compiled first — the repo ships tools/build_*_dependencies.sh scripts for this, which you hook into cibuildwheel via CIBW_BEFORE_ALL_*.

git clone https://github.com/kivy/kivy
cd kivy
export KIVY_DEPS_ROOT=$(pwd)/ios-kivy-dependencies
export CIBW_BEFORE_ALL_IOS=./tools/build_ios_dependencies.sh
uv run --project ../myapp cibuildwheel --platform ios --archs all --output-dir ./wheelhouse
uv run ./tools/add-ios-frameworks.py ./wheelhouse

The final step embeds the dependency xcframeworks into the wheels — don't skip it, the wheels won't link on device without it.

Work in progress

Android wheels for Kivy 3.0.0 are not buildable out-of-the-box yet. The remaining pieces:

  • A build_android_dependencies.sh before-all script (doesn't exist upstream yet)
  • Packaging of the ThorVG dependency for Android
  • A post-build step to bundle SDL3 / ThorVG shared libraries into the wheel's .libs/ so they end up merged into site-packages/.libs

Once those land, the build will look like:

# in your ksproject app root
export ANDROID_NDK_HOME=$(uv run ksproject android get-path ndk)

cd ../kivy   # wherever you cloned it
export CIBW_BEFORE_ALL_ANDROID="./tools/build_android_dependencies.sh"
uv run --project ../myapp cibuildwheel --platform android --archs all --output-dir ./wheelhouse

Until then, use kivy2x for Android.

export CIBW_BEFORE_ALL_MACOS="./tools/build_macos_dependencies.sh"
uv run --project ../myapp cibuildwheel --platform macos --archs all --output-dir ./wheelhouse
export CIBW_BEFORE_ALL_LINUX="./tools/build_linux_dependencies.sh"
uv run --project ../myapp cibuildwheel --platform linux --archs all --output-dir ./wheelhouse

Using the Wheels in Your App

Copy the built wheels into your ksproject app's wheelhouse:

cp ./wheelhouse/*.whl /path/to/myapp/wheelhouse/

Then make sure your dependency constraint matches what you built:

The default constraint already covers it:

dependencies = [
    "kivy>=2.3.1,<3.0.0",
]

Master builds a pre-release version, so pin it exactly (an exact pin opts in to pre-releases):

dependencies = [
    "kivy==3.0.0.dev0",
]

Build as usual — uv resolves the wheelhouse via find-links and installs your wheels into the cross-compiled site-packages:

uv run ksproject android build
# or
uv run ksproject apple build

Verify which wheel was picked

The uv pip install output during the build lists the resolved distributions. A wheel installed from the wheelhouse shows a file:// path instead of an index URL.