Skip to main content

Compile python apps for Android and iOS.

Project description

ksproject

Kivy School Project Manager — A cross-platform build tool for Kivy 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:

[!NOTE] These are already present by default!!

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"

[!NOTE] You can also append --dname "CN=My App, O=My Org" to either command if you need to provide a specific Distinguished Name string for the certificate.

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

[!NOTE] By default, ksproject android sign targets the release directory. You can optionally pass --variant debug to sign a debug artifact, or pass --keypass <password> if your security profile requires an alias password distinct from your core keystore storage password. Similarly, you can append --variant release to the run pipeline to run production builds.


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

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ksproject-0.0.1.post0.tar.gz (108.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

ksproject-0.0.1.post0-py3-none-any.whl (119.5 kB view details)

Uploaded Python 3

File details

Details for the file ksproject-0.0.1.post0.tar.gz.

File metadata

  • Download URL: ksproject-0.0.1.post0.tar.gz
  • Upload date:
  • Size: 108.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for ksproject-0.0.1.post0.tar.gz
Algorithm Hash digest
SHA256 0cf9589ca949af0933426a491312dfaed94a5677e65fe826b71ff34fbe489693
MD5 5f0d0897e1c68ddc7be83916b046f97a
BLAKE2b-256 faee56eb1089399c6ea2c1a3183cdf000a5aa960049a7e4ed937493be6680571

See more details on using hashes here.

Provenance

The following attestation bundles were made for ksproject-0.0.1.post0.tar.gz:

Publisher: pypi-release.yml on kivy-school/ksproject

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file ksproject-0.0.1.post0-py3-none-any.whl.

File metadata

  • Download URL: ksproject-0.0.1.post0-py3-none-any.whl
  • Upload date:
  • Size: 119.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for ksproject-0.0.1.post0-py3-none-any.whl
Algorithm Hash digest
SHA256 ff1ce49f893d18e18cb83d7674887b11ef8edf0e711506ced43774705b0fc48d
MD5 b8baeb1251201c52b233d0d0a4523a7c
BLAKE2b-256 a57ea75d2a4d387a0c803e7fd5a2c7e44dea096a8362d282cc5a1fce57be5c5d

See more details on using hashes here.

Provenance

The following attestation bundles were made for ksproject-0.0.1.post0-py3-none-any.whl:

Publisher: pypi-release.yml on kivy-school/ksproject

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page