Фух! Только что выбрался из под траков этого чудовища. А кое-кому повезло меньше. Как и было обещано в предыдущей статье, сегодня мы расскажем, как собираются 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, где мы будем указывать Бульдозеру с какими параметрами собирать наше приложение.
Откроем данный файл и посмотрим его содержимое:
[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 потребуется время, чтобы извлечь и развернуть все библиотеки. К счачтью, все последующие загрузки программы длятся не более пяти секунд.
В следующей статье я расскажу, за какие рычаги дергать Бульдозер, чтобы увидеть собранный проект, но уже гораздо меньшего размера...
Удачных сборок! Смотрите под траки!
Комментарии (10)
ophermit
25.05.2016 23:38Спасибо! Очень кстати — даже не буду пытаться мучать его под виндой. Но, ради интереса — чего ему в винде не хватает, на что жалуется?
HeaTTheatR
26.05.2016 00:14Дело в том, что причина здесь не в нехватке каких-то библиотек, а, скорее, в процессе компиляции Python под arm. Откровенно говоря, толком не вникал в этот вопрос.
woodhead
26.05.2016 07:28+4О, наконец-то тот самый интригующий однокартиночный пост оформлен в статью. )
knagaev
26.05.2016 09:45Жаль, что при переводе потерялась игра слов «bulldozer — buildozer» :)
thatside
26.05.2016 10:48Думаю, в русском варианте было бы что-то по типу «билдозер», хотя суть все равно теряется
knagaev
26.05.2016 10:52Ну да, просто насколько хороша по смыслу эта игра — сразу понятно чем может похвастаться это приложение.
А ещё если приглядеться, то между bulldozer и buildozer в типографике всего одна маленькая белая точка
1nt3g3r
И все же, 5 секунд — это очень много для запуска Android-приложения (разве что относительно тяжелая игра). Что вы имеете в виду под запуском — время от нажатия иконки (и появления черного экрана) до появления какого-то сплеш-скрина?
HeaTTheatR
Сплеш с выбранным вами лого появится мгновенно при нажатии иконки собранного и установленного приложения. А вот стартовый экран программы появится примерно через четыре-пять секунд.
kAIST
Может быть в этом дело? Оно при запуске распаковывает в корень карты ресурсы. Первый запуск, кстати, происходит дольше, чем последующие.
HeaTTheatR
Ну, да, я так и написал: все последующие старты приложения вполне себе вминяемы по времени запуска.