Python and Kivy for an Android app

For my make-up hack week I had a small number of short projects I wanted to try out and get some creative juices flowing. One project was to FINALLY write an Android app (using Python and Kivy) and get to the point where I felt I had a development pipeline for apps I might want to create.

Short version – I got some 3 year old Kivy code into an .apk and got it installed on my old Galaxy S4, and it works!

Skip to the end if you want some tips on what kivy/buildozer configuration worked for me.

Context and links

The history of this project is that years ago I fell in love with QPython on Android. It was wonderful to have a Python environment right on my phone and to be able to program wherever I was.  I wrote a few projects there and had them working reasonably well.  QPython came with Kivy integration which made creating a simple user interface easy (well, easy-ish once you figured out the odd .kv file).  Out of the hacking around I did, two projects came out – an attendance counter for church and a simple story telling app.

Then, QPython broke my heart.  They did an update and completely broke the Kivy integration from what I could tell.  My old projects no longer ran, and even the provided sample code didn’t work!  I tried several times over the last few years to check back and see if a new version fixed something, or if I could hack around the problems, but nothing works.  So I’ve been disappointed.

A few months ago I thought I’d try a different approach and loaded up the official Android Studio.  What a beast that is. I am not familiar with Gradle, but it is really finicky and eats up a lot of resources.  Our old family computer (Win 10) couldn’t handle it, and the family laptop strugged with it.  However, I was again frustrated that the provided examples didn’t just work cleanly out of the box.  Come on!!  If you have a CI system that is testing your software releases, you should be including the example code you provide to make sure it is up to date and works out of the box!

So, for this hack week I am coming to another approach – packaging Kivy code to run on Android ‘directly’.  By ‘directly’ I mean Kivy actually acts as an environment for the app and pulls in other libraries like python-for-android.  You can alternatively just install a Kivy execution environment app on your phone and run your scripts in that, but I wanted to have a full .apk which I hope to try out on a Kindle FireStick as well.

First attempt – buildozer on openSUSE

My work laptop is an openSUSE Leap 42.3 laptop (getting to 42.3 from 42.2 was a separate adventure).  One of my first successful steps was realizing that there is a Kivy package available in YaST.  It installed easily and I was able to run my old code right on my laptop!  https://software.opensuse.org/package/python-Kivy

Encouraged by this, I followed directions from https://kivy.org/docs/guide/packaging-android.html and the first step is to install buildozer, a wrapper project to simplify the build and deploy pipeline.

git clone https://github.com/kivy/buildozer.git

I got a little nervous about installing the setup.py directly on my laptop, but being lazy I went ahead and followed directions and got it installed.

But then I hit my first bump.  There are a number of dependencies needed to build, including Cython.  Reference https://buildozer.readthedocs.io/en/latest/installation.html#targeting-android which lists cython==0.21.  I went for a newer version and let pip figure it out (sudo pip2 install –upgrade cython) which gave me 0.28.

And then pip complained about a missing Python.h.  Ah, but I’d seen that before!  From installing DevStack, I knew that the Python.h comes with the python development package.  So I went to YaST and installed python-devel.  And realized I should have checked YaST for Cython first.  😛

Next bump was javac.  Apparently the openSUSE openjdk-8 packages have a separate openjdk-8-devel package which includes javac, and unfortunately the YaST search doesn’t tell you that (but Google did).

With more dependencies installed I ran ‘buildozer init’ and got a buildozer.spec file.  I edited the spec and filled in some basic info.  But when I tried

buildozer android debug deploy run

It failed with an ugly error.  Apparently it did not pull in pythonforandroid module to a place where python could find it.

Second Attempt: VM

At that point I was tired of fighting the dependency fight (do that enough in my regular day job), so I tried the other documented approach of running a prepared Virtual Machine to do the build.

https://kivy.org/docs/guide/packaging-android-vm.html

Sounded pretty easy.  I pulled the VM image in to my laptop’s Virtualbox instance, unzipped the file, and imported the .ovf file.

This is an XUbuntu vm, and one of the pages told me the creds were kivy/kivy.  The docs said to do an update on the VM to be sure it was the latest, but ‘apt-get update’ failed for me.

In the Start menu of the VM is a handy link to a Kivy Buildozer document.  It has some tips and pointers to get you started.  I updated buldozer as recommended and was given version 0.34. This later turned out to be a problem.

I jumped through a few hoops to get it set up, but having a shared folder was handy.  In the VirtualBox Devices menu, go through the Shared Folders dialog as described, and be sure to check the boxes for both Auto-Mount and Make Permanent.  I copied my code to my local destination and was able to build from the shared folder on the VM.

Attempting to do a build of the code failed on my first attempts.  I kept getting an error like

IOError: [Errno2] No such file or directory /build/rollandtell/android/platform/build/dists/rollandtell/build/outputs/apk/rollandtell-debug.apk

It took a good bit of digging to figure this out.  There is a reported bug (https://github.com/kivy/buildozer/issues/312) in buildozer versions 0.33 and 0.34 where it gets confused between gradle and ant builds (apparently it supports both) and on the VM it picks the wrong one.  I don’t know why the code wasn’t just written to pick it up from either place rather than failing.  But after downgrading to 0.32 I managed to get things working.

pip install buildozer==0.32

My next challenge was getting the built .apk on to my old phone.  I had it plugged in but had to dance the authorization dance a few times.  What eventually worked:

  • shut down the VM and enable USB devices then boot again,
  • in VirtualBox Devices menu select the phone device,
  • plug the phone into a different USB port until it popped up the authorization dialog,
  • run ‘buildozer –verbose android adb — devices’ (mentioned in https://github.com/kivy/buildozer) and get the command line for using the adb on the VM,
  • run the adb command line directly to see the proper output which will tell you if the device is unathorized
  • repeat until you get the proper authorization on the phone

It turned out to be very useful to get the adb command line that buildozer attempts when things fail.  Also note that my old phone had the Android developer options already set from some previous hacking, including the ‘USB debugging’ option.

After getting an authorized connection, I was able to run

buildozer android debug deploy run logcat

and it worked!  It was pretty cool to see the app functioning and the logs scrolling on the VM.

Conclusions

Using the VM was definitely easier, though it still took some tweaking. The winning trick there was getting buildozer 0.32 installed and debug authorization on the device.  I’m writing this in May of 2018, so hopefully newer versions of buildozer will fix that bug (according to the bug report a fix was attempted in 0.35 but didn’t work for everyone).

I still have some room for improvement in the app. It has the default Kivy icon and no good loading screen. A loading screen is important, as the load time is slow (takes a while to get all those libraries loaded).  My app is missing some nice things like a menu (there is a default Kivy menu that has options for Kivy configuration) or an exit button (back button works to quit).  But I am pleased to have a simpler build path for creating apps, and I get to use Python. 🙂

There are a fair set of examples and documentation at kivy.org, so I’m sure I’ll be leveraging more of those on my next app project.