back

Your free e-book!

See when it is not worth using Scrum.
"Why Scrum Doesn't Work" Download

When alone Kivy is not enough

Everybody likes games, and almost everybody likes Python Development 🙂 One interesting tool to join these two things together is Kivy.

Few words about Kivy – Python framework

 It’s a cross-platform Python library that can be very useful in the rapid development of applications (not only games) that make use of innovative user interfaces, such as e.g. multi-touch apps.
Kivy’s execution speed is comparable to the native mobile alternative, Java for Android or Objective C for iOS. Moreover, Kivy has the huge advantage of being able to run on multiple platforms, just as HTML5 does; in which case, Kivy performs better because it doesn’t rely on a heavy browser, and many of its components are implemented in C using the Cython library in such a way that most of the graphics processing runs directly in the GPU [2].

A typical application written in Kivy consists of two files: one in Python (*.py, application logic) and the second in Kivy language (*.kv, design language specifically geared towards easy and scalable GUI design). Below example is a ‘Hello World’ in Kivy. First file:


# File name: hello.py
from kivy.app import App  
from kivy.uix.button import Label

class HelloApp(App):  
    def build(self):
        return Label()

if __name__=="__main__":  
    HelloApp().run()

and the second:


 # File name: hello.kv
#:kivy 1.9.0

Awesome Pong Game tutorial learns basics of Kivy in an attractive way.

Portability in Kivy

Kivy applications are generally portable across all supported platforms – Mac, Windows, Linux, iOS, Android, and Raspberry Pi with no significant problems. Kivy strives to be as cross-platform as possible and delivers a similar user experience on every system it supports. This is a huge feature by itself; as a plus, one has the ability to write code once and run everywhere with little (or not at all) tweaks [1][2].
The downside of being cross-platform, however, is that one can only rely on the core functionalities supported by every system. This feature set includes i.a. rendering graphics on the screen, reproducing a sound if there is a sound card, accepting user input, and not too much else.
Each Kivy app, by the virtue of being written in Python, also has access to the vast Python standard library. It facilitates networking, supports a number of application protocols, and provides many general-purpose algorithms and utility functions.
Still, the input-output (I/O) capabilities of a “pure Kivy” programs are limited to those that are present on most platforms. This amounts to a tiny fraction of what a common computer system, such as a smartphone or a tablet PC, can actually do [1][2].
Features that are directly available in Python or Kivy:
• Hardware-accelerated graphics,
• Touch screen input with optional multi-touch,
• Sound playback,
• Networking [2].

Features that aren’t supported or require an external library:
• Modem, support for voice calls, and SMS,
• Use of built-in cameras (videos and taking pictures),
• Use of a built-in microphone to record sound,
• Cloud storage for application data, associated with a user account,
• Bluetooth,
• Location services and GPS,
• Fingerprinting and other biometric security,
• Motion sensors (accelerometer and gyroscope),
• Screen brightness control,
• Vibration and other forms of feedback,
• Battery charge level [2][3].

For many entries from the above list different Python libraries exist and they can handle many platform specific tasks, for example Pyjnius (accessing Java classes from Python), Audiostream (provides an easy-to-use API for streaming bytes to the speaker), Plyer (accessing features of your hardware) and others.
For example, using Plyer one can get information about battery (status and percentage of charging) and display it in a clear way:


from kivy.app import App  
from kivy.uix.boxlayout import BoxLayout  
from kivy.uix.button import Button  
from kivy.lang import Builder  
from kivy.properties import StringProperty, ObjectProperty  
from plyer import battery

Builder.load_string('''  
:  
    lbl1: lbl1
    lbl2: lbl2
    FloatLayout:
        Button:
            size_hint_y: None
            pos_hint: {'y': .5}
            text: "Battery Status"
            on_press: root.get_status()
        BoxLayout:
            size_hint_y: None
            pos_hint: {'y': .1}
            Label:
                text: "Is Charging?"
            Label:
                id: lbl1
                text:
            Label:
                text: "Percentage"
            Label:
                id: lbl2
                text:
''')


class BatteryInterface(BoxLayout):  
    lbl1 = ObjectProperty()
    lbl2 = ObjectProperty()

    def get_status(self, *args):
        self.lbl1.text = str(battery.status['isCharging'])
        self.lbl2.text = str(battery.status['percentage']) + "%"


class BatteryApp(App):

    def build(self):
        return BatteryInterface()

if __name__ == "__main__":  
    app = BatteryApp()
    app.run()

It’s not like these aforementioned features are completely unavailable to application. The challenge is that these parts of functionality are fragmented across different platforms (or even consecutive versions of the same platform, for example, Android); thus, one ends up writing platform-specific, not portable code anyway [2].

Kivy + Android

A lot of functionalities are available on Android and it is only partially covered by an existing Python or Kivy API. It creates possibility to use platform-specific features in one’s application. Unlike pure Kivy, the underlying Android API certainly provides us with ways of recording sound programmatically [1][2].
And here comes the Pyjnius with help. This library allows for using Java classes directly from Python. It means that one can have full access to the native Android API and the official Android documentation, which is obviously more suited for Java development, not Python. Pyjnius allows also for using the official Python interpreter (CPython), together with a multitude of libraries such as NumPy, which facilitates very fast computations [2].

Using Java’s native API

Let’s assume that our task is to create an application that allows recording a sound. The most suitable Java classes for purposes of sound recording are MediaRecorder and MediaPlayer. Also adding Environment class would be convenient, cause it provides access to many useful environmental variables.
To load the aforementioned classes into Python application one can use code as follows:


from jnius import autoclass

Environment = autoclass('android.os.Environment')  
MediaRecorder = autoclass('android.media.MediaRecorder')  
AudioSource = autoclass('android.media.MediaRecorder$AudioSource')  
OutputFormat = autoclass('android.media.MediaRecorder$OutputFormat')  
AudioEncoder = autoclass('android.media.MediaRecorder$AudioEncoder')

Looks quite nice. The simple practical example below shows how to do one thing (figure out where SD card is mounted) in two ways:


//code in Java
import android.os.Environment;  
String path = Environment.getExternalStorageDirectory().getAbsolutePath();

and


# code in Python
Environment = autoclass('android.os.Environment')  
path = Environment.getExternalStorageDirectory().getAbsolutePath()

Original Java code aimed at recording sound with Android can be found here. To initialize MediaRecorder object one can use the code below:


storage_path = (Environment.getExternalStorageDirectory()  
               .getAbsolutePath() + '/kivy_recording.3gp')
recorder = MediaRecorder()

def init_recorder():  
    # set the audio source for microphone
    recorder.setAudioSource(AudioSource.MIC)
    # 3GPP media file as a output format
    recorder.setOutputFormat(OutputFormat.THREE_GPP)
    # Adaptive Multi-Rate with Narrow Band codec
    recorder.setAudioEncoder(AudioEncoder.AMR_NB)
    recorder.setOutputFile(storage_path)
    recorder.prepare()

And then our recorder object and init_recorder function could be used in application class, for example in this way [2]:


class RecorderApp(App):  
    is_recording = False
    def begin_end_recording(self):
        if (self.is_recording):
            recorder.stop()
            recorder.reset()
        ...
        init_recorder()
        recorder.start()
        ...

One of few available full examples of code (in Kivy) of the recording app could be found here.

Deploying to Android

Kivy has a custom-built deployment tool called Buildozer. Buildozer is a tool that aims to package mobiles application easily. It automates the entire build process, downloads the prerequisites like python-for-android, Android SDK, NDK, etc. Buildozer manage a file named buildozer.spec in your application directory, describing your application requirements and settings such as title, icon, included modules etc. It will use the specification file to create a package for Android, iOS, and more [1]. Buildozer provides the logcat command, which calls adb logcat under the hood (adb stands for Android Debug Bridge). One can run it with buildozer android logcat. This command provides all sorts of diagnostic information in the terminal. Most importantly, you can see any Python or Java tracebacks related to your program. One can also use python-for-android directly, which is described here [1][2].

The ability to immediately launch and test an application without compiling is an incredibly important aspect of Kivy development. The Kivy Launcher app, which one may find very useful to test his own programs, is available in the form of an .apk file from the official Kivy’s website this will be useful for emulated Android devices that don’t have access to Google Play.

The only prerequisite for testing operation is an Android device, physical or virtualized, with the Kivy Launcher application installed and working [2].

Software Engineers - development team

Conclusion

When one writes non-portable code it has strengths and weaknesses. This particular choice is difficult, because the switch to native API at the beginning of the project may be completely impractical to undo at a later stage.
With platform-specific code, one can do virtually anything that the platform is capable of. There are no artificial limits; our Python code has unrestricted access to the same underlying API as the native code. On the downside, depending on a single platform is risky because porting the program to a new system becomes harder with every platform-specific feature one can use.

References

  1. Philips D., “Creating Apps inn Kivy”, O’Reilly, 2014.
  2. Vasilkov M., “Kivy Blueprints”, Packt Publishing, 2015.
  3. Ulloa R., “Kivy – Interactive Applications and Games in Python, Second Edition”, Packt Publishing, 2015.

cto - Chris Gibas

Free 30-minute consultation with our CTO

Chris Gibas - our CTO will be happy to discuss your project! Let's talk!

More blog posts
Interesting ideas for using AI in e-commerce

Idego

Substantive support - Julianna Sykutera

Interesting ideas for using AI in e-commerce

In today’s world, when you run a company, your customers require your service availability all the time – 24/7.  Not all customers are so demanding, but a considerable group surely wants you to offer professional support at any moment. With traditional solutions, providing 24 hours per day customer service is very expensive. Fortunately, you can use AI-based solutions for e-commerce. […]

Should you use Angular for developing a business solution?

Choosing the best tech stack for your company’s application is not easy – especially if you’re not tech-savvy. How can you make an informed choice between so many popular programming languages and their frameworks? We would like to tell you more about Angular and its application in business projects.  Angular has now been on the market for quite some time […]

Should you use Angular for developing a business solution?

Idego

Substantive support - Julianna Sykutera

Main differences between deep learning and machine learning

Idego

Substantive support - Julianna Sykutera

Main differences between deep learning and machine learning

Since the moment artificial intelligence first appeared, many new business and technological solutions have been invented. Creating them, though, would not be possible if not for the development of machine learning – and later deep learning – which enabled machines to learn how to process user requests similarly the human would do.  Machine learning, which was invented in 1980 (referred […]

What are the most popular JavaScript frameworks?

JavaScript and frameworks created in that language can be used for both backend and frontend parts of an application. Better knowledge about available technologies will help you make an informed decision when it comes to choosing a tech stack for your next project. JavaScript has a considerable number of backend and frontend frameworks that can be used for mobile and […]

What are the most popular JavaScript frameworks?

Idego

Substantive support - Julianna Sykutera

Get a free estimation

Need a successful project?