Search code examples
pythonkivybuildozer

How do you create a kivy apk from a package?


I have a simple python/kivy package from which I wish to create an android APK using Buildozer. The package from the root is organised as:

.
├── bin
│   ├── kivy_test-0.1-debug.apk
│   └── myapp-0.1-debug.apk
├── buildozer.spec
├── __init__.py
└── kivy_app
    ├── __init__.py
    ├── __main__.py
    └── source
        ├── main.py
        └── version.py

The module main.py is:

from kivy.app import App
from kivy.uix.screenmanager import Screen
from kivy.uix.button import Label
from kivy.lang import Builder

from version import VERSION

root = Builder.load_string('''
<MainFrame>:
    BoxLayout:
        orientation: 'vertical'
        Label:
            text: 'Hola mundo!'
        Label:
            text: root.version
''')

class MainFrame(Screen):
    version = 'Version: %s' % VERSION
    def __init__(self, **kwargs):
        super(MainFrame, self).__init__(**kwargs)

class BasicApp(App):
    def build(self):
        return MainFrame()

if __name__ == '__main__':
    BasicApp().run()

version.py is

__all__ = 'VERSION'

VERSION = '0.0.2'

and _main_.py is

from .source.main import BasicApp

def main():
    BasicApp().run()

if __name__ == "__main__":
    main()

The problem that I have is that when I run the module by typing

python -m kivy_app

in the root directory I need to have the line

from .version import VERSION

in main.py (note there is '.' before version).

On the other hand, when I build the android apk from the root directory the buildozer.spec uses the line:

# (str) Source code where the main.py live
source.dir = ./kivy_app/source

and of course it is invoking the lines:

if __name__ == '__main__':
     BasicApp().run()

in main.py.

In this case the module is treated as if it is not in a package and so needs the line:

from version import VERSION

(In this case no '.' before version in the import statement)

How can I resolve this conflict?


Solution

  • The solution to this conflict it to copy _main_.py to main.py and to replace the line:

    from .source.main import BasicApp
    

    with:

    from source.main import BasicApp
    

    In buildozer.spec replace:

    source.dir = ./kivy_app/source
    

    with:

    source.dir = ./kivy_app
    

    The tree is now:

    .
    ├── bin
    │   ├── kivy_test-0.1-debug.apk
    │   └── myapp-0.1-debug.apk
    ├── buildozer.spec
    ├── __init__.py
    └── kivy_app
        ├── __init__.py
        ├── __main__.py
        ├── main.py
        └── source
            ├── main.py
            └── version.py