Как создать игру на python для андроид
Перейти к содержимому

Как создать игру на python для андроид

  • автор:

Создание мобильных приложений на Python

Создание мобильных приложений на Python

Да, вы можете создавать мобильные приложения с использованием Python. Я этого не знал, но я достаточно давно заметил, что наш сайт ранжируется по запросу создание мобильных приложений на Python и мне стало интересно.

Существует несколько инструментов и фреймворков, которые помогут вам создать мобильные приложения на Python. Некоторые популярные варианты:

  1. Kivy: Kivy – это открытая библиотека Python для разработки многокасательных приложений. Она поддерживает платформы Android и iOS и позволяет создавать одну кодовую базу, которая может работать на обеих платформах. Kivy также имеет богатый набор элементов пользовательского интерфейса и довольно прост в изучении.
  2. BeeWare: BeeWare – это другой набор открытых инструментов и библиотек для создания мобильных приложений на Python. BeeWare включает набор виджетов, которые являются родными для каждой платформы, что обеспечивает внешний вид и ощущение вашего приложения как родного для Android и iOS. С помощью BeeWare вы можете написать свое приложение один раз и развернуть его на нескольких платформах.
  3. Chaquopy: Chaquopy – это плагин для Android Studio, который позволяет вам писать приложения для Android на Python. Он позволяет смешивать код Python и Java в одном проекте, что позволяет использовать существующие библиотеки и API Android при написании логики вашего приложения на Python.

Разберем чуть подробнее на примере Kivy. Она предоставляет инструменты и виджеты для разработки интерактивных приложений, работающих на разных операционных системах, таких как Windows, macOS, Linux, Android и iOS. Вот основные аспекты работы Kivy:

  1. Графический движок: Kivy использует OpenGL ES 2 (или выше) для отрисовки графики, что позволяет создавать аппаратно ускоренные и высокопроизводительные приложения. Он также предоставляет абстракцию от низкоуровневых графических вызовов, что делает работу с графикой проще для разработчиков.
  2. Интерфейс пользователя: Kivy предоставляет богатый набор виджетов и элементов пользовательского интерфейса (UI) для создания приложений. Виджеты в Kivy адаптивны и могут масштабироваться для различных размеров экрана и разрешений.
  3. События и ввод: Kivy поддерживает множество входных устройств и источников событий, таких как клавиатура, мышь, мультитач-экраны и другие. Он имеет встроенную систему событий, которая позволяет разработчикам управлять взаимодействием пользователя с приложением.
  4. Язык Kv: Kivy включает собственный язык разметки под названием Kv, который используется для определения пользовательского интерфейса и его свойств. Язык Kv позволяет разработчикам легко создавать сложные и гибкие интерфейсы с минимальным кодом Python.
  5. Кросс-платформенность: Kivy позволяет разработчикам создавать одну кодовую базу для приложения, которая будет работать на разных платформах. Это значительно снижает затраты на разработку и поддержку приложения.

Для начала работы с Kivy, вам нужно установить его с помощью pip:

pip install kivy

Затем вы можете создать свое первое приложение на Kivy, используя простой код Python:

from kivy.app import App from kivy.uix.button import Button class MyApp(App): def build(self): return Button(text='Hello, Kivy!') if __name__ == '__main__': MyApp().run()

Этот код создаст простое приложение с кнопкой и текстом “Hello, Kivy!”.

Обратите внимание, что Python может быть не лучшим выбором для всех типов мобильных приложений, особенно если вам требуется высокая производительность или широкое использование специфических для платформы API. В таких случаях вам может потребоваться использовать языки разработки нативных приложений, такие как Kotlin для Android или Swift для iOS. Однако для более простых приложений или прототипов Python может быть подходящим вариантом.

Kivy сам по себе не компилирует код Python в нативный код Android. Вместо этого Kivy использует инструмент под названием Buildozer, который автоматизирует процесс сборки Kivy-приложений для различных платформ, включая Android и iOS. Для Android Buildozer использует другой инструмент под названием Python for Android (Py4A или p4a).

Вот как Kivy и Buildozer работают вместе для компиляции приложения на Android:

  1. Установка Buildozer: Сначала вам нужно установить Buildozer с помощью pip:
pip install buildozer
  1. Создание спецификации проекта: Buildozer использует файл спецификации проекта ( buildozer.spec ) для настройки процесса сборки. Вы можете создать этот файл, запустив команду buildozer init в каталоге вашего проекта. Затем откройте файл buildozer.spec и настройте параметры в соответствии с вашим приложением.
  2. Компиляция приложения: Запустите следующую команду в каталоге вашего проекта, чтобы начать процесс сборки приложения для Android:
buildozer android debug deploy run

Обратите внимание, что весь код Python не компилируется в нативный код, а выполняется во встроенном интерпретаторе Python. Это может привести к более низкой производительности по сравнению с нативными приложениями Android, написанными на Java или Kotlin.

В общем вывод в том, что теоретически можно написать что угодно на чём угодно. Но если это возможно – совсем не значит, что вам следует это делать. Создание мобильных приложений на Python будет использовать несколько слоев и сторонних библиотек и кроме самых простых случаев, наверняка всегда будет работать криво.

Entrepreneur and full-stack web developer capable of multitasking and completing large-scale projects in a short period of time. Founder of moy-razmer.ru and nomadicsoft.io, large experience in e-commerce and various SaaS projects

Создание мобильных приложений на Python: интересное занятие для детей

Сегодня язык программирования Python — один из самых востребованных в мире. Несмотря на свой приличный возраст — почти 22 года — он не теряет актуальности и используется все чаще. За последние годы индекс популярности языков программирования TIOBE, в составлении которого участвуют разработчики со всего мира, трижды провозгласил его языком года. В этой статье поговорим о том, чем же он так хорош, и какие мобильные приложения на Python смогут попробовать создать начинающие программисты.

Что такое Python

Если коротко, то в конце 80-х годов прошлого века голландский математик и программист Гвидо ван Россум начал создавать новый текстовый язык программирования. Основным его планом было сделать синтаксис своего детища по-настоящему простым и не громоздким, и все получилось. Там, где в другом языке нужно использовать семь строчек кода, в Питоне можно обойтись двумя. Приведем простейший пример.

Как напечатать «Hello, World» на Python:

print «Hello World» # Python < 3.0 print(«Hello World«) # Python ≥ 3.0

И на другом популярном языке Java

public class Main < public static void main (String[] args) < System.out.println(«Hello World«); >>

Эта особенность языка Питон позволяет легче изучать его, увеличивает производительность, существенно упрощает и написание, и чтение кода. Ну и, конечно, делает его таким популярным.

Кроме того, разработчики любят Python за возможность экономить усилия и время. Часть модулей при создании программ можно не писать самостоятельно, а взять уже готовые в одной из обширных библиотек. Еще одной важной особенностью считается то, что этот язык поддерживает базы Big Data. Ведь именно на них основано большинство современных и актуальных разработок, технических и научных.

На Python сегодня пишут все: от чат-ботов, мобильных и веб-приложений до сложнейших систем по изучению и анализу больших данных и обучению искусственного интеллекта. Все говорит о том, что этим языком будут пользоваться, как минимум, ближайшие несколько десятилетий.

Поэтому сегодня так много родителей в качестве внеклассных занятий выбирают курсы обучения подростков программированию на Python. В первую очередь, это интересно, во вторую, хотя для многих это стоит на первом месте, полезно. Профессия питон-разработчика не только перспективная и востребованная, но и хорошо оплачиваемая. Так что, такие уроки программирования для детей — инвестиция в их будущее.

Создание приложений на Python

Недостатком языка программирования Питон в том, что в нем нет встроенных функций мобильного интерфейса. Ведь когда его придумали, и речи не шло о написании программ для смартфонов. Поэтому традиционно Python считается языком программирования для веб-разработки.

Однако со временем «питонисты» смогли адаптировать свой любимый язык и под создание мобильных приложений на Python. Для этого они создали несколько фреймворков, то есть, IT-моделей, которые позволяют заниматься мобильной разработкой в среде Питон. Самые популярные из них — Kivy и Beeware.

Kivy — это библиотека с открытым исходным кодом. Чаще всего ее используют для написания кроссплатформенных приложений, которые будут одинаково выглядеть и работать везде: на iOS и Android, Windows и macOS.

BeeWare считается более гибким, поскольку позволяет создавать приложения с разным пользовательским интерфейсом (UI) для различных платформ. Поэтому чаще разработчики отдают предпочтение ему.

Сегодня с использованием Python поддерживается работа таких популярных приложений, как, например, Pinterest, который изначально писался именно на этом языке. На нем же написан Panda3D — движок, на котором создаются практически все мобильные игры от Walt Disney. Да что там, даже мобильные версии Google и YouTube уже не могут обойтись без Питона. Так что обучение созданию мобильных приложений для детей, да и для взрослых, изучающих Python — практически маст хэв. Тем более, вам вовсе не обязательно начинать с чего-то сложного.

Простые мобильные игры

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

Угадай число — игра, в которой программа загадывает случайное число в определенном диапазоне, а игрок или игроки должны его отгадать.

Чтобы ее написать, нужно использовать генератор случайных чисел. Как научить программу выбирать число из списка, можно посмотреть в бесплатном видео-уроке по Python.

Случайное число в Python: видео-урок для детей

Кроме него для написания кода используются переменные и целые числа, функция вывода на экран, операторы if/else и цикл while, позволяющий повторять одни и те же действия, пока условие, которое он проверяет, истинно.

Можно попробовать сделать и более продвинутый вариант этой игры — Виселицу. В ней игрока будет ограниченное количество попыток отгадать уже не цифры, а буквы в заданном программой слове.

Список слов можно взять в одном из словарей библиотеки Питон, например, в Sowpods. Помимо этого, пригодится опыт работы с циклом while, освежить знания о котором можно, посмотрев видео-урок ниже.

Видео-урок по работе с циклами на Python

Также советуем вспомнить, генератор случайных чисел, обработку ввода и вывод, условия if/else, работу со строками и со списками:

Видео-урок по работе со списками на Python

Камень, ножницы, бумага – игра, рассказывать о правилах которой нет смысла, все и так их знают. Просто играете вы в нее не с кем-то другим, а с приложением.

Здесь вам тоже нужно будет знать, как в Python создается генератор случайных чисел, уметь обрабатывать ввод данных и выводить их на экран, использовать все тот же цикл while. Ну и не стоит забывать про условные конструкции if/else, подробнее о которых можно узнать в этом видеоуроке по обучению детей программированию на Python.

Условные конструкции: видео-урок по программированию на Python для детей

Текстовый квест – в самом простом его варианте игрок переходит из локации в локацию, получая их описание. Локации зависят от вашей фантазии, это могут быть как разные комнаты, так и разные миры.

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

Правила игры в крестики нолики тоже известны многим – на поле размером 3х3 квадрата каждый из игроков рисует свою фигуру, крестик или нолик. Выигрывает тот, кто первым сможет поставить три фигуры в ряд по горизонтали, вертикали или диагонали.

Здесь уже понадобится использовать графику, например, из библиотеки PyGame. Но основная сложность не в этом, а в программировании ходов приложения, для чего вам придется учесть максимально возможное количество вариантов развития игровых событий.

Полезные приложения и виджеты на Python

Чтобы обучение детей программированию на Python не сводилось только к созданию игр, поговорим о программах, которые могут пригодиться им на практике, например, при произведении вычислений, поиске информации, планировании своего времени и так далее.

Сама простая из них называется алгоритмом двоичного поиска и позволяет проверять, есть ли запрошенная пользователем информация в известном списке данных. Для этого в программу вводится тот самый список чисел, слов и так далее. Пользователь вводит запрос, программа проводит его сверку со списком и выводит результат.

Начинающему разработчику здесь нужны будут знания о создании циклов, умение программировать ввод и вывод данных, а также условия if/else.

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

Помочь в создании графического интерфейса могут данные библиотек Tkinter и PyQt.

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

Следующая полезная программа, связанная со временем – таймер обратного отсчета до указанного вами события, который будет виден на основном экране или экране блокировки, и предупредит сигналом о наступлении того самого события.

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

Чтобы реализовать весь ее несложный функционал, можно использовать QTextEdit.

Обучение программированию на Python для детей

Сегодня, когда всюду действует правило mobile first, то есть, большинство интерфейсов сначала создаются для мобильных браузеров или приложений, мобильный разработчик – отличная профессия для настоящего и будущего.

Научиться созданию приложений на Python можно и самостоятельно, информации на просторах интернета для этого достаочно. Но чаще всего дети и подростки еще не могут сами правильно построить программу, систематизировать информацию, найти ее в нужном объеме. Поэтому начинать изучение Python лучше на специальных курсах, где ребята могут заниматься уже с 9-10 лет. Чтобы заниматься, достаточно компьютера и стабильно работающего интернета, ведь уроки программирования для детей проходят онлайн раз в неделю, индивидуально или в группе. За три месяца они освоят основы программирования на Питоне и дальше смогут развиваться в интересном им направлении: создавать игры, писать интересные и полезные приложения, придумывать что-то принципиально новое.

Кстати, нынешнее поколение senior-разработчиков и руководителей команд в 20-21 год выросло из детей, которые пришли в разработку в раннем возрасте. Многие из них получают высшее образование и параллельно работают в крупных компаниях, создают программы для портфолио, участвуют в хакатонах (соревнованиях для программистов) для получения необходимого опыта.

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

Как создать игру для мобильного телефона #1 — [Делаем Тетрис на Python + Kivy]

Иконка канала Программирование / Олег Шпагин / Python Админ Tech

Привет друзья! Это серия видео уроков по Python, на которых мы с вами будем постепенно делать мобильную игру Тетрис для iOS/Apple и Android.))) Это первый урок #1. В этом видео мы создадим рабочую область нашего приложения / игры. Будем использовать фреймворк Kivy. Как создать игру для мобильного телефона? Смотри ответ в видео! ✔ Телеграм — https://t.me/wiseplat �� ✔ Вступай в группу Вк — https://vk.com/wiseplat1 �� ✔ Подписывайся https://zen.yandex.ru/id/5e9a612424270736479fad54 ✔ Поддержи проект: https://wiseplat.org/donat ❗️ Конечно, будет продолжение, если будет много позитивов. �� Нажимай колокольчик чтобы не пропустить! #урокиpython #python #делаемигру #игра — Уроки от #OlegShpagin ������ Ставь лайк, если тебе понравилось видео �� ►► Подписывайся на канал! Вот код из видео, для тех, кто в позитиве: https://github.com/WISEPLAT/python-code/tree/master/python-igra-tetris-kivy как создать игру,как сделать игру,создание игр,разработка игр,Тетрис Python,делаем игру на python,игра python,как сделать игру на python,игры python,python,pycharm,пайтон,python с нуля уроки,питон уроки,python уроки,пайчарм,уроки по питону,уроки питона,питон для начинающих,pycharm python,для начинающих,программирование,как начать программировать,с чего начать,python для начинающих,программирование с нуля,игра на python,kivy,игра на kivy

Показать больше

Войдите , чтобы оставлять комментарии

Разработка игры под Android на Python на базе Kivy. От А до Я: подводные камни и неочевидные решения. Часть 1

Некоторое время тому назад я решил попробовать написать что-то на Python под Android. Такой странный для многих выбор обусловлен тем, что я люблю Python и люблю Android, а ещё люблю делать необычное (ну хорошо, не самое обычное). В качестве фреймворка был выбран Kivy — фактически, безальтернативный вариант, но он мне очень понравился. Однако, по нему не так уж много информации (нет, документация отличная, но иногда её недостаточно), особенно на русском языке, а некоторые вещи хоть и можно реализовать, но их то ли никто раньше не делал, то ли не счёл нужным поделиться информацией. Ну а я счёл 🙂 И этот пост тому результатом.

Под катом я расскажу обо всех этапах разработки, о том, как развивалась простая идея и как для этого приходилось искать новые возможности, о возникших подводных камнях и багах, о неочевидных решениях и устаревшей документации 🙂 Цель — описать в одном тексте основные пункты, чтобы человеку, решившему написать что-то немного сложнее игры Pong из официального туториала, не приходилось перерывать официальный форум поддержки и StackOverflow и тратить часы на то, что делается за пару минут, если знаешь, как.

0. Если вы впервые слышите о Kivy.

… то всё зависит от того, любите ли вы Python и Android, и интересно ли вам в этом разобраться. Если нет — проще забить 🙂 А если да, то начать нужно с официальной документации, гайдов, и уже упомянутого официального туториала по игре Pong — это даст базовое представление о фреймворке и его возможностях. Я же не буду останавливаться на столь тривиальных вещах (тем более, для понимания базовых принципов туториал отлично подходит) и сразу пойду дальше. Будем считать, что это было вступление 🙂

1. Немного о моей игре

Для начала нужна была идея. Мне хотелось что-то достаточно простое, чтобы оценить возможности фреймворка, но и достаточно интересное и оригинальное, чтобы не программировать ради программирования (это здорово, но когда это не единственная цель — это ещё лучше). Я неплохо проектирую интерфейсы, но не умею рисовать, поэтому игра должна была быть простая графически, или вообще текстовая. И тут так уж сложилось, что у меня есть заброшенный сайт с цитатами, с которого я когда-то начинал свой путь в web-разработке (я о нём даже писал на Хабре много лет назад). Поэтому идея возникла такая: игра-викторина «Угадай цитату». В русскоязычном Google Play ничего подобного не было, а в англоязычном была пара поделок низкого качества с сотней скачиваний.

Почти сразу же стало понятно, что просто так отгадывать цитату за цитатой — скучно. Так появились первые «фишки», которые, в итоге, и определили итоговую игру. В первую очередь это были тематические пакеты (то есть пакеты цитат, объединённые одной темой или автором) и баллы (которые начисляются за отгадывание цитат и прохождение пакетов, и тратятся на подсказки и разблокировку новых тем), а также статистика, достижения и избранное.

Немного картинок

Так всё начиналось (кликабельно):

Ну ладно, ладно, больше не буду показывать такой ужас 🙂 Кстати, вот так оно выглядит сейчас (тоже кликабельно, скрины взяты с Google Play):

Первые проблемы начались с первого же экрана…

2. Kivy тормоз или я что-то делаю не так?

Один мой друг любит отвечать на такие вопросы «да» 🙂 На самом деле, некоторые вещи в Kivy действительно работают медленно, например, создание виджетов. Но это не значит, что это дело нельзя оптимизировать. Об этом я и расскажу.

Так как цитаты и темы хранятся в БД, то, само собой, кнопки с пакетами генерируются динамически. И вот тут-то я обнаружил, что происходит это очень медленно: примерно полсекунды на список из 20 кнопок. Возможно, это и не очень много при загрузке приложения, но при переходе на главный экран из других внутренних экранов приложения — непозволительно много. Здесь стоит отметить, что кнопка к тому моменту уже представляла собой, на самом деле, набор из нескольких элементов, визуально составляющих одну кнопку:

Первым моим побуждением было тем или иным образом закешировать их, и, действительно, опыт показал, что если создать все виджеты заранее, и сохранить их как свойство объекта StartScreen, то всё (кроме первой генерации) работает достаточно быстро. Однако же, данные в кнопках нужно периодически обновлять (хотя бы то же количество отгаданных цитат). Да и загрузку новых пакетов я уже тогда планировал. Конечно, не проблема реализовать и это, но я решил не изобретать велосипед и подумать.

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

Исходный код тестового приложения

from kivy.app import App from kivy.uix.screenmanager import ScreenManager, Screen from kivy.uix.boxlayout import BoxLayout from kivy.properties import ObjectProperty, StringProperty from kivy.clock import Clock from time import time class ListScreen(Screen): items_box = ObjectProperty(None) def on_enter(self): start = time() for i in range(0,50): self.items_box.add_widget(ListItem('Item '+str(i))) self.items_box.bind(minimum_height=self.items_box.setter('height')) print time()-start def on_leave(self): self.items_box.clear_widgets() class ListItem(BoxLayout): title = StringProperty('') def __init__(self, title, **kwargs): super(ListItem, self).__init__(**kwargs) self.title = title class ListApp(App): sm = ScreenManager() screens = <> def build(self): self.__create_screens() ListApp.sm.add_widget(ListApp.screens['list1']) Clock.schedule_interval(self._switch, 1) return ListApp.sm def _switch(self, *args): ListApp.sm.switch_to(ListApp.screens['list1' if ListApp.sm.current != 'list1' else 'list2']) def __create_screens(self): ListApp.screens['list1'] = ListScreen(name='list1') ListApp.screens['list2'] = ListScreen(name='list2') if __name__ == '__main__': ListApp().run()
: items_box: items_box BoxLayout: orientation: "vertical" AnchorLayout: size_hint_y: 0.1 padding: self.width*0.1, self.height*0.05 Label: font_size: root.height*0.05 text: "Some list" ScrollView: size_hint_y: 0.9 size: self.size BoxLayout: id: items_box orientation: "vertical" padding: self.width*0.1, 0 size_hint_y: None : orientation: "horizontal" size_hint_y: None height: app.sm.height*0.1 Label: font_size: app.sm.height*0.025 text: root.title size_hint_x: 0.9 text_size: self.size valign: "middle" CheckBox size_hint_x: 0.1

Запустил на своём стареньком Moto G (gen3) и получил:

11-28 11:44:09.525 1848 2044 I python : 0.5793800354 11-28 11:44:10.853 1848 2044 I python : 0.453143119812 11-28 11:44:12.544 1848 2044 I python : 0.633069992065 11-28 11:44:13.697 1848 2044 I python : 0.369570970535 11-28 11:44:14.988 1848 2044 I python : 0.594089031219

И далее в том же духе. Поиск по этому вопросу ничего не дал, поэтому я обратился к разработчикам. И получил ответ: «Создание виджетов относительно медленное, особенно в зависимости от того, что они содержат. Для создания больших списков лучше использовать RecycleView». Здесь хочу пояснить, почему я вообще описываю этот момент, ведь описание RecycleView есть в документации. Да, действительно, есть, но мало кто способен изучить и запомнить всю документацию перед тем, как начнёт разработку, и найти нужный инструмент бывает непросто, особенно если он нигде не описан в контексте решения конкретной проблемы. Теперь же он описан 🙂

Исходный код тестового приложения с RecycleView

from kivy.app import App from kivy.uix.screenmanager import ScreenManager, Screen from kivy.properties import ObjectProperty from kivy.clock import Clock from time import time class ListScreen(Screen): recycle_view = ObjectProperty(None) items_box = ObjectProperty(None) def on_enter(self): start = time() for i in range(0,50): self.recycle_view.data.append() print time()-start def on_leave(self): self.recycle_view.data = [] class ListApp(App): sm = ScreenManager() screens = <> def build(self): self.__create_screens() ListApp.sm.add_widget(ListApp.screens['list1']) Clock.schedule_interval(self._switch, 1) return ListApp.sm def _switch(self, *args): ListApp.sm.switch_to(ListApp.screens['list1' if ListApp.sm.current != 'list1' else 'list2']) def __create_screens(self): ListApp.screens['list1'] = ListScreen(name='list1') ListApp.screens['list2'] = ListScreen(name='list2') if __name__ == '__main__': ListApp().run()
: recycle_view: recycle_view items_box: items_box BoxLayout: orientation: "vertical" AnchorLayout: size_hint_y: 0.1 padding: self.width*0.1, self.height*0.05 Label: font_size: root.height*0.05 text: "Some list" RecycleView: id: recycle_view size_hint: 1, 0.9 viewclass: "ListItem" RecycleBoxLayout: id: items_box orientation: "vertical" padding: self.width*0.1, 0 default_size_hint: 1, None size_hint: 1, None height: self.minimum_height : orientation: "horizontal" size_hint: 1, None height: app.sm.height*0.1 title: '' Label: font_size: app.sm.height*0.025 text: root.title size_hint_x: 0.9 text_size: self.size valign: "middle" CheckBox size_hint_x: 0.1
11-29 13:11:58.196 13121 13203 I python : 0.00388479232788 11-29 13:11:59.192 13121 13203 I python : 0.00648307800293 11-29 13:12:00.189 13121 13203 I python : 0.00288391113281 11-29 13:12:01.189 13121 13203 I python : 0.00324606895447 11-29 13:12:03.188 13121 13203 I python : 0.00265002250671

Более чем в 100 раз быстрее. Впечатляет, не правда ли?

В завершение следует упомянуть, что RecycleView — не панацея. Он не подходит, если размер элемента зависит от содержимого (например, Label, размер которого меняется в зависимости от количества текста).

3. Сервисы. Автозапуск и перезапуск

Следующая проблема, с которой я столкнулся, не поддавалась решению так долго, что я уже малодушно подумывал счесть данный фреймворк непригодным и забить 🙂 Проблема была с сервисами (в Android так называется процессы, выполняющиеся в фоновом режиме). Создать сервис не так уж и сложно — немного сбивает с толку устаревшая документация, но и только. Однако, в большинстве случаев, много ли толку от сервиса, который, во-первых, не запускается автоматически при загрузке телефона, а во-вторых, не перезапускается, если «выбросить» приложение свайпом из диспетчера задач? По-моему, нет.

На тот момент по этой теме была всего лишь одна статья в официальной wiki, но она, хоть и называлась «Starting Kivy service on bootup», на самом деле всего лишь рассказывала, как при загрузке телефона запустить приложение, но не его сервис (да, такое тоже бывает полезно, но значительно реже, как по мне). Ту статью я, в итоге, переписал, а здесь расскажу подробности.

Допустим, у нас есть примитивный сервис, который всего-то и делает, что периодически выводит в лог строку (этим мы заранее исключаем баги, которые могут возникать из-за особенностей самого сервиса).

from time import sleep if __name__ == '__main__': while True: print "myapp service" sleep(5)

Из приложения мы запускаем его методом основного класса при помощи PyJnius:

 from jnius import autoclass # . # class GuessTheQuoteApp(App): # . # def __start_service(self): service = autoclass('com.madhattersoft.guessthequote.ServiceGuessthequoteservice') mActivity = autoclass('org.kivy.android.PythonActivity').mActivity service.start(mActivity, "")

Если APK собран правильно, при запуске приложения сервис будет стартовать, но этого недостаточно.

Для начала, попробуем сделать так, чтобы он перезапускался при остановке приложения (например, при снятии его из диспетчера задач). Конечно, можно было бы использовать startForeground, но это уже не совсем фоновое выполнение задачи 🙂 Для него потребуется, как минимум, уведомление — это не всегда подходит. В данном случае идеально подходит флаг START_STICKY, но мы же пишем на Python, что делает задачу не столь тривиальной — по крайней мере, при помощи PyJnius она уже не решается.

Честно говоря, она вообще решается достаточно криво, поскольку я пока не готов становиться одним из разработчиков Python4Android, благодаря которому всё это счастье вообще работает. А изменения нужно вносить именно в код Python4Android. А конкретно, нам нужен файл .buildozer/android/platform/build/dists/guessthequote/src/org/kivy/android/PythonService.java в котором в функции startType() мы меняем флаг START_NOT_STICKY на START_STICKY:

public int startType()

Ура, сервис рестартится. Всё? Конечно, нет 🙂 Потому что он тут же валится с ошибкой:

E AndroidRuntime: Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'android.os.Bundle android.content.Intent.getExtras()' on a null object reference

Проблема в функции onStartCommand(Intent intent, int flags, int startId), поскольку после перезапуска intent у нас null. Что ж, перепишем и её:

@Override public int onStartCommand(Intent intent, int flags, int startId) < if (pythonThread != null) < Log.v("python service", "service exists, do not start again"); return START_NOT_STICKY; >if (intent != null) < startIntent = intent; Bundle extras = intent.getExtras(); androidPrivate = extras.getString("androidPrivate"); androidArgument = extras.getString("androidArgument"); serviceEntrypoint = extras.getString("serviceEntrypoint"); pythonName = extras.getString("pythonName"); pythonHome = extras.getString("pythonHome"); pythonPath = extras.getString("pythonPath"); pythonServiceArgument = extras.getString("pythonServiceArgument"); pythonThread = new Thread(this); pythonThread.start(); if (canDisplayNotification()) < doStartForeground(extras); >> else < pythonThread = new Thread(this); pythonThread.start(); >return startType(); >
F DEBUG : Abort message: 'art/runtime/java_vm_ext.cc:410] JNI DETECTED ERROR IN APPLICATION: GetStringUTFChars received NULL jstring'

Проблема в том, что функция nativeStart() не получает нужных Extras. К сожалению, два из них мне пришлось захардкодить. В итоге выглядит это так:

@Override public void run() < String package_root = getFilesDir().getAbsolutePath(); String app_root = package_root + "/app"; File app_root_file = new File(app_root); PythonUtil.loadLibraries(app_root_file); this.mService = this; if (androidPrivate == null) < androidPrivate = package_root; >if (androidArgument == null) < androidArgument = app_root; >if (serviceEntrypoint == null) < serviceEntrypoint = "./service/main.py"; // hardcoded >if (pythonName == null) < pythonName = "guessthequoteservice"; // hardcoded >if (pythonHome == null) < pythonHome = app_root; >if (pythonPath == null) < pythonPath = package_root; >if (pythonServiceArgument == null) < pythonServiceArgument = app_root+":"+app_root+"/lib"; >nativeStart( androidPrivate, androidArgument, serviceEntrypoint, pythonName, pythonHome, pythonPath, pythonServiceArgument); stopSelf(); >

Перейдём к автозапуску сервиса при запуске телефона. После предыдущей проблемы это будет уже проще. (На самом деле же всё было наоборот — я очень долго не мог понять, что именно нужно добавить, поскольку информации об этом не было вообще нигде, и сами разработчики тоже не знали, как решить данную задачу. И только разобравшись параллельно с вопросом перезапуска, я понял, что нужно сделать.)

Для начала понадобится разрешение RECEIVE_BOOT_COMPLETED — это просто. А затем — BroadcastReceiver, его придётся добавить в AndroidManifest вручную, но это тоже не проблема. Проблема в том, что в нём писать 🙂

Решение для запуска приложения (не сервиса) выглядит так:

package com.madhattersoft.guessthequote; import android.content.BroadcastReceiver; import android.content.Intent; import android.content.Context; import org.kivy.android.PythonActivity; public class MyBroadcastReceiver extends BroadcastReceiver < public void onReceive(Context context, Intent intent) < Intent ix = new Intent(context, PythonActivity.class); ix.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(ix); >>

Сначала я попытался просто переписать его для сервиса:

package com.madhattersoft.guessthequote; import android.content.BroadcastReceiver; import android.content.Intent; import android.content.Context; import com.madhattersoft.guessthequote.ServiceGuessthequoteservice; public class MyBroadcastReceiver extends BroadcastReceiver < public void onReceive(Context context, Intent intent) < Intent ix = new Intent(context, ServiceGuessthequoteservice.class); ix.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startService(ix); >>
E AndroidRuntime: java.lang.RuntimeException: Unable to start service com.madhattersoft.guessthequote.ServiceGuessthequoteservice@8c96929 with Intent < cmp=com.madhattersoft.guessthequote/.ServiceGuessthequoteservice >: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.os.Bundle.getString(java.lang.String)' on a null object reference

Думаю, вам уже понятно, что проблема в тех самых Extras. Мне же тогда об этом было узнать неоткуда. Но не буду тянуть, рабочий код выглядит так:

 package import com.madhattersoft.guessthequote; import android.content.BroadcastReceiver; import android.content.Intent; import android.content.Context; import com.madhattersoft.guessthequote.ServiceGuessthequoteservice; public class MyBroadcastReceiver extends BroadcastReceiver < public void onReceive(Context context, Intent intent) < String package_root = context.getFilesDir().getAbsolutePath(); String app_root = package_root + "/app"; Intent ix = new Intent(context, ServiceGuessthequoteservice.class); ix.putExtra("androidPrivate", package_root); ix.putExtra("androidArgument", app_root); ix.putExtra("serviceEntrypoint", "./service/main.py"); ix.putExtra("pythonName", "guessthequoteservice"); ix.putExtra("pythonHome", app_root); ix.putExtra("pythonPath", package_root); ix.putExtra("pythonServiceArgument", app_root+":"+app_root+"/lib"); ix.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startService(ix); >>

Локализация и мультиязычность

В целом, для локализации можно использовать gettext, или же поступить ещё проще — создать папку lang, в ней по файлу на каждый язык (например, en.py и ru.py), определить там все слова и фразы в виде переменных/констант, и далее подключить нужный модуль. Примерно так:

if autoclass('java.util.Locale').getDefault().getLanguage() in ('ru', 'uk', 'be'): import lang.ru as lang else: import lang.en as lang GuessTheQuote.lang = lang

Статическая переменная использована для того, чтобы языковые константы было удобно использовать в kv-файле:

app.lang.some_phrase

Это, в общем-то, довольно тривиально, а основное, о чём я хотел рассказать в аспекте локализации — как задать константы в res/values/strings.xml и отдельных локализациях. Зачем это нужно? Как минимум, чтобы задать название приложения на разных языках, а также чтобы прописать такие константы, как app_id для сервисов Google Play и facebook_app_id для сервисов Facebook.

По-умолчанию P4A генерирует strings.xml следующего содержания:

  Guess The Quote 1517538478.81 #2EBCB2 kivy 

При этом название приложения и цвет фона экрана загрузки можно задать в buildozer.spec. На первый взгляд, этого достаточно, но это только в том случае, если приложение одноязычное, и дополнительные строковые константы не нужны, а это как-то минималистично 🙂 Конечно, никто не запрещает вручную прописать всё необходимое, но при следующей сборке оно затрётся. Также можно вручную создать папки с локализациями, например, values-ru, но они при новых сборках они не будут обновляться. Поэтому лучше ещё раз подправить P4A, а именно, файл .buildozer/android/platform/build/dists/guessthequote/build.py следующим образом:

# оригинальный код, в текущей версии P4A начинается на строке 370 render( 'strings.tmpl.xml', 'res/values/strings.xml', args=args, url_scheme=url_scheme, ) # заменяем на усовершенствованный :) local_args = for key in local_args: local_args[key].name = u'Угадай цитату!' # ну захардкодил, да, ну не готов я пока сделать свой форк P4A и buildozer, чтобы сделать это через передачу параметра for i in os.listdir('res'): if i[:6] == 'values': render( 'strings.tmpl.xml', 'res/'+i+'/strings.xml', args=(args if i == 'values' else local_args[i[7:10]]), url_scheme=url_scheme, ) # и ещё один фрагмент, в текущей версии P4A начиная со строки 388 with open(join(dirname(__file__), 'res', 'values', 'strings.xml')) as fileh: lines = fileh.read() with open(join(dirname(__file__), 'res', 'values', 'strings.xml'), 'w') as fileh: fileh.write(re.sub(r'"private_version">[0-9\.]*<><'.format( str(time.time())), lines)) # тоже заменяем на аналогичный в цикле for i in os.listdir('res'): if i[:6] == 'values': with open(join(dirname(__file__), 'res', i, 'strings.xml')) as fileh: lines = fileh.read() with open(join(dirname(__file__), 'res', i, 'strings.xml'), 'w') as fileh: fileh.write(re.sub(r'"private_version">[0-9\.]*<><'.format( str(time.time())), lines))

Ну а все необходимые вам строковые константы нужно прописать в файле .buildozer/android/platform/build/dists/guessthequote/templates/strings.tmpl.xml

Продолжение следует

Если статья покажется сообществу интересной, во второй части я опишу самые интересные вещи: покупки в приложении, интеграцию сервисов Google Play Games и Facebook SDK, и подготовку release version с последующей публикацией в Google Play, а также подготовлю проект на Github с модулями для реализации описанных задач. Если вам интересны ещё какие-то подробности — напишите в комментариях, постараюсь по возможности осветить.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *