Skip to content

Commit 5eb12ff

Browse files
committed
fix(android): switch to Kivy master + p4a develop for Python 3.14
Kivy 2.3.1 ships pre-generated Cython C that calls _PyLong_AsByteArray with 5 args. Python 3.14 added a 6th `with_exceptions` parameter, so buildozer dies during the Cython extension compile with: error: too few arguments to function call, expected 6, have 5 note: '_PyLong_AsByteArray' declared here (... 6 params) The p4a project tracked this in kivy/python-for-android#3274 and shipped the auto-resolve recipe in PR #3271; on the user side, the documented fix is to use Kivy master (which is built with Cython >= 3.1 that emits the new 6-arg call) plus p4a develop + API 36 + NDK r29. Changes: - buildozer.spec: kivy==2.3.0 -> kivy==master; android.api 34 -> 36; android.ndk 25b -> 29; android.sdk 34 -> 36; comment block rewritten to document the new tested combination. - build.sh: auto-resolve ANDROIDNDK from $ANDROID_SDK_ROOT/ndk/29.*; auto-detect buildozer in ~/venv_p4a_develop/bin first (the venv Buildozer docs require for the Python 3.14 path); ANDROIDAPI 34 -> 36; NDKAPI 21 -> 26; ANDROIDNDKVER 25b -> 29. - docs/ANDROID_BUILD.md: rewrite \u00a71 (pre-flight) for the python3.14 venv install; \u00a72 (SDK) for platform 36 / build-tools 36 / ndk r29; \u00a74 (build) to source the venv first; expanded troubleshooting table with the _PyLong_AsByteArray entry and links to upstream issues. Refs: - https://buildozer.readthedocs.io/en/latest/installation/ - kivy/python-for-android#3271 - kivy/python-for-android#3274
1 parent 64e516d commit 5eb12ff

3 files changed

Lines changed: 110 additions & 43 deletions

File tree

build.sh

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,11 @@
1212
#
1313
# Expects an Arch Linux host with:
1414
# - jdk17-openjdk
15-
# - android-sdk-cmdline-tools-latest (AUR) + platform 34 + build-tools 34.0.0
16-
# - Android NDK 25b (25.1.8937393) — installed via sdkmanager (see docs/ANDROID_BUILD.md)
17-
# - buildozer >= 1.5.0 (pipx or pip --user)
15+
# - android-sdk-cmdline-tools-latest (AUR) + platform 36 + build-tools 36.0.0
16+
# - Android NDK r29 — installed via sdkmanager (see docs/ANDROID_BUILD.md)
17+
# - Python 3.14 venv at ~/venv_p4a_develop with:
18+
# buildozer (master from git), cython==0.29.34, legacy-cgi, setuptools
19+
# - See docs/ANDROID_BUILD.md §1 for one-shot setup.
1820
# ----------------------------------------
1921
set -euo pipefail
2022
unset GIT_OPTIONAL_LOCKS
@@ -25,24 +27,48 @@ export JAVA_HOME=/usr/lib/jvm/java-17-openjdk
2527
export ANDROID_HOME=/opt/android-sdk
2628
export ANDROID_SDK_ROOT=/opt/android-sdk
2729
export ANDROIDSDK="${ANDROID_SDK_ROOT}"
28-
export ANDROIDNDK="${ANDROID_SDK_ROOT}/ndk/25.1.8937393"
29-
export ANDROIDAPI=34
30-
export NDKAPI=21 # min SDK — keep ≤ NDK platform floor
31-
export ANDROIDNDKVER=25b
30+
# Resolve NDK r29 install path (sdkmanager installs to ndk/<full-version>)
31+
if [ -z "${ANDROIDNDK:-}" ]; then
32+
if [ -d "${ANDROID_SDK_ROOT}/ndk" ]; then
33+
ANDROIDNDK="$(find "${ANDROID_SDK_ROOT}/ndk" -maxdepth 1 -mindepth 1 -type d -name '29.*' | sort | tail -1)"
34+
fi
35+
: "${ANDROIDNDK:=${ANDROID_SDK_ROOT}/ndk/29.0.13599879}"
36+
fi
37+
export ANDROIDNDK
38+
export ANDROIDAPI=36
39+
export NDKAPI=26 # min SDK — matches android.ndk_api in buildozer.spec
40+
export ANDROIDNDKVER=29
3241

3342
export PATH="${ANDROID_SDK_ROOT}/cmdline-tools/latest/bin:${ANDROID_SDK_ROOT}/platform-tools:${JAVA_HOME}/bin:/usr/bin:/bin"
3443

3544
# Strip any pip mirrors that leak from the user shell — they break p4a wheels.
3645
PIP_CLEAN_ENV=(env -u PIP_EXTRA_INDEX_URL -u PIP_INDEX_URL -u PIP_FIND_LINKS)
3746

47+
# Prefer the Python 3.14 venv if present (matches Buildozer docs p4a-develop path).
48+
BUILDOZER_BIN=""
49+
for cand in \
50+
"${HOME}/venv_p4a_develop/bin/buildozer" \
51+
"${HOME}/.local/bin/buildozer" \
52+
"$(command -v buildozer 2>/dev/null || true)"; do
53+
if [ -n "${cand}" ] && [ -x "${cand}" ]; then
54+
BUILDOZER_BIN="${cand}"
55+
break
56+
fi
57+
done
58+
if [ -z "${BUILDOZER_BIN}" ]; then
59+
echo "[build.sh] buildozer not found. See docs/ANDROID_BUILD.md §1 to set up" >&2
60+
echo " a Python 3.14 venv with buildozer master + cython 0.29.34." >&2
61+
exit 127
62+
fi
63+
3864
# ── Subcommand dispatch ──────────────────────────────────────────────────────
3965
MODE="${1:-debug}"
4066
shift || true
4167

4268
case "${MODE}" in
4369
clean)
4470
echo "[build.sh] cleaning .buildozer and bin/ ..."
45-
"${PIP_CLEAN_ENV[@]}" ~/.local/bin/buildozer android clean || true
71+
"${PIP_CLEAN_ENV[@]}" "${BUILDOZER_BIN}" android clean || true
4672
rm -rf .buildozer bin
4773
echo "[build.sh] clean complete. Re-run ./build.sh debug or ./build.sh release."
4874
exit 0
@@ -64,7 +90,8 @@ esac
6490
echo "[build.sh] JAVA_HOME=${JAVA_HOME}"
6591
echo "[build.sh] ANDROID_HOME=${ANDROID_HOME}"
6692
echo "[build.sh] ANDROIDNDK=${ANDROIDNDK}"
93+
echo "[build.sh] BUILDOZER=${BUILDOZER_BIN}"
6794
echo "[build.sh] target=${TARGET}"
6895

6996
# shellcheck disable=SC2086
70-
"${PIP_CLEAN_ENV[@]}" ~/.local/bin/buildozer ${TARGET} "$@" 2>&1 | tee ~/buildozer_debug.log
97+
"${PIP_CLEAN_ENV[@]}" "${BUILDOZER_BIN}" ${TARGET} "$@" 2>&1 | tee ~/buildozer_debug.log

buildozer.spec

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,22 @@
22
# Qompass AI — ONTrack Android build configuration
33
# Copyright (C) 2026 Qompass AI, All rights reserved.
44
# ----------------------------------------------------
5-
# Tested combinations (May 2026):
6-
# buildozer == 1.5.0
7-
# python-for-android (p4a) == develop
8-
# Android SDK platform 34 build-tools 34.0.0
9-
# Android NDK 25b (25.1.8937393) <-- newer NDKs break p4a's CPython recipe
5+
# Tested combinations (May 2026, Python 3.14 / Play Store target):
6+
# buildozer == git+https://github.com/kivy/buildozer (master)
7+
# python-for-android == develop (required for Python 3.14)
8+
# cython == 0.29.34 (host) ; p4a builds Kivy with its own cython 0.29.36
9+
# Android SDK platform 36 build-tools 36.0.0
10+
# Android NDK 29 (r29) <-- required by p4a develop
1011
# JDK 17 (jdk17-openjdk on Arch)
11-
# Python 3.11 on host
12+
# Python 3.14 on host (`python3.14 -m venv venv_p4a_develop`)
13+
#
14+
# Why Kivy is pinned to `master` (not 2.3.1):
15+
# Kivy 2.3.1 ships pre-generated Cython C that calls `_PyLong_AsByteArray`
16+
# with 5 args. Python 3.14 changed that signature to 6 args (added
17+
# `with_exceptions`), so the build dies with:
18+
# error: too few arguments to function call, expected 6, have 5
19+
# Kivy master regenerates Cython with cython>=3.1 (Python-3.14-aware).
20+
# See https://github.com/kivy/python-for-android/pull/3271 (closes #3274).
1221
#
1322
# Build: bash build.sh # debug APK -> bin/
1423
# Release: buildozer android release # unsigned AAB -> bin/ (sign with apksigner)
@@ -32,7 +41,7 @@ source.exclude_patterns = ontrack.spec,Cargo.toml,Cargo.lock,flake.nix,flak
3241

3342
# Comma-separated, single line — buildozer / p4a parses this very strictly.
3443
# Do NOT mix newlines and commas.
35-
requirements = python3,kivy==2.3.0,android,plyer,pyjnius,requests,certifi,urllib3,chardet,idna,charset-normalizer,python-dotenv,pillow,openssl,sqlite3,libffi
44+
requirements = python3,kivy==master,android,plyer,pyjnius,requests,certifi,urllib3,chardet,idna,charset-normalizer,python-dotenv,pillow,openssl,sqlite3,libffi
3645

3746
orientation = portrait
3847
fullscreen = 0
@@ -42,11 +51,11 @@ presplash.color = #002855
4251
presplash.keep_on_top = 1
4352

4453
# ── Android ────────────────────────────────────────────────────────────────
45-
android.api = 34
54+
android.api = 36
4655
android.minapi = 26
47-
android.ndk = 25b
56+
android.ndk = 29
4857
android.ndk_api = 26
49-
android.sdk = 34
58+
android.sdk = 36
5059
android.archs = arm64-v8a, armeabi-v7a
5160
android.allow_backup = 0
5261
android.copy_libs = 1

docs/ANDROID_BUILD.md

Lines changed: 55 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,26 @@
33
This is the reference procedure for building the OnTrack Kivy app into a
44
Google Play–ready Android App Bundle (`.aab`) on an Arch Linux workstation.
55

6-
It documents the exact toolchain pins that work as of May 2026. The previous
7-
build failure (`Py_DEPRECATED(VERSION_UNUSED) __attribute__((__deprecated__))`
8-
during `pythonforandroid.toolchain create`) was caused by:
9-
10-
1. A malformed multi-line `requirements =` in `buildozer.spec` that p4a was
11-
parsing as a single recipe name.
12-
2. Desktop-only dependencies (`faster-whisper`, `ctranslate2`, `ortools`,
13-
`geopy`, `numpy`, `pandas`) that have no python-for-android recipe.
14-
3. Android NDK 29, which breaks p4a's CPython recipe.
15-
16-
The fixes in this branch (`fix/android-build`) address all three.
6+
It documents the exact toolchain pins that work as of May 2026.
7+
8+
### Build failures this branch resolves
9+
10+
1. **`Py_DEPRECATED(VERSION_UNUSED)` during `pythonforandroid.toolchain create`**
11+
caused by a malformed multi-line `requirements =` in `buildozer.spec` that
12+
p4a parsed as a single recipe name, plus desktop-only deps
13+
(`faster-whisper`, `ctranslate2`, `ortools`, `geopy`, `numpy`, `pandas`) that
14+
have no python-for-android recipe.
15+
2. **`_PyLong_AsByteArray ... too few arguments to function call, expected 6,
16+
have 5`** while compiling Kivy/Cython modules — Python 3.14 changed the
17+
`_PyLong_AsByteArray` C-API signature, and the pre-generated Cython C in
18+
Kivy 2.3.x release tarballs still uses the old 5-arg call. **Fix:** pin
19+
`kivy==master` in `requirements`, switch to `p4a.branch = develop`, and
20+
target `android.api = 36 / android.ndk = 29` per the
21+
[official Buildozer Python 3.14 path](https://buildozer.readthedocs.io/en/latest/installation/).
22+
See [p4a PR #3271](https://github.com/kivy/python-for-android/pull/3271)
23+
(closes [#3274](https://github.com/kivy/python-for-android/issues/3274)).
24+
25+
All fixes live on the `fix/android-build` branch.
1726

1827
---
1928

@@ -31,13 +40,25 @@ sudo pacman -S --needed base-devel git python python-pip \
3140
autoconf automake libtool pkgconf cmake ninja \
3241
zlib openssl libffi sqlite ccache unzip
3342

34-
# Buildozer — pin to a release that knows about NDK 25.
35-
pip install --user --upgrade 'buildozer>=1.5.0' Cython==0.29.36
43+
# Python 3.14 — required by p4a develop (the only branch that supports the
44+
# new _PyLong_AsByteArray signature).
45+
sudo pacman -S --needed python # Arch's `python` package is 3.14 in May 2026
3646

37-
# Make sure ~/.local/bin is on PATH (add to ~/.zshrc/.bashrc if missing).
38-
export PATH="$HOME/.local/bin:$PATH"
47+
# Create the isolated Python 3.14 venv used for buildozer + p4a develop.
48+
python3.14 -m venv ~/venv_p4a_develop
49+
source ~/venv_p4a_develop/bin/activate
50+
pip install --upgrade pip
51+
pip install git+https://github.com/kivy/buildozer
52+
pip install legacy-cgi setuptools 'cython==0.29.34'
53+
54+
# Verify (should print 1.6.x.dev0 from git).
55+
buildozer --version
3956
```
4057

58+
> **Why a venv?** `build.sh` auto-detects `~/venv_p4a_develop/bin/buildozer`
59+
> first, then falls back to `~/.local/bin/buildozer`. Keeping the Python 3.14
60+
> build env separate avoids polluting your system Python.
61+
4162
Set the env vars the build script expects (also add to your shell rc):
4263

4364
```bash
@@ -47,22 +68,26 @@ export ANDROID_SDK_ROOT=/opt/android-sdk
4768
export PATH="$ANDROID_SDK_ROOT/cmdline-tools/latest/bin:$ANDROID_SDK_ROOT/platform-tools:$JAVA_HOME/bin:$PATH"
4869
```
4970

50-
## 2. Install Android SDK + NDK 25b
71+
## 2. Install Android SDK + NDK r29
72+
73+
p4a `develop` requires **API 36 / NDK r29**. The old `NDK 25b` path does not
74+
work with Python 3.14.
5175

5276
```bash
5377
# Accept all licenses first.
5478
yes | sdkmanager --licenses
5579

56-
# Platform 34 + matching build-tools + NDK 25b (the only NDK p4a is happy with).
80+
# Platform 36 + matching build-tools + NDK r29 (matches buildozer.spec pins).
5781
sdkmanager \
5882
"platform-tools" \
59-
"platforms;android-34" \
60-
"build-tools;34.0.0" \
61-
"ndk;25.1.8937393"
83+
"platforms;android-36" \
84+
"build-tools;36.0.0" \
85+
"ndk;29.0.13599879"
6286
```
6387

64-
After this, `$ANDROID_SDK_ROOT/ndk/25.1.8937393` must exist. The build script
65-
exports `ANDROIDNDK` to that exact path.
88+
After this, `$ANDROID_SDK_ROOT/ndk/29.*` must exist. `build.sh` auto-resolves
89+
`ANDROIDNDK` by globbing that directory, so the exact patch version doesn't
90+
matter — any `29.x.y` install will be picked up.
6691

6792
## 3. Clone and check out the fix branch
6893

@@ -74,7 +99,11 @@ git checkout fix/android-build
7499

75100
## 4. Build
76101

102+
Activate the venv first so `buildozer` resolves to the Python 3.14 install:
103+
77104
```bash
105+
source ~/venv_p4a_develop/bin/activate
106+
78107
# Always start from a clean cache the first time after pulling toolchain changes.
79108
./build.sh clean
80109

@@ -278,12 +307,14 @@ the other forms are Console-only.
278307

279308
| Symptom | Cause | Fix |
280309
|---------|-------|-----|
281-
| `Py_DEPRECATED(VERSION_UNUSED) __attribute__((__deprecated__))` during `toolchain create` | NDK too new (>= 26) | Re-install NDK 25b: `sdkmanager "ndk;25.1.8937393"` |
310+
| `_PyLong_AsByteArray ... too few arguments to function call, expected 6, have 5` while compiling Kivy/Cython | Python 3.14 changed the `_PyLong_AsByteArray` C-API; Kivy 2.3.x ships pre-generated Cython C with the old 5-arg call | Use `kivy==master` in `requirements`, `p4a.branch = develop`, `android.api = 36`, `android.ndk = 29`. Already pinned in this branch's `buildozer.spec`. |
282311
| `Recipe with name '<long-string>' not found` | Multi-line `requirements =` in `buildozer.spec` | Keep `requirements =` on one comma-separated line |
283312
| `Could not find ortools / faster-whisper / numpy` | Desktop-only dep in mobile requirements | Remove from `buildozer.spec`; guard import in code |
284313
| `Gradle build failed: Unsupported class file major version 65` | Wrong JDK | `export JAVA_HOME=/usr/lib/jvm/java-17-openjdk` |
285-
| `aidl is missing` | build-tools not installed | `sdkmanager "build-tools;34.0.0"` |
314+
| `aidl is missing` | build-tools not installed | `sdkmanager "build-tools;36.0.0"` |
315+
| `Py_DEPRECATED(VERSION_UNUSED) __attribute__((__deprecated__))` during `toolchain create` | Mixing p4a `master` with Python 3.14, or running NDK r25 against Python 3.14 sources | Use Python 3.14 venv + `p4a.branch = develop` + NDK r29 as documented in §1–2 |
286316
| Build cache wedged after upgrading p4a | Stale `.buildozer/` | `./build.sh clean` |
317+
| `buildozer not found` from `build.sh` | Venv not activated or installed elsewhere | `source ~/venv_p4a_develop/bin/activate` (see §1) |
287318

288319
## Reference
289320

0 commit comments

Comments
 (0)