Skip to main content

ksproject

Kivy School Project Manager — A cross-platform build toolchain for Python apps targeting Android (iOS/macOS, windows and linux soon).

ksproject generates a pure AGP (Android Gradle Plugin) Gradle project, downloads the Android SDK, NDK, and JDK completely on demand, and builds your APK, AAB, or AAR.

No buildozer, no python-for-android at build time — just a clean, native Gradle project under project_dist/gradle/ that you can open and debug directly in Android Studio.


Requirements

  • Python 3.13
  • uv (used for environment and dependency management)

Everything else (Android SDK, NDK, JDK, Gradle wrapper) is downloaded automatically on the first build into .kivyschool/ inside your project directory or globally.


1. Create a New Project

uv init --package hello-world --python 3.13
cd hello-world
uv add git+https://github.com/kivy-school/ksproject@master --dev
uv run ksproject init

ksproject init handles the heavy lifting of project scaffolding. It:

  • Writes a starter main.py and app.kv in src/hello_world/.
  • Creates a src/hello_world/services/ directory (with an __init__.py) for Android background services.
  • Adds a comprehensive [tool.kivy-school] block to your pyproject.toml.
  • Generates AndroidManifest.tmpl.xml and build.tmpl.gradle.kts in your project root so you can customize native build behaviors directly.
  • Creates a .java folder for native code injections.

2. Add Kivy

uv add kivy

3. Add Platform-Specific Dependencies

pyjnius is only meaningful on Android. Mark it with a PEP 508 marker so uv won't try to install it on macOS, Linux, or Windows:

uv add "pyjnius ; sys_platform == 'android'"

Same trick for iOS (coming soon):

uv add "pyobjus ; sys_platform == 'ios'"

Optional scientific stack:

uv add numpy matplotlib

4. Run on Desktop

uv run hello-world

This launches the entry point declared in pyproject.toml — the exact same code that will run on Android, with no changes needed.


5. Build for Android

uv run ksproject android build

The first run downloads the required toolchain:

  • Android command-line tools + SDK (API 36, build-tools)
  • NDK 28c (or your configured version)
  • Temurin JDK 21 (via sdkman)
  • Gradle 9.5.0 wrapper
  • CPython-for-Android prebuilt wheels

The output APK lands at: project_dist/gradle/app/build/outputs/apk/debug/app-debug.apk

Release Builds & Formats

# Build a Release APK
uv run ksproject android build release

# Build an Android App Bundle (.aab) for Google Play
uv run ksproject android build release --bundle

# Build an AAR (library) instead of an app
uv run ksproject android build release --aar

6. Run on an Emulator

List attached devices and available AVDs:

uv run ksproject android devices

Example output:

avd     name=Pixel9
device  serial=emulator-5554     state=device       model=sdk_gphone64_arm64

Boot an AVD by name (boots it, builds the app, installs it, and launches):

uv run ksproject android run --name Pixel9

7. Run on a Real Device

Plug a phone in over USB with USB debugging enabled (Settings → Developer options → USB debugging). Authorise the host when the dialog pops up.

Find its adb serial:

uv run ksproject android devices
# device  serial=R3CN30XXXXX  state=device  model=SM-G998B

Run by serial:

uv run ksproject android run --uuid R3CN30XXXXX

(Append --variant release to run the production build instead of debug).


8. App Signing & Keystore Generation

ksproject includes built-in tools for generating secure keystores and signing your production artifacts (.apk and .aab) using standard Android SDK/JDK tools.

💡 Pro-Tip: Streamline with a .env File

To keep your passwords out of your terminal history and to make commands significantly shorter, save your credentials in a .env file at the root of your project. ksproject will automatically detect them. Create a .env file and add your variables like this:

# .env

# App Signing Credentials
KEYSTORE="my-release-key.jks"
KEYALIAS="myapp"
STOREPASS="SecretPass123"
#KEYPASS="defaults_to_storepass"

1. Generate a Release Keystore

This is required only when your key is outdated or you need to generate a new key for the first time.

Using explicit flags:

uv run ksproject android genkey --out my-release-key.jks --storepass SecretPass123 --keyalias myapp

Using your .env file:

uv run ksproject android genkey --dname "CN=My App, O=My Org"

2. Sign a Built Artifact

The orchestrator automatically detects your built release binary and signs it. Using explicit flags:

# Sign the APK
uv run ksproject android sign --keystore my-release-key.jks --storepass SecretPass123 --keyalias myapp

# Sign an App Bundle (.aab)
uv run ksproject android sign --bundle --keystore my-release-key.jks --storepass SecretPass123 --keyalias myapp

Using your .env file:

# Sign the APK
uv run ksproject android sign

# Sign an App Bundle (.aab)
uv run ksproject android sign --bundle

9. Advanced Customization (Templates)

When you run init, ksproject creates two highly important template files in your root directory. The build engine uses these to generate the final project_dist/ payload.

  • AndroidManifest.tmpl.xml: Add custom broadcast receivers, specific hardware features, or specific intent filters here. ksproject will automatically inject your Python services, meta-data, and permissions at build time.
  • build.tmpl.gradle.kts: Modify your core Gradle setup. Need custom Maven repositories or externalNativeBuild flags? Put them here.
  • Note on Push Notifications: The default template automatically maps the system environment variable ONESIGNAL_APP_ID to an Android String Resource (onesignal_app_id), making it instantly available for libraries like pyonesignal.

10. Configuration (pyproject.toml)

Your pyproject.toml is the single source of truth for your app's metadata.

[tool.uv]
index-strategy = "unsafe-best-match"
find-links = ["./wheelhouse"]

[tool.uv.pip]
extra-index-url = [
    "https://pypi-index.psychowaspx.workers.dev/simple",
    "https://pypi.anaconda.org/kivyschool/simple",
]
find-links = ["./wheelhouse"]

#### kivy-school configuration ####

[tool.kivy-school]
app_name = "Hello World"

[tool.kivy-school.android]
package_name = "org.example.hello_world"

# version_name = "0.1" # change when you want to release a very new version
version_code = 1 # keep increasing to make an update to existing version_name (bug fixes/security releases)

# icon = "relative to pyproject (png)"
# presplash_color = "#FFFFFF"
# presplash = "relative to pyproject (png,jpg,gif)"
# presplash_lottie = "relative to pyproject (json)"

archs = [
    "arm64-v8a", 
    # "x86_64" # Uncomment to support emulators (increases APK size)
]

# API and Toolchain Versions
api = 36
min_api = 24
sdk = "36"
ndk = "28c"
ndk_api = 24

# --- Toolchain Management ---
global_tools = true  # Set to false to use project-local SDK/NDK (./.kivyschool)
# global_tools_path = "~/.kivyschool" # Override root path when global_tools = true

# --- Gradle & Manifest Configs ---
gradle_dependencies = [
    # "com.onesignal:OneSignal:[5.6.1, 5.9.99]"
]
gradle_plugins = [
    # 'id("com.google.gms.google-services") version "4.4.2" apply false'
]
permissions = [
    # "POST_NOTIFICATIONS", "INTERNET", "ACCESS_NETWORK_STATE"
]

# --- File Inclusions ---
# Format: [Destination, Source(s)]
# include_files = [
#     ["gradle/app", ["./google-services.json", "./some-other-config.xml"]]
# ]

# pre_build = "path/to/android_prebuild.py"
# post_build = "path/to/android_prebuild.py"

byte_compile_python = true

# <meta-data> entries inside <application>
# [tool.kivy-school.android.meta_data]
# "com.google.android.gms.ads.APPLICATION_ID" = "ca-app-pub-xxxxxxxx~xxxxxxxx"

# --- Background Services ---
# [[tool.kivy-school.android.services]]
# name = "MyService1"
# start_type = "START_NOT_STICKY"
# entrypoint = "hello_world.services.myservice1"
# foreground = true
# foreground_service_type = "location|dataSync"
# notification_title = "MyService1 Running"
# notification_text = "Service is managing background data."
# notification_icon = "stat_notify_sync"

#### iOS Configuration (Coming Soon) ####
[tool.kivy-school.ios]
bundle_id = "org.example.hello_world"
info_plist = {}
entitlements = {}
permissions = []
frameworks = []
# developer_team = "ABC123XYZ" 

Command Reference

Command What it does
ksproject init Scaffold a new project, template files, and pyproject.toml configurations
ksproject android build [debug|release] Build an APK artifact
ksproject android build --aar [debug|release] Build an AAR library instead of an APK
ksproject android build --bundle [debug|release] Build an AAB (Android App Bundle) instead of an APK
ksproject android build [debug|release] --clean Perform a clean step before executing the build task
ksproject android sign --keystore <file> --storepass <pass> --keyalias <alias> Sign the built APK inside the target directory using apksigner
ksproject android sign --bundle --keystore <file> --storepass <pass> --keyalias <alias> Sign the built App Bundle (.aab) inside the target directory using jarsigner
ksproject android genkey --out <file> --storepass <pass> --keyalias <alias> Generate a secure Java Keystore (.jks) using keytool
ksproject android get-path [sdk|ndk|emulator] Print the fully resolved local file system path for the specified tool
ksproject android devices List connected active adb serial devices and available AVD profiles
ksproject android run --name <AVD> Build, install, and launch the target application on a simulated emulator
ksproject android run --uuid <serial> Build, install, and launch the target application on a physical USB device

Metadata

Release files for ksproject 0.0.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for ksproject 0.0.3
File Size Uploaded Provenance Actions
ksproject-0.0.3.tar.gz 110.6 kB With provenance Details for ksproject-0.0.3.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for ksproject 0.0.3
File Interpreter ABI Platform Actions
ksproject-0.0.3-py3-none-any.whl Python 3 none any Details for ksproject-0.0.3-py3-none-any.whl

Total release size: 232.4 kB

Release files / ksproject-0.0.3.tar.gz

Download URL ksproject-0.0.3.tar.gz
Size 110.6 kB
Tags Source
SHA-256 checksum
How to use checksums
11e9a4f5fb33adae915d028d59e485f98df7412e20844b575520e081aba9c71a
BLAKE2b-256 checksum
How to use checksums
2d0a263b515cc9135cbc47698a5e9db1b4923c7e6e49611b7cc709cf4f022765
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 1, 2026.

Transparency log

Release files / ksproject-0.0.3-py3-none-any.whl

Download URL ksproject-0.0.3-py3-none-any.whl
Size 121.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
39216aa66f70d30591b69e05a67ed2e2242c93321d9eb1dd91a5fcaceb57ad7f
BLAKE2b-256 checksum
How to use checksums
9dc721e7eb05571e2fcd0064fd367557ef5b47cfb84ab56b052ff36efb603dd5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 1, 2026.

Transparency log

Security for ksproject 0.0.3

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for ksproject-0.0.3.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 1, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page