Осторожно — Бульдозер (сборка 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 потребуется время, чтобы извлечь и развернуть все библиотеки. К счачтью, все последующие загрузки программы длятся не более пяти секунд.


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



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

    Similar posts

    Ads
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More

    Comments 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 :(

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

              Only users with full accounts can post comments. Log in, please.