Kodi for Android: Building and Using Binary Python Extensions - Part 3

 Nov. 18, 2016     0 comments

This is the 3rd article in my series about building and using binary Python modules in Kodi on Android. In the previous article I described how to build a simple "Hello World!" binary module. In this article I will tell you how to use binary Python/C extension modules in Kodi for Android.

As I mentioned in the previous article, the import mechanism for binary Python modules in Kodi for Android is seriously broken. You cannot just use import foo to load such module, like on other platforms. If you try to do this you'll get ImportError exception. Fortunately, guys from the unofficial Russian Kodi forum found a magical trick that allows to load binary Python modules in Kodi for Android. The trick is really magical because, honestly, I don't know how it works, but it does.

The following code example shows how to load and use our libhello.so binary module that we have build in the previous article:

import os
import imp
from ctypes import CDLL
from xbmcgui import Dialog

cwd = os.path.dirname(os.path.abspath(__file__))
dialog = Dialog()
fo = None
try:
    # Magic trick: we need to load our shared library via ctypes first.
    CDLL(os.path.join(cwd, 'libhello.so'))
    # Find our module by filename without extension.
    fo, p, d = imp.find_module('libhello', [cwd])
    # Load our module from a file object
    hello = imp.load_module('hello', fo, p, d)
except Exception as ex:
    dialog.ok('Error!', str(ex))
    raise ex
else:
    dialog.ok('Success!', hello.get_hello())
finally:
    # Close the file object if module has been found successfully.
    if hasattr(fo, 'close'):
        fo.close()

You need to put this code in the main addon script. The example assumes that the libhello.so file is placed in the same folder as our addon script.

Possible problems

Some Android systems do not allow to load shared libraries (and our binary Python module is essentially a shared library) from arbitrary locations, so our import may fail. Locations that are known to work:

  • The addon folder.
  • The Kodi cache folder (can be obtained using xbmc.translatePath('special://temp')).
  • The Kodi installation folder (can be obtained using xbmc.translatePath('special://xbmc')).

Maybe other locations could be used too. The script.module.libtorrent library that is a collection of Python binding for libtorrent library compiled for various platforms probes several directories by copying a module file into a directory and trying to import it from there. If you are going to support wide range of Android devices you will have to do the same.

In this article I have described how to import a binary Python module in Kodi for Android. In the next article I will briefly cover two convenience C++ libraries — Boost.Python and Pybind11 — that simplify writing binary Python modules.

  AndroidCC++KodiPluginPython