Осторожно — Бульдозер (сборка apk пакетов в Kivy)


    Фух! Только что выбрался из под траков этого чудовища. А кое-кому повезло меньше. Как и было обещано в предыдущей статье, сегодня мы расскажем, как собираются apk пакеты для программ, написанных с использованием фреймворка Kivy при помощи утилиты Buildozer.


    Что для этого понадобится? Помимо уже известных инструментов — кофе-сигареты, полкило нервов — нам потребуются ключи от новенького Бульдозера, который стоит в ангаре на github и сопутствующие зависимости, без которых он, к сожалению, не заведется, а если заведется, то никого задавить не удастся и apk пакет для Android не собрать.


    Кстати, пользователи Microsoft, на своих Windows машинах за Бульдозером с нами не едут, потому что для сборки apk пакета требуется Linux система, либо ее образ на виртуалке. Ну, что ж. А мы отправляемся на github, отбуксируем Бульдозер и распакуем архив в какую-нибудь директорию. Блин. Да это просто монстр!


    Спокойно. Не заводим. За рычаги не хватаемся. Во-первых, нам нужно скачать пакет pip — инструмент для установки и управления пакетами Python.


    sudo apt-get install python-pip

    Заходим в ангар, в смысле в папку с Бульдозером...



    … и выполняем команду -


    sudo python setup.py install

    Об успешной установке мы будем извещены сообщением Successfully installed buildozer. Бульдозер работает как на Python 2.7 так и на Python >= 3.3. Я использую Python 2.7. Просто потому, что я пока не пытался собирать apk пакеты для программ, написанных с использованием Python 3, хотя по заявлениям разработчиков Kivy, третий Python полностью поддерживается. Ну, и теперь, собственно, давайте скачаем python-for-android. У меня работает именно эта ветка, поэтому других я не предлагаю. Распакуйте python-for-android.zip и пока забудем о нем.


    Зависимости


    Их довольно много и от правильной их установки будет зависеть, сможете ли вы собрать заветную apk-шечку или придется выпить валидолу и начать все сначала. Считается, что все вышеперечисленные пакеты у вас отсутствуют и предполагается, что фреймворк Kivy установлен и успешно вами используется.


    sudo pip install --upgrade cython
    sudo pip install virtualenv
    sudo pip install Jinja2

    Для сборки пакета под Android нам понадобится Android SDK. Некоторые его двоичные файлы все еще находятся в 32 битных библиотеках, так что нужно сделать их доступными:


    dpkg --add-architecture i386

    После этого можем установить следующие пакеты:


    sudo apt-get update
    sudo apt-get install -y build-essential ccache git zlib1g-dev python2.7 python2.7-dev libncurses5:i386 libstdc++6:i386 zlib1g:i386 openjdk-7-jdk unzip

    Ну, и теперь, наконец, мы готовы сесть в удобное кресло Бульдозера и схватится за рычаги управления. Заходим в папку проекта и выполняем в терминале команду -


    buildozer init

    … которая создаст в проекте файл спецификации buildozer.spec, где мы будем указывать Бульдозеру с какими параметрами собирать наше приложение.



    Откроем данный файл и посмотрим его содержимое:


    buildozer.spec
    [app]
    
    # (str) Title of your application
    title = DemoCleanMaster
    
    # (str) Package name
    package.name = democleanmaster
    
    # (str) Package domain (needed for android/ios packaging)
    package.domain = org.heattheatr
    
    # (str) Source code where the main.py live
    source.dir = .
    
    # (list) Source files to include (let empty to include all the files)
    source.include_exts = py,png,kv,jpg
    
    # (list) Source files to exclude (let empty to not exclude anything)
    #source.exclude_exts = []
    
    # (list) List of directory to exclude (let empty to not exclude anything)
    #source.exclude_dirs = []
    
    # (list) List of exclusions using pattern matching
    #source.exclude_patterns = license,images/*/*.jpg
    
    # (str) Application versioning (method 1)
    version.regex = __version__ = ['"](.*)['"]
    version.filename = %(source.dir)s/main.py
    
    # (str) Application versioning (method 2)
    # version = 1.2.0
    
    # (list) Application requirements
    # comma seperated e.g. requirements = sqlite3,kivy
    requirements = kivy
    # (str) Custom source folders for requirements
    # Sets custom source for any requirements with recipes
    # requirements.source.kivy = ../../kivy
    
    # (list) Garden requirements
    #garden_requirements =
    
    # (str) Presplash of the application
    presplash.filename = %(source.dir)s/Data/Images/presplash.jpg
    
    # (str) Icon of the application
    icon.filename = %(source.dir)s/Data/Images/logo.png
    
    # (str) Supported orientation (one of landscape, portrait or all)
    orientation = portrait
    
    # (bool) Indicate if the application should be fullscreen or not
    fullscreen = 1
    
    #
    # Android specific
    #
    
    # (list) Permissions
    android.permissions = INTERNET
    
    # (int) Android API to use
    android.api = 18
    
    # (int) Minimum API required (8 = Android 2.2 devices)
    android.minapi = 8
    
    # (int) Android SDK version to use
    android.sdk = 21
    
    # (str) Android NDK version to use
    android.ndk = 9
    
    # (bool) Use --private data storage (True) or --dir public storage (False)
    android.private_storage = False
    
    # (str) Android NDK directory (if empty, it will be automatically downloaded.)
    android.ndk_path = /home/zavulon/Opt/android-ndk-r9
    
    # (str) Android SDK directory (if empty, it will be automatically downloaded.)
    android.sdk_path = /home/zavulon/Opt/android-sdk
    
    # (str) python-for-android git clone directory (if empty, it will be automatically cloned from github)
    android.p4a_dir = /home/zavulon/Opt/Python/python-for-android
    
    # (list) python-for-android whitelist
    #android.p4a_whitelist =
    
    # (str) Android entry point, default is ok for Kivy-based app
    #android.entrypoint = org.renpy.android.PythonActivity
    
    # (list) List of Java .jar files to add to the libs so that pyjnius can access
    # their classes. Don't add jars that you do not need, since extra jars can slow
    # down the build process. Allows wildcards matching, for example:
    # OUYA-ODK/libs/*.jar
    #android.add_jars = foo.jar,bar.jar,path/to/more/*.jar
    
    # (list) List of Java files to add to the android project (can be java or a
    # directory containing the files)
    #android.add_src =
    
    # (str) python-for-android branch to use, if not master, useful to try
    # not yet merged features.
    #android.branch = master
    
    # (str) OUYA Console category. Should be one of GAME or APP
    # If you leave this blank, OUYA support will not be enabled
    #android.ouya.category = GAME
    
    # (str) Filename of OUYA Console icon. It must be a 732x412 png image.
    #android.ouya.icon.filename = %(source.dir)s/data/ouya_icon.png
    
    # (str) XML file to include as an intent filters in <activity> tag
    #android.manifest.intent_filters =
    
    # (list) Android additionnal libraries to copy into libs/armeabi
    #android.add_libs_armeabi = libs/android/*.so
    #android.add_libs_armeabi_v7a = libs/android-v7/*.so
    #android.add_libs_x86 = libs/android-x86/*.so
    #android.add_libs_mips = libs/android-mips/*.so
    
    # (bool) Indicate whether the screen should stay on
    # Don't forget to add the WAKE_LOCK permission if you set this to True
    #android.wakelock = False
    
    # (list) Android application meta-data to set (key=value format)
    #android.meta_data =
    
    # (list) Android library project to add (will be added in the
    # project.properties automatically.)
    #android.library_references =
    
    #
    # iOS specific
    #
    
    # (str) Name of the certificate to use for signing the debug version
    # Get a list of available identities: buildozer ios list_identities
    #ios.codesign.debug = "iPhone Developer: <lastname> <firstname> (<hexstring>)"
    
    # (str) Name of the certificate to use for signing the release version
    #ios.codesign.release = %(ios.codesign.debug)s
    
    [buildozer]
    
    # (int) Log level (0 = error only, 1 = info, 2 = debug (with command output))
    log_level = 2
    
    # (int) Display warning if buildozer is run as root (0 = False, 1 = True)
    warn_on_root = 0
    
    #    -----------------------------------------------------------------------------
    #    List as sections
    #
    #    You can define all the "list" as [section:key].
    #    Each line will be considered as a option to the list.
    #    Let's take [app] / source.exclude_patterns.
    #    Instead of doing:
    #
    #[app]
    #source.exclude_patterns = license,data/audio/*.wav,data/images/original/*
    #
    #    This can be translated into:
    #
    #[app:source.exclude_patterns]
    #license
    #data/audio/*.wav
    #data/images/original/*
    #
    #    -----------------------------------------------------------------------------
    #    Profiles
    #
    #    You can extend section / key with a profile
    #    For example, you want to deploy a demo version of your application without
    #    HD content. You could first change the title to add "(demo)" in the name
    #    and extend the excluded directories to remove the HD content.
    #
    #[app@demo]
    #title = My Application (demo)
    #
    #[app:source.exclude_patterns@demo]
    #images/hd/*
    #
    #    Then, invoke the command line with the "demo" profile:
    #
    #buildozer --profile demo android debug

    Теперь рассмотрим подробнее...


    title = DemoCleanMaster

    Это имя приложение, которое будет отображаться на Android девайсе и которое будет носить установочный apk пакет.


    package.name = democleanmaster
    package.domain = org.heattheatr

    Уникальный домен приложения.



    source.dir = .

    Директория, в которой находится точка входа в приложение — файл main.py. По умолчанию это корневая директория проекта.



    source.include_exts = py,kv,jpg,png

    Расширение файлов, которые будут включены в сборку apk пакета из вашего проекта. Структура дерева директорий, откуда указанные файлы будут браться, сохраняется.


    version.regex = __version__ = ['"](.*)['"]
    version.filename = %(source.dir)s/main.py

    Версия программы и в каком файле ее (версию) искать. Данный метод говорит, что в файле main.py корневой директории проекта должна быть переменная со значением версии вашего приложения.


    # main.py
    
    __version__ = '0.0.1'
    
    # ...ваш код

    requirements = kivy

    Сторонние библиотеки, которые будут включены в сборку. Через запятую вы можете указать пакеты библиотек, с которыми работает ваше приложение, например: kivy, opencv, pil, sqlite3.


    Полный список доступных библиотек вы можете посмотреть в редакторе спецификации в инструменте для построения UI — Kivy Designer. Очень рекомендую!



    presplash.filename = %(source.dir)s/Data/Images/presplash.jpg

    Изображение, которое будет показано на экране девайса пока запускается ваше приложение, где %(source.dir)s — путь к корневой директории проекта.



    icon.filename = %(source.dir)s/Data/Images/logo.png

    Иконка приложения, которая будет отображаться на девайсе.


    orientation = portrait
    fullscreen = 1

    Ориентация вашего приложения на девайсе. Помимо 'portrait', может принимать значение 'landscape'. 'fullscreen' указывает разворачивать Activity на весь экран. Также принимает значение '0'.


    android.permissions = INTERNET

    Права приложения.


    android.api = 18

    Используемая приложением версия Android API (должна быть в Android SDK). Здесь могут возникнуть проблемы, если, например, вы указали версию Android API 10, которая отсутствует в Android NDK.



    android.minapi = 8

    Минимальная версия Android API, поддерживаемая приложением.


    android.sdk = 21

    Версия Android SDK.


    android.ndk = 9

    Версия Android NDK.


    android.private_storage = False

    Указывает создавать папку с файлами проекта на девайсе на SD карте. Рекомендую. Потому что в данном случае вы можете заменить байткомпилированое представление *.pyo файлов проекта на исходные тексты, и если будет необходимость внести в проект небольшое изменение, вы можете сделать это прямо на девайсе, отредактировав исходники или перезалив их с компьютера.


    android.ndk_path = /home/zavulon/Opt/android-ndk-r9
    android.sdk_path = /home/zavulon/Opt/android-sdk
    
    android.p4a_dir = /home/zavulon/Opt/Python/python-for-android

    Здесь все понятно. Можете сделать следующим образом:


    android.ndk_path = 
    android.sdk_path = 
    android.p4a_dir = 

    В таком случае Бульдозер скачает и Android SDK с указанными в спецификации версиями ANDROID API, и Android NDK, и python-for-android, будет скачан Apache-ant, если Бульдозер его не найдет. Также будут скачаны следующие библиотеки и исходники самого Python и модулей:



    Да. Все это несколько хлопотно, но делается это один раз. Потом, для сборки проекта, достаточно просто отредактировать файл спецификации buildozer.spec и закинуть его в проект, который мы хотим собрать. Остальные параметры спецификации я не рассматриваю, поскольку пока я их еще сам не использоавл. И, да, параметры для сборки под iOS тоже остаются за траками, потому что я не имею девайса с данной платформой.


    Собственно, эй, вы там — закройте двери Бульдозера с той стороны и прочь со взлетной полосы — мы заходим в папку проекта и выполняем в терминале команду начала компиляции:


    buildozer android debug

    Пройдет о-о-очень много времени (пригодились сигареты и кофе), прежде чем вы увидите заветное сообщение:



    Обратите внимание, что apk-шечка получается дебажная. На Хабре есть статья, в которой описывается процесс создания подписанного пакета. К тому же размер сборки довольно внушительный — 7.6 Мб. Это потому, что Бульдозер включает в сборку весь Python целиком со всеми тестами и не нужными библиотеками. Также сам Kivy включается со всеми API даже если ваше приложение их не использует.


    После установки собранного apk на девайсе и его старта, приложение будет довольно долго запускаться. Kivy потребуется время, чтобы извлечь и развернуть все библиотеки. К счачтью, все последующие загрузки программы длятся не более пяти секунд.


    В следующей статье я расскажу, за какие рычаги дергать Бульдозер, чтобы увидеть собранный проект, но уже гораздо меньшего размера...



    Удачных сборок! Смотрите под траки!

    Поделиться публикацией

    Похожие публикации

    Комментарии 15

      +2
      И все же, 5 секунд — это очень много для запуска Android-приложения (разве что относительно тяжелая игра). Что вы имеете в виду под запуском — время от нажатия иконки (и появления черного экрана) до появления какого-то сплеш-скрина?
        0

        Сплеш с выбранным вами лого появится мгновенно при нажатии иконки собранного и установленного приложения. А вот стартовый экран программы появится примерно через четыре-пять секунд.

          0
          android.private_storage = False

          Указывает создавать папку с файлами проекта на девайсе на SD карте. Рекомендую

          Может быть в этом дело? Оно при запуске распаковывает в корень карты ресурсы. Первый запуск, кстати, происходит дольше, чем последующие.
            0

            Ну, да, я так и написал: все последующие старты приложения вполне себе вминяемы по времени запуска.

        0
        Спасибо! Очень кстати — даже не буду пытаться мучать его под виндой. Но, ради интереса — чего ему в винде не хватает, на что жалуется?
          0

          Дело в том, что причина здесь не в нехватке каких-то библиотек, а, скорее, в процессе компиляции Python под arm. Откровенно говоря, толком не вникал в этот вопрос.

          +4
          О, наконец-то тот самый интригующий однокартиночный пост оформлен в статью. )
            0
            Жаль, что при переводе потерялась игра слов «bulldozer — buildozer» :)
              0
              Думаю, в русском варианте было бы что-то по типу «билдозер», хотя суть все равно теряется
                0
                Ну да, просто насколько хороша по смыслу эта игра — сразу понятно чем может похвастаться это приложение.
                А ещё если приглядеться, то между bulldozer и buildozer в типографике всего одна маленькая белая точка
              0
              А как сделать чтобы оно не закрывалось а продолжало висеть в памяти?
              И как убрать Kivy меню при нажатии кнопки меню?
                0

                Kivy приложение будет закрыто при попытке свернуть его в трей. Это связано с использованием Kivy OpenGL на платформе Android. Пока этот вопрос разработчики не решили и будут ли решать, не знаю.

                  0
                  Кстати, нашел ответ на свой первый вопрос у вас на гит в исходниках к CreatorKivyProject-master.
                  Достаточно определить класс метод on_pause в объекте унасделованным от App
                  def on_pause(self):
                  return True


                  теперь осталось найти по второй части вопроса: при нажатии на кнопку «квадратик» рядом с кнопкой домой у меня открывается окошко настроек kivy (и настройки в нём кстати не применяются) как мне его переопределить?
                    0

                    Что есть кнопка "квадратик"? В CreatorKivyProject наcтройки Kivy отключены.

                      0
                      честно говоря у меня сам CreatorKivyProject не запустился потому что он не видит KivyMD.

                      на моём телефоне помимо кнопок на экране есть 3 стандартные кнопки: «назад», «домой» и «квадратик» (ну не знаю как называется последняя на ней нарисован квадратик). Обычно она вызывает меню в программах. Но в программах на kivy она вызывает окно настроек kivy :(

                      Спасибо за наводку — буду ковырять исходники глубже…

              Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

              Самое читаемое