Merge branch 'master' into master

This commit is contained in:
Veselin Penev 2021-08-17 18:02:38 +02:00 committed by GitHub
commit f9b1acf4a0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 346 additions and 113 deletions

25
.deepsource.toml Normal file
View 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

View file

@ -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

View file

@ -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,15 +269,18 @@ 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 sensible:
self.debug('Run {0!r}'.format(command))
else:
if type(command) in (list, tuple):
self.debug('Run {0!r} ...'.format(command[0]))
if not quiet:
if not sensible:
self.debug('Run {0!r}'.format(command))
else:
self.debug('Run {0!r} ...'.format(command.split()[0]))
self.debug('Cwd {}'.format(kwargs.get('cwd')))
if isinstance(command, (list, tuple)):
self.debug('Run {0!r} ...'.format(command[0]))
else:
self.debug('Run {0!r} ...'.format(command.split()[0]))
self.debug('Cwd {}'.format(kwargs.get('cwd')))
# open the process
if sys.platform == 'win32':
@ -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('')

View file

@ -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]

View file

@ -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:

View file

@ -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),
cwd=self.buildozer.global_platform_dir,
show_output=True)
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,
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)

View file

@ -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...')

View file

@ -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))

View file

@ -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:

View file

@ -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

View file

@ -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.

View file

@ -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
)

View file

@ -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!

View file

@ -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
~~~~~~~~~~~~~~~~

View file

@ -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'

View file

@ -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

View file

@ -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",
)]

View file

@ -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])

View file

@ -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()