Introduction
Kivy can build applications for desktop and mobile including Android and iOS. The same code base can be used for both desktop and mobile, depending on what hardware devices you are trying to access.
This guide will walk through the basics of installing Kivy, building simple applications, building and packaging them for desktop and Android.
For an example of a complete project, check out my Bitcoin Price Checker example with the Live Stream on YouTube.
Alternatives for desktop application programming with Python are PyQt5, Tkinter, and wxPython. Those packages have a more traditional desktop UI but lack the Android and iOS build capabilities the same way Kivy has. Qt technically supports Android but it is not easy to build with PyQt5.
Important concepts
There are a few concepts to understand in mind when building a Kivy application:
- Layouts - Screen layouts are defined in a
.kv
template file using a special Kivy language - Widgets - The UI elements that get packed in to layout elements. Buttons, for example.
- A layout is just another type of widget
To create a Kivy application in Python, there are a few easy steps:
- Create a class that inherits the Kivy main app class
kivy.app.App
- Define a
build()
method in the class that returns a root widget; anything from a single Button (kivy.uix.button.Button
) to a complex GridLayout (kivy.uix.gridlayout.GridLayout
)). - Create an instance of your class and call the
.run()
method.
That is all there is to a Kivy app at a high level.
Installation
You will need to install the Python package kivy
at a minimum.
There is also an optional package called plyer
that contains a number
of cross-platform APIs for accessing device features like notifications
and GPS. Another package used for building Android and iOS is named buildozer
.
You have a few options for installing Kivy:
- From source: https://github.com/kivy/kivy
- Download it from the Kivy website
- Use
pip
to install the packages
To use pip
to install Kivy:
# The core package
python -m pip install kivy
# For additional cross-platform APIs like notifications, GPS, and vibrator
python -m pip install plyer
# For Android/iOS building (Linux only)
python -m pip install buildozer
# You probablyalso need cython for the Android builds
python -m pip install cython
# Or use your system package like this for Fedora:
sudo dnf install python3-Cython
On Fedora, I needed to install ncurses-compat-libs
to resolve the error:
$HOME/.buildozer/android/platform/android-ndk-r17c/toolchains/llvm/prebuilt/linux-x86_64/bin/clang: error while loading shared libraries: libtinfo.so.5: cannot open shared object file: No such file or directory
.
# For Fedora might be needed
dnf install ncurses-compat-libs
In Ubuntu, others report similar: https://github.com/kivy/buildozer/issues/841
# Ubuntu fixes
sudo apt-get install libncurses5-dev libncursesw5-dev
sudo apt-get install libtinfo5
In Windows, you may need to install other dependencies. Official instrucations: Installation in Windows
# Other pip packages to install
python -m pip install pypiwin32
python -m pip install kivy_deps.glew
# One of the backends:
python -m pip install kivy_deps.sdl2
python -m pip install kivy.deps.angle
# If needed for video
python -m pip install kivy.deps.gstreamer
Check installed version
Once Kivy is installed, you can verify it is installed properly and check what version you have installed.
To check what version of Kivy you have, you run pip list
to check
the Kivy package version, or just open your Python interpreter and
import kivy
and inspect kivy.__version__
.
>>> import kivy
[INFO ] [Kivy ] v1.11.1
[INFO ] [Kivy ] Installed at "/usr/local/lib64/python3.7/site-packages/kivy/__init__.py"
[INFO ] [Python ] v3.7.4 (default, Jul 9 2019, 16:32:37)
[GCC 9.1.1 20190503 (Red Hat 9.1.1-1)]
[INFO ] [Python ] Interpreter at "/usr/bin/python3"
>>> kivy.__version__
'1.11.1'
Start a new project
A Kivy application can be as simple as a single .py
file.
This is an example of a minimal application that loads a window with one widget, a button:
# main.py
# Modified from https://kivy.org/doc/stable/guide/basic.html
import kivy
kivy.require('1.11.1') # Set to your Kivy version
from kivy.app import App
from kivy.uix.button import Button
class MyApp(App):
def build(self):
return Button(text='This is a button.')
MyApp().run()
Run the application by executing the Python file:
python main.py
Use the Kv language
In the first example we just returned a single root widget, the button.
You can use methods like .add_widget()
to pack in nested widgets,
but it can be tedious to do all the layout building programmatically.
This is why Kivy created the Kv language for defining widget trees. It is similar to YAML but defines the heirarchy of widgets. It is easier to work with visually and creates separation between the view layer and the controller code.
While the Kv language is optional, and you don't have to use it, it is the preferred way to build layouts and worth getting familiar with. Read more about the KV language in the official Kv language guide
You can provide KV templates as separate .kv
files or as hard-coded
strings inside your Python code.
When building a user interface, you first need to understand the layouts. The layouts will allow you to organize the screen. For example, do you want to stack up a list of buttons vertically, or do you want to have a main frame with a top and bottom bar, or do you want a 3x3 grid of buttons?
Read more about layouts. These are some of the common layout types:
- kivy.uix.boxlayout.BoxLayout
- kivy.uix.gridlayout.GridLayout
- kivy.uix.stacklayout.StackLayout
- kivy.uix.pagelayout.PageLayout
Once you have a layout (which you can nest inside other layouts), you can start putting widgets in it. Widgets are things like buttons, text fields, and checkboxes. Read more about widgets in the official Widget Guide.
Here is an example .kv
file that uses a box layout to hold
two buttons. This creates two buttons side-by-side with no text.
While it is valid and demonstrates the simplest case, it's
not very useful.
# example.kv
BoxLayout:
Button:
Button:
Once you have a .kv
file ready, you need to load it in your application.
By default, it tries to map your app class to a .kv
based off of the name.
For example, if your app is named PracticeApp
it will look for a file named
practice.kv
. I prefer to be more explicit and use kivy.lang.builder.Builder.load_file()
to load a specific file. Alternatively, if you don't want to use a file at all, you can use
kivy.lang.builder.Builder.load_string()
to load a string with the Kv contents.
Here is an example of how to load the simple example.kv
file we created a few lines above.
# main.py
import kivy
kivy.require('1.11.1') # Set to your Kivy version
from kivy.app import App
from kivy.lang.builder import Builder
class MyApp(App):
def build(self):
return Builder.load_file('example.kv')
MyApp().run()
A button generally needs some text and and a callback function to be useful though.
We can modify the .kv
file to look more like this:
# example.kv
BoxLayout:
Button:
id: btn1
text: "Button 1"
on_press: print("%s was pressed" % btn1.text)
Button:
text: "Button 2"
on_press: print(8 * 8)
You can reference other methods from the on_press
and other events.
For example in the Button object, referencing self
would reference
the Button object, and referencing root
would reference the root
widget in the heirarchy (BoxLayout in this case).
A more powerful way to do this would be to create a custom class that inherits the BoxLayout so we can extend its behavior.
We can swap out the BoxLayout
in the .kv
file and replace it with our
CustomBoxLayout
widget.
# example.kv
MyCustomBoxLayout:
Button:
text: "Press me"
on_press: root.custom_callback()
Button:
We haven't actually created the CustomBoxLayout
class though.
We need to add one in our .py
file like this:
# main.py
import kivy
kivy.require('1.11.1') # Set to your Kivy version
from kivy.app import App
from kivy.lang.builder import Builder
from kivy.uix.boxlayout import BoxLayout
class MyCustomBoxLayout(BoxLayout):
def custom_callback(self):
print('Custom callback called.')
class MyApp(App):
def build(self):
return Builder.load_file('example.kv')
MyApp().run()
Running the above example would load the .kv
file and hook up the callback specified
in the .kv
file with the method defined in the .py
file.
Use Plyer to access mobile device hardware
Plyer is a Kivy package that provides an API to hardware devices like accelerometer, screen brightness, camera, compass, and GPS. It also provides access to some utilities like notifications, which work across desktop and mobile. It's a very ambitious library that has some cool features. Refer to the Plyer documentation for the latest information.
You can also find code examples at: https://github.com/kivy/plyer/tree/master/examples
As of September 2019, I found several of the examples did not work on my Android device. The compatibility still seems to be a bit questionable. Be sure to test out of a module works on device.
python -m pip install plyer
Then you can try building some of the Plyer examples.
See the section further down about how to use buildozer
to build an .apk
file for Android.
Build and package
Now that we have looked at installing Kivy and building a simple application, let's look at how to run and package a Kivy application for distribution. We'll look at desktop applications and then Android. I don't cover iOS because I don't have any experience with it, but Kivy does support it.
Build for desktop
You can share your app in a few ways, starting from simplest to most complex packaging:
- As source code - let people download your source, install Python and Kivy, and run your script themselves.
- As a Python package - Package it with distutils and a
setup.py
that users can install withpython setup.py install
- Push the Python package to pypi.org so others can install it with
pip install
- Use PyInstaller to package a .exe or Mac/Linux equivalent. This can create a directory with the .exe and supporting files or a standalone .exe (slower to startup). Distribute this as a .zip for others to download and run. Check out my PyInstaller Tutorial to learn more about how to use it.
- Create an system-specific installer package (e.g. MSI installer with InnoSetup for Window, or a
.deb
package for Ubuntu/Debian) that install the package created with PyInstaller. Check out my Debian Package Tutorial to learn how to make a .deb.
For more details on packaging, refer to the official documentation for Windows packaging and OSX packaging.
PyInstaller notes
If using PyInstaller to package the application, there is a special step needed in order to ensure the SDL and glew DLLs are included in the final package. These notes are taken from the official instructions at: https://kivy.org/doc/stable/guide/packaging-windows.html#pyinstaller-default-hook.
To use PyInstaller to get a properly built package with the right DLLs,
modify the PyInstaller .spec
file to have at the top:
from kivy_deps import sdl2, glew
And in the coll
object, after the last positional argument, add:
*[Tree(p) for p in (sdl2.dep_bins + glew.dep_bins)],
This will allow it to find and include the right dependencies since they are included in the code.
This helps with errors like unable to get window
.
If you want to create an installer, you need to build an installer for each platform. For example, you can use Inno Setup to build Windows installer wizards.
Build for Android
Let's look at the basic steps for building an Android .apk
with a Python Kivy application.
For more in-depth details on building for Android, check out the official documentation pages:
Test adb
The adb
tool is crucial to Android tooling. Buildozer has a way
to use adb
. The one special thing to remember when calling adb
through the buildozer command is that you need to add two dashes (--
)
before passing the actual command for adb.
To verify everything is working, check the adb version.
Running the version
command will also output the full path
to the adb
executable that it is using if you want to run it directly yourself.
python -m buildozer -v android adb -- version
# adb path will be something like:
# $HOME/.buildozer/android/platform/android-sdk/platform-tools/adb
You can also use adb to list devices like this:
python -m buildozer -v android adb -- devices
Configure the buildozer.spec file
The buildozer.spec
file has all the configuration for
the Android and iOS build parameters.
Generate a template buildozer spec file using init
command:
# Generates a `buildozer.spec` file
python -m buildozer init
With the generated buildozer.spec
file, edit it to specify things like:
- Project name
- Version
- Source directory
- Files to include and exclude
- Required Python packages
- Icon image -
icon.filename
a 512x512 PNG - Splash loading image -
presplash.filename
a 512x512 PNG - Change allowed orientations -
orientation = all
- Log level (
log_level = 2
) - Android Permissions
- Android API level
Build the APK file
Once you have your Python Kivy application
and a buildozer.spec
file for your project.
You can build a debug APK that does not require signing
or a release app that is signed and ready for the Google Play Store.
Build the debug APK
To build the debug APK which doesn't require any app signing,
runthe android debug
command for buildozer
.
python3 -m buildozer -v android debug
This will generate an APK file in the bin/
directory with a name like:
myapp-0.1-debug.apk
.
Build the release APK
To build the release APK there is more involved than the debug one. You need to first have a keystore with a key ready to sign the app.
See my Java Keytool Tutorial to learn how to generate and manage keystores. Once you have a keystore, come back and the rest will make sense here.
Also refer to the Kivy Wiki: Creating a Release APK.
The main thing Buildozer needs to have is your keystore information. You can set these values as environment variables. You need to provide the keystore path, keystore password, key alias, and key password.
export P4A_RELEASE_KEYSTORE=$HOME/.keystore
export P4A_RELEASE_KEYSTORE_PASSWD=s3cr3t
export P4A_RELEASE_KEYALIAS_PASSWD=s3cr3t
export P4A_RELEASE_KEYALIAS=mykey
Once your keystore environment variables are set, you can run the release build command:
# Requires the buildozer.spec file
python3 -m buildozer -v android release
Release app on the Google Play Store
Once you have a signed release APK from the previous step, you can publish it to the Google Play Store. I have a dedicated tutorial about this topic. Check out How to Publish Android Apps to Google Play Store.
Install the app
Install the application to a device (physical or virtual)
by running android debug deploy
. This will install it
to all connected devices.
python -m buildozer -v android debug deploy
You can also use buildozer
to serve the current directory with
an HTTP server. This is useful so any Android device on the network
can open the HTTP URL in a web browser and download the .apk
and install
it on the device without the need to be connected via USB.
# Serve the current HTTP directory on port 8000
python -m buildozer serve
# Essentially the same as Python 3's http.server
python -m http.server
You'd then visit http://<your-hostname-or-ip>/
and navigate to the .apk
file.
Run the app
You can build, install, and run the app all in one step with:
python -m buildozer -v android debug deploy run
- The built .apk file is about 13MB.
- The RAM consumption of simple example in debug is about 60MB.
The stats did not change much between release and debug mode.
View debug log
Use logcat to view the device logs
python -m buildozer -v android logcat
If you run with multiple devices attached it won't tail the logs. If you have one device then you will get the stream of log messages. You can build, install, run, and dump logs in a single step. You will get a ton of log messages so it's best to output it to a file like this:
python -m buildozer -v android debug deploy run logcat 2>log.txt
Other common tasks
Now that we have looked at installing Kivy, creating simple applications, and how to package them for distribution, we have all the knowledge needed to create an app.
At this point you should understand how to
get everything installed, create an application from scratch,
creating custom widgets and callbacks with the Kv language,
and how to build the app in to a .exe
for desktop and a .apk
for Android.
All that information should be enough to continue exploring Kivy and building your own applications.
Kivy also includes packages for many things, including:
- animation
- async
- audio
- canvas drawing
- shaders
- 3D rendering
Refer to the official Kivy documentation for the latest and most accurate information. For code references, check out the collection of official Kivy examples.
To learn more, follow the official Pong game tutorial.
It shows you how to build a Pong game using Rectangle
and Ellipse
widgets
on a canvas
widget, and use the built-it collide_widget()
method
available on widgets to detect collisions like the ball hitting the paddle.
Also check out the Paint app tutorial which shows you how to detect touches and respond by
drawing an Ellipse
(circle) at the touch location.
Conclusion
After reading this, you should have a good understanding of what Kivy is
and how you can use it. You should understand how to create desktop apps
and mobile apps by building layouts using the .kv
language. Additionally,
you should know how to use the plyer
package to access cross-platform
features and hardware devices.
References
- Official Kivy documentation
- Kivy Source
- Kv language guide
- Kivy examples
- Paint app tutorial
- Pong game tutorial
- Widget Guide
- Plyer documentation
- Plyer examples
- PyInstaller Tutorial
- InnoSetup
- Windows packaging
- OSX packaging
- Android packaging
- Android Kivy guide
- Buildozer source
- Inno Setup Installer
- PyQt5 Tutorial
- Python Tkinter Tutorial
- wxPython
- Bitcoin Price Checker
- Live Stream making Bitcoin Price Checker
- Java Keytool Tutorial
- Kivy Wiki: Creating a Release APK
- How to Publish Android Apps to Google Play Store