Merge branch 'master' into master
This commit is contained in:
commit
f9b1acf4a0
19 changed files with 346 additions and 113 deletions
25
.deepsource.toml
Normal file
25
.deepsource.toml
Normal file
|
@ -0,0 +1,25 @@
|
|||
version = 1
|
||||
|
||||
test_patterns = ["tests/**"]
|
||||
|
||||
[[analyzers]]
|
||||
name = "python"
|
||||
enabled = true
|
||||
|
||||
[analyzers.meta]
|
||||
runtime_version = "3.x.x"
|
||||
|
||||
|
||||
[[analyzers]]
|
||||
name = "docker"
|
||||
enabled = true
|
||||
|
||||
[analyzers.meta]
|
||||
dockerfile_paths = [
|
||||
"dockerfile_dev",
|
||||
"dockerfile_prod"
|
||||
]
|
||||
|
||||
[[analyzers]]
|
||||
name = "ruby"
|
||||
enabled = true
|
|
@ -15,7 +15,7 @@ your application requirements and settings such as title, icon, included modules
|
|||
etc. Buildozer will use that spec to create a package for Android, iOS, Windows,
|
||||
OSX and/or Linux.
|
||||
|
||||
Buildozer currently supports packaging for Android via the [python-for-android](http://github.com/kivy/python-for-android/)
|
||||
Buildozer currently supports packaging for Android via the [python-for-android](https://github.com/kivy/python-for-android/)
|
||||
project, and for iOS via the kivy-ios project. iOS and OSX are still under work.
|
||||
|
||||
For Android, buildozer will automatically download and prepare the
|
||||
|
@ -24,7 +24,7 @@ build dependencies. For more information, see
|
|||
Note that only Python 3 is supported.
|
||||
|
||||
Note that this tool has nothing to do with the eponymous online build service
|
||||
[buildozer.io](http://buildozer.io).
|
||||
[buildozer.io](https://buildozer.io).
|
||||
|
||||
## Installing Buildozer with target Python 3 (default):
|
||||
|
||||
|
@ -176,7 +176,7 @@ For [debugging on Android](https://python-for-android.readthedocs.io/en/stable/t
|
|||
## Contributing
|
||||
|
||||
We love pull requests and discussing novel ideas. Check out our
|
||||
[contribution guide](http://kivy.org/docs/contribute.html) and
|
||||
[contribution guide](https://kivy.org/docs/contribute.html) and
|
||||
feel free to improve buildozer.
|
||||
|
||||
The following mailing list and IRC channel are used exclusively for
|
||||
|
|
|
@ -19,7 +19,7 @@ from buildozer.jsonstore import JsonStore
|
|||
from sys import stdout, stderr, exit
|
||||
from re import search
|
||||
from os.path import join, exists, dirname, realpath, splitext, expanduser
|
||||
from subprocess import Popen, PIPE
|
||||
from subprocess import Popen, PIPE, TimeoutExpired
|
||||
from os import environ, unlink, walk, sep, listdir, makedirs
|
||||
from copy import copy
|
||||
from shutil import copyfile, rmtree, copytree, move
|
||||
|
@ -253,7 +253,7 @@ class Buildozer:
|
|||
|
||||
def cmd(self, command, **kwargs):
|
||||
# prepare the environ, based on the system + our own env
|
||||
env = copy(environ)
|
||||
env = environ.copy()
|
||||
env.update(self.environ)
|
||||
|
||||
# prepare the process
|
||||
|
@ -269,11 +269,14 @@ class Buildozer:
|
|||
get_stderr = kwargs.pop('get_stderr', False)
|
||||
break_on_error = kwargs.pop('break_on_error', True)
|
||||
sensible = kwargs.pop('sensible', False)
|
||||
run_condition = kwargs.pop('run_condition', None)
|
||||
quiet = kwargs.pop('quiet', False)
|
||||
|
||||
if not quiet:
|
||||
if not sensible:
|
||||
self.debug('Run {0!r}'.format(command))
|
||||
else:
|
||||
if type(command) in (list, tuple):
|
||||
if isinstance(command, (list, tuple)):
|
||||
self.debug('Run {0!r} ...'.format(command[0]))
|
||||
else:
|
||||
self.debug('Run {0!r} ...'.format(command.split()[0]))
|
||||
|
@ -297,9 +300,9 @@ class Buildozer:
|
|||
|
||||
ret_stdout = [] if get_stdout else None
|
||||
ret_stderr = [] if get_stderr else None
|
||||
while True:
|
||||
while not run_condition or run_condition():
|
||||
try:
|
||||
readx = select.select([fd_stdout, fd_stderr], [], [])[0]
|
||||
readx = select.select([fd_stdout, fd_stderr], [], [], 1)[0]
|
||||
except select.error:
|
||||
break
|
||||
if fd_stdout in readx:
|
||||
|
@ -322,7 +325,13 @@ class Buildozer:
|
|||
stdout.flush()
|
||||
stderr.flush()
|
||||
|
||||
process.communicate()
|
||||
try:
|
||||
process.communicate(
|
||||
timeout=(1 if run_condition and not run_condition() else None)
|
||||
)
|
||||
except TimeoutExpired:
|
||||
pass
|
||||
|
||||
if process.returncode != 0 and break_on_error:
|
||||
self.error('Command failed: {0}'.format(command))
|
||||
self.log_env(self.ERROR, kwargs['env'])
|
||||
|
@ -337,10 +346,12 @@ class Buildozer:
|
|||
self.error('raising an issue with buildozer itself.')
|
||||
self.error('In case of a bug report, please add a full log with log_level = 2')
|
||||
raise BuildozerCommandException()
|
||||
|
||||
if ret_stdout:
|
||||
ret_stdout = b''.join(ret_stdout)
|
||||
if ret_stderr:
|
||||
ret_stderr = b''.join(ret_stderr)
|
||||
|
||||
return (ret_stdout.decode('utf-8', 'ignore') if ret_stdout else None,
|
||||
ret_stderr.decode('utf-8') if ret_stderr else None,
|
||||
process.returncode)
|
||||
|
@ -349,7 +360,7 @@ class Buildozer:
|
|||
from pexpect import spawnu
|
||||
|
||||
# prepare the environ, based on the system + our own env
|
||||
env = copy(environ)
|
||||
env = environ.copy()
|
||||
env.update(self.environ)
|
||||
|
||||
# prepare the process
|
||||
|
@ -924,8 +935,7 @@ class Buildozer:
|
|||
|
||||
if not meth.__doc__:
|
||||
continue
|
||||
doc = [x for x in
|
||||
meth.__doc__.strip().splitlines()][0].strip()
|
||||
doc = list(meth.__doc__.strip().splitlines())[0].strip()
|
||||
print(' {0:<18} {1}'.format(name, doc))
|
||||
|
||||
print('')
|
||||
|
|
|
@ -87,6 +87,10 @@ fullscreen = 0
|
|||
# Lottie files can be created using various tools, like Adobe After Effect or Synfig.
|
||||
#android.presplash_lottie = "path/to/lottie/file.json"
|
||||
|
||||
# (str) Adaptive icon of the application (used if Android API level is 26+ at runtime)
|
||||
#icon.adaptive_foreground.filename = %(source.dir)s/data/icon_fg.png
|
||||
#icon.adaptive_background.filename = %(source.dir)s/data/icon_bg.png
|
||||
|
||||
# (list) Permissions
|
||||
#android.permissions = INTERNET
|
||||
|
||||
|
@ -178,6 +182,11 @@ fullscreen = 0
|
|||
# (list) Gradle dependencies to add
|
||||
#android.gradle_dependencies =
|
||||
|
||||
# (bool) Enable AndroidX support. Enable when 'android.gradle_dependencies'
|
||||
# contains an 'androidx' package, or any package from Kotlin source.
|
||||
# android.enable_androidx requires android.api >= 28
|
||||
#android.enable_androidx = False
|
||||
|
||||
# (list) add java compile options
|
||||
# this can for example be necessary when importing certain java libraries using the 'android.gradle_dependencies' option
|
||||
# see https://developer.android.com/studio/write/java8-support for further information
|
||||
|
@ -235,6 +244,9 @@ fullscreen = 0
|
|||
# (str) Android logcat filters to use
|
||||
#android.logcat_filters = *:S python:D
|
||||
|
||||
# (bool) Android logcat only display log for activity's pid
|
||||
#android.logcat_pid_only = False
|
||||
|
||||
# (str) Android additional adb arguments
|
||||
#android.adb_args = -H host.docker.internal
|
||||
|
||||
|
@ -260,16 +272,25 @@ android.allow_backup = True
|
|||
# Usage example : android.manifest_placeholders = [myCustomUrl:\"org.kivy.customurl\"]
|
||||
# android.manifest_placeholders = [:]
|
||||
|
||||
# (bool) disables the compilation of py to pyc/pyo files when packaging
|
||||
# android.no-compile-pyo = True
|
||||
|
||||
#
|
||||
# Python for android (p4a) specific
|
||||
#
|
||||
|
||||
# (str) python-for-android fork to use, defaults to upstream (kivy)
|
||||
# (str) python-for-android URL to use for checkout
|
||||
#p4a.url =
|
||||
|
||||
# (str) python-for-android fork to use in case if p4a.url is not specified, defaults to upstream (kivy)
|
||||
#p4a.fork = kivy
|
||||
|
||||
# (str) python-for-android branch to use, defaults to master
|
||||
#p4a.branch = master
|
||||
|
||||
# (str) python-for-android specific commit to use, defaults to HEAD, must be within p4a.branch
|
||||
#p4a.commit = HEAD
|
||||
|
||||
# (str) python-for-android git clone directory (if empty, it will be automatically cloned from github)
|
||||
#p4a.source_dir =
|
||||
|
||||
|
@ -317,9 +338,27 @@ ios.codesign.allowed = false
|
|||
# Get a list of available identities: buildozer ios list_identities
|
||||
#ios.codesign.debug = "iPhone Developer: <lastname> <firstname> (<hexstring>)"
|
||||
|
||||
# (str) The development team to use for signing the debug version
|
||||
#ios.codesign.development_team.debug = <hexstring>
|
||||
|
||||
# (str) Name of the certificate to use for signing the release version
|
||||
#ios.codesign.release = %(ios.codesign.debug)s
|
||||
|
||||
# (str) The development team to use for signing the release version
|
||||
#ios.codesign.development_team.release = <hexstring>
|
||||
|
||||
# (str) URL pointing to .ipa file to be installed
|
||||
# This option should be defined along with `display_image_url` and `full_size_image_url` options.
|
||||
#ios.manifest.app_url =
|
||||
|
||||
# (str) URL pointing to an icon (57x57px) to be displayed during download
|
||||
# This option should be defined along with `app_url` and `full_size_image_url` options.
|
||||
#ios.manifest.display_image_url =
|
||||
|
||||
# (str) URL pointing to a large icon (512x512px) to be used by iTunes
|
||||
# This option should be defined along with `app_url` and `display_image_url` options.
|
||||
#ios.manifest.full_size_image_url =
|
||||
|
||||
|
||||
[buildozer]
|
||||
|
||||
|
|
|
@ -234,7 +234,7 @@ class Target:
|
|||
|
||||
This will clone the contents of a git repository to
|
||||
`buildozer.platform_dir`. The location of this repo can be
|
||||
speficied via URL and branch name, or via a custom (local)
|
||||
specified via URL and branch name, or via a custom (local)
|
||||
directory name.
|
||||
|
||||
:Parameters:
|
||||
|
|
|
@ -33,6 +33,7 @@ from os.path import exists, join, realpath, expanduser, basename, relpath
|
|||
from platform import architecture
|
||||
from shutil import copyfile, rmtree
|
||||
from glob import glob
|
||||
from time import sleep
|
||||
|
||||
from buildozer.libs.version import parse
|
||||
from distutils.version import LooseVersion
|
||||
|
@ -60,6 +61,7 @@ class TargetAndroid(Target):
|
|||
p4a_directory_name = "python-for-android"
|
||||
p4a_fork = 'kivy'
|
||||
p4a_branch = 'master'
|
||||
p4a_commit = 'HEAD'
|
||||
p4a_apk_cmd = "apk --debug --bootstrap="
|
||||
p4a_recommended_ndk_version = None
|
||||
extra_p4a_args = ''
|
||||
|
@ -98,11 +100,15 @@ class TargetAndroid(Target):
|
|||
else:
|
||||
self.extra_p4a_args += ' --ignore-setup-py'
|
||||
|
||||
|
||||
activity_class_name = self.buildozer.config.getdefault(
|
||||
'app', 'android.activity_class_name', 'org.kivy.android.PythonActivity')
|
||||
if activity_class_name != 'org.kivy.android.PythonActivity':
|
||||
self.extra_p4a_args += ' --activity-class-name={}'.format(activity_class_name)
|
||||
|
||||
if self.buildozer.log_level >= 2:
|
||||
self.extra_p4a_args += ' --debug'
|
||||
|
||||
self.warn_on_deprecated_tokens()
|
||||
|
||||
def warn_on_deprecated_tokens(self):
|
||||
|
@ -124,7 +130,7 @@ class TargetAndroid(Target):
|
|||
# Default p4a dir
|
||||
p4a_dir = join(self.buildozer.platform_dir, self.p4a_directory_name)
|
||||
|
||||
# Possibly overriden by user setting
|
||||
# Possibly overridden by user setting
|
||||
system_p4a_dir = self.buildozer.config.getdefault('app', 'p4a.source_dir')
|
||||
if system_p4a_dir:
|
||||
p4a_dir = expanduser(system_p4a_dir)
|
||||
|
@ -248,10 +254,7 @@ class TargetAndroid(Target):
|
|||
'adb.exe')
|
||||
self.javac_cmd = self._locate_java('javac.exe')
|
||||
self.keytool_cmd = self._locate_java('keytool.exe')
|
||||
elif platform in ('darwin', ):
|
||||
self.adb_cmd = join(self.android_sdk_dir, 'platform-tools', 'adb')
|
||||
self.javac_cmd = self._locate_java('javac')
|
||||
self.keytool_cmd = self._locate_java('keytool')
|
||||
# darwin, linux
|
||||
else:
|
||||
self.adb_cmd = join(self.android_sdk_dir, 'platform-tools', 'adb')
|
||||
self.javac_cmd = self._locate_java('javac')
|
||||
|
@ -375,7 +378,7 @@ class TargetAndroid(Target):
|
|||
|
||||
self.buildozer.info('Android ANT is missing, downloading')
|
||||
archive = 'apache-ant-{0}-bin.tar.gz'.format(APACHE_ANT_VERSION)
|
||||
url = 'http://archive.apache.org/dist/ant/binaries/'
|
||||
url = 'https://archive.apache.org/dist/ant/binaries/'
|
||||
self.buildozer.download(url,
|
||||
archive,
|
||||
cwd=ant_dir)
|
||||
|
@ -423,7 +426,7 @@ class TargetAndroid(Target):
|
|||
return ndk_dir
|
||||
|
||||
import re
|
||||
_version = re.search('(.+?)[a-z]', self.android_ndk_version).group(1)
|
||||
_version = int(re.search(r'(\d+)', self.android_ndk_version).group(1))
|
||||
|
||||
self.buildozer.info('Android NDK is missing, downloading')
|
||||
# Welcome to the NDK URL hell!
|
||||
|
@ -433,28 +436,23 @@ class TargetAndroid(Target):
|
|||
# from 10e on the URLs can be looked up at
|
||||
# https://developer.android.com/ndk/downloads/older_releases
|
||||
|
||||
is_darwin = platform == 'darwin'
|
||||
is_linux = platform.startswith('linux')
|
||||
|
||||
if platform in ('win32', 'cygwin'):
|
||||
# Checking of 32/64 bits at Windows from: http://stackoverflow.com/a/1405971/798575
|
||||
# Checking of 32/64 bits at Windows from: https://stackoverflow.com/a/1405971/798575
|
||||
import struct
|
||||
archive = 'android-ndk-r{0}-windows-{1}.zip'
|
||||
is_64 = (8 * struct.calcsize("P") == 64)
|
||||
|
||||
elif platform in ('darwin', ):
|
||||
if _version >= '10e':
|
||||
archive = 'android-ndk-r{0}-darwin-{1}.zip'
|
||||
elif _version >= '10c':
|
||||
archive = 'android-ndk-r{0}-darwin-{1}.bin'
|
||||
elif is_darwin or is_linux:
|
||||
_platform = 'linux' if is_linux else 'darwin'
|
||||
if self.android_ndk_version in ['10c', '10d', '10e']:
|
||||
ext = 'bin'
|
||||
elif _version <= 10:
|
||||
ext = 'tar.bz2'
|
||||
else:
|
||||
archive = 'android-ndk-r{0}-darwin-{1}.tar.bz2'
|
||||
is_64 = (os.uname()[4] == 'x86_64')
|
||||
|
||||
elif platform.startswith('linux'):
|
||||
if _version >= '10e':
|
||||
archive = 'android-ndk-r{0}-linux-{1}.zip'
|
||||
elif _version >= '10c':
|
||||
archive = 'android-ndk-r{0}-linux-{1}.bin'
|
||||
else:
|
||||
archive = 'android-ndk-r{0}-linux-{1}.tar.bz2'
|
||||
ext = 'zip'
|
||||
archive = 'android-ndk-r{0}-' + _platform + '-{1}.' + ext
|
||||
is_64 = (os.uname()[4] == 'x86_64')
|
||||
else:
|
||||
raise SystemError('Unsupported platform: {}'.format(platform))
|
||||
|
@ -464,10 +462,10 @@ class TargetAndroid(Target):
|
|||
archive = archive.format(self.android_ndk_version, architecture)
|
||||
unpacked = unpacked.format(self.android_ndk_version)
|
||||
|
||||
if _version >= '10e':
|
||||
if _version >= 11:
|
||||
url = 'https://dl.google.com/android/repository/'
|
||||
else:
|
||||
url = 'http://dl.google.com/android/ndk/'
|
||||
url = 'https://dl.google.com/android/ndk/'
|
||||
|
||||
self.buildozer.download(url,
|
||||
archive,
|
||||
|
@ -666,7 +664,7 @@ class TargetAndroid(Target):
|
|||
self.buildozer.error(
|
||||
'You might have missed to install 32bits libs')
|
||||
self.buildozer.error(
|
||||
'Check http://buildozer.readthedocs.org/en/latest/installation.html')
|
||||
'Check https://buildozer.readthedocs.org/en/latest/installation.html')
|
||||
self.buildozer.error('')
|
||||
else:
|
||||
self.buildozer.error('')
|
||||
|
@ -699,9 +697,15 @@ class TargetAndroid(Target):
|
|||
p4a_fork = self.buildozer.config.getdefault(
|
||||
'app', 'p4a.fork', self.p4a_fork
|
||||
)
|
||||
p4a_url = self.buildozer.config.getdefault(
|
||||
'app', 'p4a.url', f'https://github.com/{p4a_fork}/python-for-android.git'
|
||||
)
|
||||
p4a_branch = self.buildozer.config.getdefault(
|
||||
'app', 'p4a.branch', self.p4a_branch
|
||||
)
|
||||
p4a_commit = self.buildozer.config.getdefault(
|
||||
'app', 'p4a.commit', self.p4a_commit
|
||||
)
|
||||
|
||||
p4a_dir = self.p4a_dir
|
||||
system_p4a_dir = self.buildozer.config.getdefault('app',
|
||||
|
@ -714,21 +718,19 @@ class TargetAndroid(Target):
|
|||
self.buildozer.error('')
|
||||
raise BuildozerException()
|
||||
else:
|
||||
# check that fork/branch has not been changed
|
||||
# check that url/branch has not been changed
|
||||
if self.buildozer.file_exists(p4a_dir):
|
||||
cur_fork = cmd(
|
||||
cur_url = cmd(
|
||||
'git config --get remote.origin.url',
|
||||
get_stdout=True,
|
||||
cwd=p4a_dir,
|
||||
)[0].split('/')[3]
|
||||
)[0].strip()
|
||||
cur_branch = cmd(
|
||||
'git branch -vv', get_stdout=True, cwd=p4a_dir
|
||||
)[0].split()[1]
|
||||
if any([cur_fork != p4a_fork, cur_branch != p4a_branch]):
|
||||
if any([cur_url != p4a_url, cur_branch != p4a_branch]):
|
||||
self.buildozer.info(
|
||||
"Detected old fork/branch ({}/{}), deleting...".format(
|
||||
cur_fork, cur_branch
|
||||
)
|
||||
f"Detected old url/branch ({cur_url}/{cur_branch}), deleting..."
|
||||
)
|
||||
rmtree(p4a_dir)
|
||||
|
||||
|
@ -736,11 +738,10 @@ class TargetAndroid(Target):
|
|||
cmd(
|
||||
(
|
||||
'git clone -b {p4a_branch} --single-branch '
|
||||
'https://github.com/{p4a_fork}/python-for-android.git '
|
||||
'{p4a_dir}'
|
||||
'{p4a_url} {p4a_dir}'
|
||||
).format(
|
||||
p4a_branch=p4a_branch,
|
||||
p4a_fork=p4a_fork,
|
||||
p4a_url=p4a_url,
|
||||
p4a_dir=self.p4a_directory_name,
|
||||
),
|
||||
cwd=self.buildozer.platform_dir,
|
||||
|
@ -755,6 +756,8 @@ class TargetAndroid(Target):
|
|||
cmd('git fetch --tags origin {0}:{0}'.format(p4a_branch),
|
||||
cwd=p4a_dir)
|
||||
cmd('git checkout {}'.format(p4a_branch), cwd=p4a_dir)
|
||||
if p4a_commit != 'HEAD':
|
||||
cmd('git reset --hard {}'.format(p4a_commit), cwd=p4a_dir)
|
||||
|
||||
# also install dependencies (currently, only setup.py knows about it)
|
||||
# let's extract them.
|
||||
|
@ -766,7 +769,7 @@ class TargetAndroid(Target):
|
|||
except IOError:
|
||||
self.buildozer.error('Failed to read python-for-android setup.py at {}'.format(
|
||||
join(self.p4a_dir, 'setup.py')))
|
||||
exit(1)
|
||||
sys.exit(1)
|
||||
pip_deps = []
|
||||
for dep in deps:
|
||||
pip_deps.append("'{}'".format(dep))
|
||||
|
@ -939,6 +942,11 @@ class TargetAndroid(Target):
|
|||
cmd.append('--manifest-placeholders')
|
||||
cmd.append("{}".format(manifest_placeholders))
|
||||
|
||||
# support disabling of compilation
|
||||
compile_py = self.buildozer.config.getdefault('app', 'android.no-compile-pyo', None)
|
||||
if compile_py:
|
||||
cmd.append('--no-compile-pyo')
|
||||
|
||||
cmd.append('--arch')
|
||||
cmd.append(self._arch)
|
||||
|
||||
|
@ -988,6 +996,12 @@ class TargetAndroid(Target):
|
|||
cwd=self.buildozer.global_platform_dir)
|
||||
self.buildozer.environ.pop('ANDROID_SERIAL', None)
|
||||
|
||||
while True:
|
||||
if self._get_pid():
|
||||
break
|
||||
sleep(.1)
|
||||
self.buildozer.info('Waiting for application to start.')
|
||||
|
||||
self.buildozer.info('Application started.')
|
||||
|
||||
def cmd_p4a(self, *args):
|
||||
|
@ -1160,6 +1174,11 @@ class TargetAndroid(Target):
|
|||
icon = config.getdefault('app', 'icon.filename', '')
|
||||
if icon:
|
||||
build_cmd += [("--icon", join(self.buildozer.root_dir, icon))]
|
||||
icon_fg = config.getdefault('app', 'icon.adaptive_foreground.filename', '')
|
||||
icon_bg = config.getdefault('app', 'icon.adaptive_background.filename', '')
|
||||
if icon_fg and icon_bg:
|
||||
build_cmd += [("--icon-fg", join(self.buildozer.root_dir, icon_fg))]
|
||||
build_cmd += [("--icon-bg", join(self.buildozer.root_dir, icon_bg))]
|
||||
|
||||
# OUYA Console support
|
||||
ouya_category = config.getdefault('app', 'android.ouya.category',
|
||||
|
@ -1193,6 +1212,13 @@ class TargetAndroid(Target):
|
|||
if wakelock:
|
||||
build_cmd += [("--wakelock", )]
|
||||
|
||||
# AndroidX ?
|
||||
enable_androidx = config.getbooldefault('app',
|
||||
'android.enable_androidx',
|
||||
False)
|
||||
if enable_androidx:
|
||||
build_cmd += [("--enable-androidx", )]
|
||||
|
||||
# intent filters
|
||||
intent_filters = config.getdefault(
|
||||
'app', 'android.manifest.intent_filters', '')
|
||||
|
@ -1313,7 +1339,7 @@ class TargetAndroid(Target):
|
|||
self.buildozer.error(
|
||||
'Invalid library reference (path not found): {}'.format(
|
||||
cref))
|
||||
exit(1)
|
||||
sys.exit(1)
|
||||
# get a relative path from the project file
|
||||
ref = relpath(ref, realpath(expanduser(dist_dir)))
|
||||
# ensure the reference exists
|
||||
|
@ -1416,6 +1442,18 @@ class TargetAndroid(Target):
|
|||
|
||||
self.buildozer.info('Application pushed.')
|
||||
|
||||
def _get_pid(self):
|
||||
pid, *_ = self.buildozer.cmd(
|
||||
f'{self.adb_cmd} shell pidof {self._get_package()}',
|
||||
get_stdout=True,
|
||||
show_output=False,
|
||||
break_on_error=False,
|
||||
quiet=True,
|
||||
)
|
||||
if pid:
|
||||
return pid.strip()
|
||||
return False
|
||||
|
||||
def cmd_logcat(self, *args):
|
||||
'''Show the log from the device
|
||||
'''
|
||||
|
@ -1427,10 +1465,23 @@ class TargetAndroid(Target):
|
|||
"app", "android.logcat_filters", "", section_sep=":", split_char=" ")
|
||||
filters = " ".join(filters)
|
||||
self.buildozer.environ['ANDROID_SERIAL'] = serial[0]
|
||||
self.buildozer.cmd('{adb} logcat {filters}'.format(adb=self.adb_cmd,
|
||||
filters=filters),
|
||||
extra_args = []
|
||||
pid = None
|
||||
if self.buildozer.config.getdefault('app', 'android.logcat_pid_only'):
|
||||
pid = self._get_pid()
|
||||
if pid:
|
||||
extra_args.extend(('--pid', pid))
|
||||
|
||||
self.buildozer.cmd(
|
||||
f"{self.adb_cmd} logcat {filters} {' '.join(extra_args)}",
|
||||
cwd=self.buildozer.global_platform_dir,
|
||||
show_output=True)
|
||||
show_output=True,
|
||||
run_condition=self._get_pid if pid else None,
|
||||
break_on_error=False,
|
||||
)
|
||||
|
||||
self.buildozer.info(f"{self._get_package()} terminated")
|
||||
|
||||
self.buildozer.environ.pop('ANDROID_SERIAL', None)
|
||||
|
||||
|
||||
|
|
|
@ -115,8 +115,8 @@ class TargetIos(Target):
|
|||
kwargs.setdefault('cwd', self.ios_dir)
|
||||
return self.buildozer.cmd(self._toolchain_cmd + cmd, **kwargs)
|
||||
|
||||
def xcodebuild(self, cmd='', **kwargs):
|
||||
return self.buildozer.cmd(self._xcodebuild_cmd + cmd, **kwargs)
|
||||
def xcodebuild(self, *args, **kwargs):
|
||||
return self.buildozer.cmd(self._xcodebuild_cmd + ' '.join(arg for arg in args if arg is not None), **kwargs)
|
||||
|
||||
@property
|
||||
def code_signing_allowed(self):
|
||||
|
@ -124,6 +124,11 @@ class TargetIos(Target):
|
|||
allowed = "YES" if allowed else "NO"
|
||||
return f"CODE_SIGNING_ALLOWED={allowed}"
|
||||
|
||||
@property
|
||||
def code_signing_development_team(self):
|
||||
team = self.buildozer.config.getdefault("app", f"ios.codesign.development_team.{self.build_mode}", None)
|
||||
return f"DEVELOPMENT_TEAM={team}" if team else None
|
||||
|
||||
def get_available_packages(self):
|
||||
available_modules = self.toolchain("recipes --compact", get_stdout=True)[0]
|
||||
return available_modules.splitlines()[0].split()
|
||||
|
@ -202,7 +207,8 @@ class TargetIos(Target):
|
|||
plist_rfn = join(self.app_project_dir, plist_fn)
|
||||
version = self.buildozer.get_version()
|
||||
self.buildozer.info('Update Plist {}'.format(plist_fn))
|
||||
plist = plistlib.readPlist(plist_rfn)
|
||||
with open(plist_rfn, 'rb') as f:
|
||||
plist = plistlib.load(f)
|
||||
plist['CFBundleIdentifier'] = self._get_package()
|
||||
plist['CFBundleShortVersionString'] = version
|
||||
plist['CFBundleVersion'] = '{}.{}'.format(version,
|
||||
|
@ -211,12 +217,36 @@ class TargetIos(Target):
|
|||
# add icons
|
||||
self._create_icons()
|
||||
|
||||
# Generate OTA distribution manifest if `app_url`, `display_image_url` and `full_size_image_url` are defined.
|
||||
app_url = self.buildozer.config.getdefault("app", "ios.manifest.app_url", None)
|
||||
display_image_url = self.buildozer.config.getdefault("app", "ios.manifest.display_image_url", None)
|
||||
full_size_image_url = self.buildozer.config.getdefault("app", "ios.manifest.full_size_image_url", None)
|
||||
|
||||
if any((app_url, display_image_url, full_size_image_url)):
|
||||
|
||||
if not all((app_url, display_image_url, full_size_image_url)):
|
||||
self.buildozer.error("Options ios.manifest.app_url, ios.manifest.display_image_url"
|
||||
" and ios.manifest.full_size_image_url should be defined all together")
|
||||
return
|
||||
|
||||
plist['manifest'] = {
|
||||
'appURL': app_url,
|
||||
'displayImageURL': display_image_url,
|
||||
'fullSizeImageURL': full_size_image_url,
|
||||
}
|
||||
|
||||
# ok, write the modified plist.
|
||||
plistlib.writePlist(plist, plist_rfn)
|
||||
with open(plist_rfn, 'wb') as f:
|
||||
plistlib.dump(plist, f)
|
||||
|
||||
mode = self.build_mode.capitalize()
|
||||
self.xcodebuild(
|
||||
f"-configuration {mode} ENABLE_BITCODE=NO {self.code_signing_allowed} clean build",
|
||||
f'-configuration {mode}',
|
||||
'-allowProvisioningUpdates',
|
||||
'ENABLE_BITCODE=NO',
|
||||
self.code_signing_allowed,
|
||||
self.code_signing_development_team,
|
||||
'clean build',
|
||||
cwd=self.app_project_dir)
|
||||
ios_app_dir = '{app_lower}-ios/build/{mode}-iphoneos/{app_lower}.app'.format(
|
||||
app_lower=app_name.lower(), mode=mode)
|
||||
|
@ -242,25 +272,24 @@ class TargetIos(Target):
|
|||
self.buildozer.rmdir(intermediate_dir)
|
||||
|
||||
self.buildozer.info('Creating archive...')
|
||||
self.xcodebuild((
|
||||
' -alltargets'
|
||||
' -configuration {mode}'
|
||||
' -scheme {scheme}'
|
||||
' -archivePath "{xcarchive}"'
|
||||
' archive'
|
||||
' ENABLE_BITCODE=NO'
|
||||
).format(mode=mode, xcarchive=xcarchive, scheme=app_name.lower()),
|
||||
self.xcodebuild(
|
||||
'-alltargets',
|
||||
f'-configuration {mode}',
|
||||
f'-scheme {app_name.lower()}',
|
||||
f'-archivePath "{xcarchive}"',
|
||||
'archive',
|
||||
'ENABLE_BITCODE=NO',
|
||||
self.code_signing_development_team,
|
||||
cwd=build_dir)
|
||||
|
||||
self.buildozer.info('Creating IPA...')
|
||||
self.xcodebuild((
|
||||
' -exportArchive'
|
||||
' -exportFormat IPA'
|
||||
' -archivePath "{xcarchive}"'
|
||||
' -exportPath "{ipa}"'
|
||||
' CODE_SIGN_IDENTITY={ioscodesign}'
|
||||
' ENABLE_BITCODE=NO'
|
||||
).format(xcarchive=xcarchive, ipa=ipa_tmp, ioscodesign=ioscodesign),
|
||||
self.xcodebuild(
|
||||
'-exportArchive',
|
||||
f'-archivePath "{xcarchive}"',
|
||||
f'-exportOptionsPlist "{plist_rfn}"',
|
||||
f'-exportPath "{ipa_tmp}"',
|
||||
f'CODE_SIGN_IDENTITY={ioscodesign}',
|
||||
'ENABLE_BITCODE=NO',
|
||||
cwd=build_dir)
|
||||
|
||||
self.buildozer.info('Moving IPA to bin...')
|
||||
|
|
|
@ -46,16 +46,16 @@ class TargetOSX(Target):
|
|||
self.buildozer.info('Downloading kivy...')
|
||||
status_code = check_output(
|
||||
('curl', '-L', '--write-out', '%{http_code}', '-o', 'Kivy{}.dmg'.format(py_branch),
|
||||
'http://kivy.org/downloads/{}/Kivy-{}-osx-python{}.dmg'
|
||||
'https://kivy.org/downloads/{}/Kivy-{}-osx-python{}.dmg'
|
||||
.format(current_kivy_vers, current_kivy_vers, py_branch)),
|
||||
cwd=cwd)
|
||||
|
||||
if status_code == "404":
|
||||
self.buildozer.error(
|
||||
"Unable to download the Kivy App. Check osx.kivy_version in your buildozer.spec, and verify "
|
||||
"Kivy servers are accessible. http://kivy.org/downloads/")
|
||||
"Kivy servers are accessible. https://kivy.org/downloads/")
|
||||
check_call(("rm", "Kivy{}.dmg".format(py_branch)), cwd=cwd)
|
||||
exit(1)
|
||||
sys.exit(1)
|
||||
|
||||
self.buildozer.info('Extracting and installing Kivy...')
|
||||
check_call(('hdiutil', 'attach', cwd + '/Kivy{}.dmg'.format(py_branch)))
|
||||
|
@ -76,8 +76,6 @@ class TargetOSX(Target):
|
|||
else:
|
||||
self.download_kivy(kivy_app_dir, py_branch)
|
||||
|
||||
return
|
||||
|
||||
def check_requirements(self):
|
||||
self.ensure_sdk()
|
||||
self.ensure_kivyapp()
|
||||
|
@ -90,7 +88,7 @@ class TargetOSX(Target):
|
|||
len(errors)))
|
||||
for error in errors:
|
||||
print(error)
|
||||
exit(1)
|
||||
sys.exit(1)
|
||||
# check
|
||||
|
||||
def build_package(self):
|
||||
|
@ -177,7 +175,7 @@ class TargetOSX(Target):
|
|||
if not args:
|
||||
self.buildozer.error('Missing target command')
|
||||
self.buildozer.usage()
|
||||
exit(1)
|
||||
sys.exit(1)
|
||||
|
||||
result = []
|
||||
last_command = []
|
||||
|
@ -191,7 +189,7 @@ class TargetOSX(Target):
|
|||
if not last_command:
|
||||
self.buildozer.error('Argument passed without a command')
|
||||
self.buildozer.usage()
|
||||
exit(1)
|
||||
sys.exit(1)
|
||||
last_command.append(arg)
|
||||
if last_command:
|
||||
result.append(last_command)
|
||||
|
@ -202,7 +200,7 @@ class TargetOSX(Target):
|
|||
command, args = item[0], item[1:]
|
||||
if not hasattr(self, 'cmd_{0}'.format(command)):
|
||||
self.buildozer.error('Unknown command {0}'.format(command))
|
||||
exit(1)
|
||||
sys.exit(1)
|
||||
|
||||
func = getattr(self, 'cmd_{0}'.format(command))
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ torrent:
|
|||
mktorrent \
|
||||
-a ${TORRENT_ANNOUNCE} \
|
||||
-o output-kivy-buildozer-vm/kivy-buildozer-vm.torrent \
|
||||
-w http://txzone.net/files/torrents/${PACKAGE_FILENAME} \
|
||||
-w https://txzone.net/files/torrents/${PACKAGE_FILENAME} \
|
||||
-v output-kivy-buildozer-vm/${PACKAGE_FILENAME}
|
||||
|
||||
upload:
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
# an error when using the android sdk:
|
||||
# "Can't read cryptographic policy directory: unlimited"
|
||||
|
||||
wget http://bootstrap.pypa.io/get-pip.py
|
||||
wget https://bootstrap.pypa.io/get-pip.py
|
||||
python get-pip.py
|
||||
rm get-pip.py
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ BUILDDIR = build
|
|||
|
||||
# User-friendly check for sphinx-build
|
||||
ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
|
||||
$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
|
||||
$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from https://www.sphinx-doc.org/)
|
||||
endif
|
||||
|
||||
# Internal variables.
|
||||
|
|
|
@ -56,7 +56,7 @@ if errorlevel 9009 (
|
|||
echo.may add the Sphinx directory to PATH.
|
||||
echo.
|
||||
echo.If you don't have Sphinx installed, grab it from
|
||||
echo.http://sphinx-doc.org/
|
||||
echo.https://www.sphinx-doc.org/
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
|
|
|
@ -15,10 +15,10 @@ limitation.
|
|||
|
||||
To test your own recipe via Buildozer, you need to:
|
||||
|
||||
#. Fork `Python for Android <http://github.com/kivy/python-for-android>`_, and
|
||||
#. Fork `Python for Android <https://github.com/kivy/python-for-android>`_, and
|
||||
clone your own version (this will allow easy contribution later)::
|
||||
|
||||
git clone http://github.com/YOURNAME/python-for-android
|
||||
git clone https://github.com/YOURNAME/python-for-android
|
||||
|
||||
#. Change your `buildozer.spec` to reference your version::
|
||||
|
||||
|
@ -44,6 +44,6 @@ include it in the python-for-android project, by issuing a Pull Request:
|
|||
|
||||
git push origin master
|
||||
|
||||
#. Go to `http://github.com/YOURNAME/python-for-android`, and you should see
|
||||
#. Go to `https://github.com/YOURNAME/python-for-android`, and you should see
|
||||
your new branch and a button "Pull Request" on it. Use it, write a
|
||||
description about what you did, and Send!
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
|
||||
Installation
|
||||
============
|
||||
|
||||
|
@ -27,6 +28,48 @@ Android on Ubuntu 20.04 (64bit)
|
|||
# add the following line at the end of your ~/.bashrc file
|
||||
export PATH=$PATH:~/.local/bin/
|
||||
|
||||
Android on Windows 10
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
To use buildozer in Windows 10 you need first to enable Windows Subsystem for Linux (WSL) and install a Linux distribution: https://docs.microsoft.com/en-us/windows/wsl/install-win10.
|
||||
|
||||
These instructions were tested with WSL 1 and Ubuntu 18.04 LTS.
|
||||
|
||||
After installing WSL and Ubuntu in your Windows 10 machine, open Ubuntu and do this:
|
||||
|
||||
1) Run the commands listed on the previous section (Android in Ubuntu 18.04 (64-bit).
|
||||
2) Run the following commands:
|
||||
|
||||
::
|
||||
|
||||
# Use here the python version you need
|
||||
sudo apt install -y python3.7-venv
|
||||
# Create a folder for buildozer. For example: C:\buildozer
|
||||
mkdir /mnt/c/buildozer
|
||||
cd /mnt/c/buildozer
|
||||
python3.7 -m venv venv-buildozer
|
||||
source venv/bin/activate
|
||||
python -m pip install --upgrade pip
|
||||
python -m pip install --upgrade wheel
|
||||
python -m pip install --upgrade cython
|
||||
python -m pip install --upgrade virtualenv
|
||||
python -m pip install --upgrade buildozer
|
||||
# Restart your WSL terminal to enable the path change
|
||||
|
||||
Windows Subsystem for Linux does not have direct access to USB. Due to this, you need to install the Windows version of ADB (Android Debug Bridge):
|
||||
|
||||
- Go to https://developer.android.com/studio/releases/platform-tools and click on "Download SDK Platform-Tools for Windows".
|
||||
|
||||
- Unzip the downloaded file to a new folder. For example, "C:\\platform-tools".
|
||||
|
||||
Before Using Buildozer
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
If you wish, clone your code to a new folder, where the build process will run.
|
||||
|
||||
You don't need to create a virtualenv for your code requirements. But just add these requirements to a configuration file called buildozer.spec as you will see in the following sections.
|
||||
|
||||
Before running buildozer in your code folder, remember to go into the buildozer folder and activate the buildozer virtualenv.
|
||||
|
||||
Android on macOS
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
|
2
setup.py
2
setup.py
|
@ -57,7 +57,7 @@ setup(
|
|||
long_description_content_type='text/markdown',
|
||||
author='Mathieu Virbel',
|
||||
author_email='mat@kivy.org',
|
||||
url='http://github.com/kivy/buildozer',
|
||||
url='https://github.com/kivy/buildozer',
|
||||
license='MIT',
|
||||
packages=[
|
||||
'buildozer', 'buildozer.targets', 'buildozer.libs', 'buildozer.scripts'
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import os
|
||||
import tempfile
|
||||
from six import StringIO
|
||||
from unittest import mock
|
||||
|
||||
import pytest
|
||||
|
@ -350,3 +351,44 @@ class TestTargetAndroid:
|
|||
]
|
||||
)
|
||||
]
|
||||
|
||||
def test_install_platform_p4a_clone_url(self):
|
||||
"""The `p4a.url` config should be used for cloning p4a before the `p4a.fork` option."""
|
||||
target_android = init_target(self.temp_dir, {
|
||||
'p4a.url': 'https://custom-p4a-url/p4a.git',
|
||||
'p4a.fork': 'myfork',
|
||||
})
|
||||
|
||||
with patch_buildozer_cmd() as m_cmd, mock.patch('buildozer.targets.android.open') as m_open:
|
||||
m_open.return_value = StringIO('install_reqs = []') # to stub setup.py parsing
|
||||
target_android._install_p4a()
|
||||
|
||||
assert mock.call(
|
||||
'git clone -b master --single-branch https://custom-p4a-url/p4a.git python-for-android',
|
||||
cwd=mock.ANY) in m_cmd.call_args_list
|
||||
|
||||
def test_install_platform_p4a_clone_fork(self):
|
||||
"""The `p4a.fork` config should be used for cloning p4a."""
|
||||
target_android = init_target(self.temp_dir, {
|
||||
'p4a.fork': 'fork'
|
||||
})
|
||||
|
||||
with patch_buildozer_cmd() as m_cmd, mock.patch('buildozer.targets.android.open') as m_open:
|
||||
m_open.return_value = StringIO('install_reqs = []') # to stub setup.py parsing
|
||||
target_android._install_p4a()
|
||||
|
||||
assert mock.call(
|
||||
'git clone -b master --single-branch https://github.com/fork/python-for-android.git python-for-android',
|
||||
cwd=mock.ANY) in m_cmd.call_args_list
|
||||
|
||||
def test_install_platform_p4a_clone_default(self):
|
||||
"""The default URL should be used for cloning p4a if no config options `p4a.url` and `p4a.fork` are set."""
|
||||
target_android = init_target(self.temp_dir)
|
||||
|
||||
with patch_buildozer_cmd() as m_cmd, mock.patch('buildozer.targets.android.open') as m_open:
|
||||
m_open.return_value = StringIO('install_reqs = []') # to stub setup.py parsing
|
||||
target_android._install_p4a()
|
||||
|
||||
assert mock.call(
|
||||
'git clone -b master --single-branch https://github.com/kivy/python-for-android.git python-for-android',
|
||||
cwd=mock.ANY) in m_cmd.call_args_list
|
||||
|
|
|
@ -182,7 +182,6 @@ class TestTargetIos:
|
|||
# fmt: off
|
||||
with patch_target_ios("_unlock_keychain") as m_unlock_keychain, \
|
||||
patch_buildozer_error() as m_error, \
|
||||
patch_target_ios("xcodebuild") as m_xcodebuild, \
|
||||
mock.patch("buildozer.targets.ios.plistlib.readPlist") as m_readplist, \
|
||||
mock.patch("buildozer.targets.ios.plistlib.writePlist") as m_writeplist, \
|
||||
patch_buildozer_cmd() as m_cmd:
|
||||
|
@ -196,13 +195,6 @@ class TestTargetIos:
|
|||
'You must fill the "ios.codesign.debug" token.'
|
||||
)
|
||||
]
|
||||
assert m_xcodebuild.call_args_list == [
|
||||
mock.call(
|
||||
"-configuration Debug ENABLE_BITCODE=NO "
|
||||
"CODE_SIGNING_ALLOWED=NO clean build",
|
||||
cwd="/ios/dir/myapp-ios",
|
||||
)
|
||||
]
|
||||
assert m_readplist.call_args_list == [
|
||||
mock.call("/ios/dir/myapp-ios/myapp-Info.plist")
|
||||
]
|
||||
|
@ -216,4 +208,8 @@ class TestTargetIos:
|
|||
"/ios/dir/myapp-ios/myapp-Info.plist",
|
||||
)
|
||||
]
|
||||
assert m_cmd.call_args_list == [mock.call(mock.ANY, cwd=target.ios_dir)]
|
||||
assert m_cmd.call_args_list == [mock.call(mock.ANY, cwd=target.ios_dir), mock.call(
|
||||
"xcodebuild -configuration Debug -allowProvisioningUpdates ENABLE_BITCODE=NO "
|
||||
"CODE_SIGNING_ALLOWED=NO clean build",
|
||||
cwd="/ios/dir/myapp-ios",
|
||||
)]
|
||||
|
|
|
@ -53,7 +53,7 @@ def init_buildozer(temp_dir, target, options=None):
|
|||
spec = []
|
||||
for line in default_spec:
|
||||
if line.strip():
|
||||
match = re.search(r"[#\s]?([a-z_\.]+)", line)
|
||||
match = re.search(r"[#\s]?([0-9a-z_.]+)", line)
|
||||
key = match and match.group(1)
|
||||
if key in options:
|
||||
line = "{} = {}\n".format(key, options[key])
|
||||
|
|
|
@ -61,7 +61,7 @@ class TestBuildozer(unittest.TestCase):
|
|||
|
||||
def test_buildozer_base(self):
|
||||
"""
|
||||
Basic test making sure the Buildozer object can be instanciated.
|
||||
Basic test making sure the Buildozer object can be instantiated.
|
||||
"""
|
||||
buildozer = Buildozer()
|
||||
assert buildozer.specfilename == 'buildozer.spec'
|
||||
|
@ -158,7 +158,7 @@ class TestBuildozer(unittest.TestCase):
|
|||
assert m_file_extract.call_args_list == [mock.call(mock.ANY, cwd='/my/ant/path')]
|
||||
assert ant_path == my_ant_path
|
||||
assert download.call_args_list == [
|
||||
mock.call("http://archive.apache.org/dist/ant/binaries/", mock.ANY, cwd=my_ant_path)]
|
||||
mock.call("https://archive.apache.org/dist/ant/binaries/", mock.ANY, cwd=my_ant_path)]
|
||||
# Mock ant already installed
|
||||
with mock.patch.object(Buildozer, 'file_exists', return_value=True):
|
||||
ant_path = target._install_apache_ant()
|
||||
|
|
Loading…
Reference in a new issue