LICENSE: verbatim copy of android-app-template's (official SPDX text, not retyped) — GPL-3.0 as previously decided. Update checker: check_latest_release()/download_and_install()/ MessagePopup ported from the template, wired to a new "Check for Updates" button next to Settings. Requires certifi added to p4a-recipes/kivy's python_depends (HTTPS on Android needs an explicit CA bundle) and INTERNET/REQUEST_INSTALL_PACKAGES added to buildozer.spec. FORGEJO_TOKEN at the top of main.py ships blank — update checking is inert until it's set to a repo-scoped read-only token. download_and_install() is the standard p4a pattern but not yet verified on real hardware, same caveat as the template it came from. Dropped the previously-agreed config.json split (event list vs. data path) — decided it's not needed after all.
130 lines
5.4 KiB
Python
130 lines
5.4 KiB
Python
# Local override of p4a's built-in kivy recipe — identical except
|
|
# python_depends is trimmed. See buildozer.spec for the full story:
|
|
# upstream's ['certifi', 'chardet', 'idna', 'requests', 'urllib3',
|
|
# 'filetype'] pulls in requests -> charset-normalizer, whose newest
|
|
# release ships an Android-tagged wheel that p4a's own install step
|
|
# can't actually install.
|
|
#
|
|
# 'filetype' and 'certifi' are kept — neither is part of that broken
|
|
# chain (both pure Python, zero deps of their own, no requests/
|
|
# charset-normalizer involved):
|
|
# - filetype: kivy/core/image/__init__.py imports it directly for
|
|
# image format sniffing. Confirmed the hard way — dropping it too
|
|
# caused a startup crash on-device: ModuleNotFoundError: No module
|
|
# named 'filetype'.
|
|
# - certifi: main.py's update checker needs it for HTTPS on Android
|
|
# (see the comment on check_latest_release() in main.py) — the
|
|
# desktop-facing v1 of this app never made a network call, so it
|
|
# never needed this until the update checker was ported over.
|
|
# The remaining three (chardet, idna, requests, urllib3 minus what's
|
|
# listed above) are only for kivy.network.UrlRequest, which this app
|
|
# still never calls — reminder: editing python_depends here alone isn't
|
|
# enough for the change to take effect on an existing build. p4a caches
|
|
# the built dist by name+recipe-list and won't re-derive python_depends
|
|
# for a dist that already exists — delete
|
|
# .buildozer/android/platform/build-<arch>/dists/<package.name> after
|
|
# any python_depends change or the fix will silently not apply. See
|
|
# CLAUDE.md for the full trace of that gotcha.
|
|
from os.path import join
|
|
import sys
|
|
import packaging.version
|
|
|
|
import sh
|
|
from pythonforandroid.recipe import PyProjectRecipe
|
|
from pythonforandroid.toolchain import current_directory, shprint
|
|
|
|
|
|
def get_kivy_version(recipe, arch):
|
|
with current_directory(join(recipe.get_build_dir(arch.arch), "kivy")):
|
|
return shprint(
|
|
sh.Command(sys.executable),
|
|
"-c",
|
|
"import _version; print(_version.__version__)",
|
|
)
|
|
|
|
|
|
def is_kivy_affected_by_deadlock_issue(recipe=None, arch=None):
|
|
return packaging.version.parse(
|
|
str(get_kivy_version(recipe, arch))
|
|
) < packaging.version.Version("2.2.0.dev0")
|
|
|
|
|
|
def is_kivy_less_than_3(recipe=None, arch=None):
|
|
return packaging.version.parse(
|
|
str(get_kivy_version(recipe, arch))
|
|
) < packaging.version.Version("3.0.0.dev0")
|
|
|
|
|
|
class KivyRecipe(PyProjectRecipe):
|
|
version = '2.3.1'
|
|
url = 'https://github.com/kivy/kivy/archive/{version}.zip'
|
|
name = 'kivy'
|
|
|
|
depends = [('sdl2', 'sdl3'), 'pyjnius', 'setuptools', 'android']
|
|
python_depends = ['filetype', 'certifi'] # upstream also had: 'chardet', 'idna', 'requests', 'urllib3' — unused, see buildozer.spec
|
|
hostpython_prerequisites = ["cython>=0.29.1,<=3.0.12"]
|
|
|
|
# sdl-gl-swapwindow-nogil.patch is needed to avoid a deadlock.
|
|
# See: https://github.com/kivy/kivy/pull/8025
|
|
# WARNING: Remove this patch when a new Kivy version is released.
|
|
patches = [
|
|
("sdl-gl-swapwindow-nogil.patch", is_kivy_affected_by_deadlock_issue),
|
|
("use_cython.patch", is_kivy_less_than_3),
|
|
"no-ast-str.patch"
|
|
]
|
|
|
|
@property
|
|
def need_stl_shared(self):
|
|
if "sdl3" in self.ctx.recipe_build_order:
|
|
return True
|
|
else:
|
|
return False
|
|
|
|
def get_recipe_env(self, arch, **kwargs):
|
|
env = super().get_recipe_env(arch, **kwargs)
|
|
|
|
# Taken from CythonRecipe
|
|
env['LDFLAGS'] = env['LDFLAGS'] + ' -L{} '.format(
|
|
self.ctx.get_libs_dir(arch.arch) +
|
|
' -L{} '.format(self.ctx.libs_dir) +
|
|
' -L{}'.format(join(self.ctx.bootstrap.build_dir, 'obj', 'local',
|
|
arch.arch)))
|
|
env['LDSHARED'] = env['CC'] + ' -shared'
|
|
env['LIBLINK'] = 'NOTNONE'
|
|
|
|
# NDKPLATFORM is our switch for detecting Android platform, so can't be None
|
|
env['NDKPLATFORM'] = "NOTNONE"
|
|
if not is_kivy_less_than_3(self, arch):
|
|
env['KIVY_CROSS_PLATFORM'] = 'android'
|
|
|
|
if 'sdl2' in self.ctx.recipe_build_order:
|
|
env['USE_SDL2'] = '1'
|
|
env['KIVY_SPLIT_EXAMPLES'] = '1'
|
|
sdl2_mixer_recipe = self.get_recipe('sdl2_mixer', self.ctx)
|
|
sdl2_image_recipe = self.get_recipe('sdl2_image', self.ctx)
|
|
env['KIVY_SDL2_PATH'] = ':'.join([
|
|
join(self.ctx.bootstrap.build_dir, 'jni', 'SDL', 'include'),
|
|
*sdl2_image_recipe.get_include_dirs(arch),
|
|
*sdl2_mixer_recipe.get_include_dirs(arch),
|
|
join(self.ctx.bootstrap.build_dir, 'jni', 'SDL2_ttf'),
|
|
])
|
|
if "sdl3" in self.ctx.recipe_build_order:
|
|
sdl3_mixer_recipe = self.get_recipe("sdl3_mixer", self.ctx)
|
|
sdl3_image_recipe = self.get_recipe("sdl3_image", self.ctx)
|
|
sdl3_ttf_recipe = self.get_recipe("sdl3_ttf", self.ctx)
|
|
sdl3_recipe = self.get_recipe("sdl3", self.ctx)
|
|
env["USE_SDL3"] = "1"
|
|
env["KIVY_SPLIT_EXAMPLES"] = "1"
|
|
env["KIVY_SDL3_PATH"] = ":".join(
|
|
[
|
|
*sdl3_mixer_recipe.get_include_dirs(arch),
|
|
*sdl3_image_recipe.get_include_dirs(arch),
|
|
*sdl3_ttf_recipe.get_include_dirs(arch),
|
|
*sdl3_recipe.get_include_dirs(arch),
|
|
]
|
|
)
|
|
|
|
return env
|
|
|
|
|
|
recipe = KivyRecipe()
|