Skip to content

Configure your Android app

Your Android configuration lives in the [tool.kivy.android] overlay of your pyproject.toml. This page covers the settings you change most often. For every key, see the Android overlay reference.

Before you begin

Start from a template

Run kivyforge init -p android in the folder that holds your pyproject.toml. It adds [tool.kivy] and a [tool.kivy.android] overlay with comments and TODO markers on the values you need to change, so you edit a working file instead of typing the Android overlay by hand. To regenerate an overlay that already exists, add --force. See Seed overlays with init.

Start from a minimal overlay

This overlay is the one the hello-android example uses:

[tool.kivy.android]
schema_version = 1
package = "org.kivyforge.helloandroid"
min_sdk = 24
target_sdk = 35
kivy_generation = 2
abis = ["arm64_v8a", "x86_64"]
extra_index_urls = ["https://elliotgarbus.github.io/kivy-mobile-wheels/simple/"]
exclude = ["kivy-garden", "docutils", "pygments"]

[tool.kivy.android.python]
version = "3.14.6"

[tool.kivy.android.permissions]
uses = ["INTERNET"]

schema_version, package, and [tool.kivy.android.python].version are required. The other keys shown have defaults, listed in the reference.

Key settings

package
The applicationId, in reverse-DNS form (org.example.myapp). It is your app's identity on the device and on Google Play, and you cannot change it for a published app.
version_code
The integer Google Play uses to order uploads. Set version_code = "auto" to derive it from [project].version, so you bump only one version.
min_sdk and target_sdk
The minimum and target Android API levels. min_sdk cannot be lower than 24. Keep target_sdk at Google Play's current requirement; see Supported Android versions.
kivy_generation

2 for Kivy 2.3.1 on SDL2, 3 for Kivy 3.0 on SDL3. It selects the matching SDL bootstrap and must match the Kivy version in your dependencies.

It does not choose the Kivy version

kivy_generation is not an input to dependency resolution. The Kivy that gets locked comes only from [project].dependencies. With kivy_generation = 3 and a plain kivy requirement, kivyforge lock still pins 2.3.1, because pip skips pre-releases. Require Kivy 3.0 yourself, for example "kivy>=3.0.0.dev0,<4", with an index that hosts it. That range moves to the newest snapshot on every re-lock. To stay on one snapshot, pin it exactly. kivyforge lock and kivyforge doctor both warn when the two disagree.

Generation 2 keeps clear of the system bars

Android 15 and later draw an app edge to edge, under the status bar and the navigation bar. Kivy 2.3.1 can't report a safe area, so with kivy_generation = 2 the app's window is kept clear of the bars and the notch, with black behind the bars. This applies on API 30 and higher. With kivy_generation = 3 the app draws edge to edge and pads its own layout by the safe area.

abis
The ABIs (application binary interfaces) to build. Physical phones use arm64_v8a. Most emulators on an x86_64 computer use x86_64. Keep both to cover development and distribution.
extra_index_urls
Where to find the Android builds of Kivy and pyjnius, which are not on PyPI yet.
exclude
Dependencies that Kivy declares but an Android app does not use. Pruning them keeps the lock and the app smaller.
fullscreen
Set fullscreen = true to hide the status bar and the navigation bar while your app runs. A swipe in from the edge shows them for a few seconds. It defaults to false. buildozer's default is the reverse, so set it explicitly when you migrate an app that relied on that default. Fullscreen does not remove the notch, so keep padding your layout by the safe area. With kivy_generation = 2, kivyforge keeps the window clear of the notch for you.

Add an icon and a splash screen

Point [tool.kivy.android.icons] at a 1024x1024 PNG. kivyforge generates the adaptive icon set from it.

[tool.kivy.android.icons]
source = "assets/icon.png"

[tool.kivy.android.splash]
source = "assets/splash.png"
background = "#1e1e2e"

Without an icon source, kivyforge generates a plain default icon. Without a splash source, it generates no splash screen.

Add Android resources

To ship your own Android resources, such as vector drawables, a notification icon, density-specific images, values/ files or xml/ configuration, keep them in a folder laid out like an Android res folder and stage it with include_files:

android_res/
├── drawable/
│   └── ic_notification.xml
├── drawable-night/
│   └── banner.xml
├── drawable-xxhdpi/
│   └── banner.png
├── values/
│   └── colors.xml
└── xml/
    └── network_security_config.xml
[[tool.kivy.android.include_files]]
dest = "app/src/main/res"
sources = ["android_res"]

A directory source copies its contents, subfolders included, so android_res/drawable-night/banner.xml ends up at res/drawable-night/banner.xml. Qualifiers such as -night, -v26, -xxhdpi or -land are ordinary Android folder names; kivyforge copies them as they are and AAPT, Android's resource compiler, interprets them. Combined qualifiers must follow Android's order, for example drawable-night-xxhdpi.

kivyforge lock records a hash for every file, so after adding, editing or removing one, run kivyforge lock -p android again. A file you remove from the folder is also removed from the generated project on the next build.

A service's notification icon is a resource name, looked up as a drawable and then as a mipmap, so drawable/ic_notification.xml above is icon = "ic_notification" in the service's notification table.

Replacing a file kivyforge generates

kivyforge writes some resources itself: values/strings.xml (the app name), values/styles.xml (the app theme), the launcher icon under mipmap-*, and the splash screen when one is configured. A file of yours at the same path replaces kivyforge's, and the build says so with KF-ANDROID-INCLUDE-OVERRIDE.

The generated manifest uses the string app_name and the style Theme.Kivyforge, so a replacement strings.xml or styles.xml must still define them, or the build stops and says which one is missing. Replacing styles.xml also drops what kivyforge put in that theme for fullscreen and the splash screen. To add values without replacing anything, use files with other names, such as colors.xml or themes.xml. To change only the theme's parent, set [tool.kivy.android].base_theme.

SVG files

Android does not accept SVG files in res/. Convert them to vector drawable XML first, for example with Android Studio's Vector Asset tool.

Declare permissions

List the permissions your app needs. For permissions that imply hardware, such as CAMERA, kivyforge also adds a non-required <uses-feature> entry so Google Play does not hide your app from devices without that hardware:

[tool.kivy.android.permissions]
uses = ["INTERNET", "CAMERA"]

Verify

Any change to pyproject.toml makes the lock stale, so re-lock, then build a debug APK (Android Package):

kivyforge lock -p android
kivyforge build -p android --debug --abi x86_64

kivyforge rejects an invalid value with a message that names the key. It ignores keys it does not recognize, so a misspelled key has no effect instead of failing.

What's next