Building your first Kivy mobile app
Posted 2026-04-10 on the pythondeck.com blog
Kivy is the easiest way to ship a Python app to Android and iOS. This is a walkthrough of building a tiny note-taking app, packaging it for Android with Buildozer, and the gotchas nobody tells you about.
Project layout
notes/
main.py
notes.kv
buildozer.spec # generated
main.py
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import ListProperty
class Root(BoxLayout):
notes = ListProperty([])
def add_note(self, text):
if text.strip():
self.notes = self.notes + [text.strip()]
self.ids.entry.text = ""
class NotesApp(App):
def build(self):
return Root()
NotesApp().run()
notes.kv
<Root>:
orientation: 'vertical'
padding: 12
spacing: 8
TextInput:
id: entry
hint_text: 'New note...'
size_hint_y: None
height: 48
Button:
text: 'Add'
size_hint_y: None
height: 48
on_release: root.add_note(entry.text)
ScrollView:
BoxLayout:
id: list
orientation: 'vertical'
size_hint_y: None
height: self.minimum_height
spacing: 4
on_parent: pass
Packaging for Android
Install Buildozer on Linux or WSL: pip install buildozer cython. Run buildozer init, edit buildozer.spec to set title, package.name and requirements = python3,kivy, then buildozer android debug deploy run. The first build downloads the Android SDK/NDK and takes 30+ minutes; subsequent builds are fast.
What trips people up
- Permissions: declare them in
buildozer.specunderandroid.permissions. - File paths: use
App.user_data_dir, not relative paths. - Touch vs mouse: emulate touch in the desktop preview before testing on a phone.
- Screen density: design in
dpunits, not pixels.