Python Kivy Tutorial

Advertisement

Advertisement

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:

  1. Create a class that inherits the Kivy main app class kivy.app.App
  2. 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)).
  3. 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:

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:

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 with python 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

Advertisement

Advertisement