From 4936d31828cc64b06af197d0057c0272ce1a09f6 Mon Sep 17 00:00:00 2001 From: Alexander Taylor Date: Fri, 1 Feb 2019 13:04:06 +0000 Subject: [PATCH] Removed android_old target and began update to sdk install --- buildozer/__init__.py | 22 +- buildozer/targets/android.py | 454 ++++++++++++++++++------------- buildozer/targets/android_new.py | 217 --------------- 3 files changed, 270 insertions(+), 423 deletions(-) delete mode 100644 buildozer/targets/android_new.py diff --git a/buildozer/__init__.py b/buildozer/__init__.py index e80bd5ade..2048a1528 100644 --- a/buildozer/__init__.py +++ b/buildozer/__init__.py @@ -155,7 +155,6 @@ def __init__(self, filename='buildozer.spec', target=None): def set_target(self, target): '''Set the target to use (one of buildozer.targets, such as "android") ''' - target = self.translate_target(target) self.targetname = target m = __import__('buildozer.targets.{0}'.format(target), fromlist=['buildozer']) @@ -919,23 +918,6 @@ def package_full_name(self): # command line invocation # - def translate_target(self, target, inverse=False): - # FIXME at some point, refactor to remove completely android old toolchain - if inverse: - if target == "android": - target = "android_old" - elif target == "android_new": - target = "android" - else: - if target == "android": - target = "android_new" - elif target == "android_new": - self.error("ERROR: The target android_new is now android") - exit(1) - elif target == "android_old": - target = "android" - return target - def targets(self): for fn in listdir(join(dirname(__file__), 'targets')): if fn.startswith('.') or fn.startswith('__'): @@ -946,7 +928,7 @@ def targets(self): try: m = __import__('buildozer.targets.{0}'.format(target), fromlist=['buildozer']) - yield self.translate_target(target, inverse=True), m + yield target, m except NotImplementedError: pass except: @@ -1054,7 +1036,7 @@ def run_command(self, args): # maybe it's a target? targets = [x[0] for x in self.targets()] - if self.translate_target(command, inverse=True) not in targets: + if command not in targets: print('Unknown command/target {}'.format(self.translate_target(command, inverse=True))) exit(1) diff --git a/buildozer/targets/android.py b/buildozer/targets/android.py index f5c8b31f5..dd9782fb9 100644 --- a/buildozer/targets/android.py +++ b/buildozer/targets/android.py @@ -28,8 +28,7 @@ import sh from pipes import quote from sys import platform, executable -from buildozer import BuildozerException -from buildozer import IS_PY3 +from buildozer import BuildozerException, USE_COLOR, IS_PY3 from buildozer.target import Target from os import environ from os.path import exists, join, realpath, expanduser, basename, relpath @@ -42,10 +41,55 @@ class TargetAndroid(Target): - targetname = 'android_old' + targetname = 'android' p4a_directory = "python-for-android" - p4a_branch = 'old_toolchain' - p4a_apk_cmd = "python build.py" + p4a_branch = 'master' + p4a_apk_cmd = "apk --debug --bootstrap=" + extra_p4a_args = '' + + def __init__(self, *args, **kwargs): + super(TargetAndroid, self).__init__(*args, **kwargs) + self._build_dir = join(self.buildozer.platform_dir, 'build') + executable = sys.executable or 'python' + self._p4a_cmd = '{} -m pythonforandroid.toolchain '.format(executable) + self._p4a_bootstrap = self.buildozer.config.getdefault( + 'app', 'p4a.bootstrap', 'sdl2') + self.p4a_apk_cmd += self._p4a_bootstrap + color = 'always' if USE_COLOR else 'never' + self.extra_p4a_args = ' --color={} --storage-dir="{}"'.format( + color, self._build_dir) + + # minapi should match ndk-api, so can use the same default if + # nothing is specified + ndk_api = self.buildozer.config.getdefault( + 'app', 'android.ndk_api', self.android_minapi) + self.extra_p4a_args += ' --ndk-api={}'.format(ndk_api) + + hook = self.buildozer.config.getdefault("app", "p4a.hook", None) + if hook is not None: + self.extra_p4a_args += ' --hook={}'.format(realpath(hook)) + port = self.buildozer.config.getdefault('app', 'p4a.port', None) + if port is not None: + self.extra_p4a_args += ' --port={}'.format(port) + + def _p4a(self, cmd, **kwargs): + if not hasattr(self, "pa_dir"): + self.pa_dir = join(self.buildozer.platform_dir, self.p4a_directory) + kwargs.setdefault('cwd', self.pa_dir) + return self.buildozer.cmd(self._p4a_cmd + cmd + self.extra_p4a_args, **kwargs) + + def _sdkmanager(self, *args): + """Call the sdkmanager in our Android SDK with the given arguments.""" + sdkmanager_path = os.path.join(self.buildozer.global_platform_dir, + 'android-sdk', + 'tools', + 'bin', + 'sdkmanager') + assert os.path.isfile(sdkmanager_path) + + return self.buildozer.cmd(sdkmanager_path + ' ' + ' '.join(args), + get_stdout=True) + @property def android_sdk_version(self): @@ -73,10 +117,8 @@ def android_sdk_dir(self): 'app', 'android.sdk_path', '')) if directory: return realpath(directory) - version = self.buildozer.config.getdefault('app', 'android.sdk', - self.android_sdk_version) return join(self.buildozer.global_platform_dir, - 'android-sdk-{0}'.format(version)) + 'android-sdk') @property def android_ndk_dir(self): @@ -248,30 +290,31 @@ def _install_android_sdk(self): self.buildozer.info('Android SDK is missing, downloading') if platform in ('win32', 'cygwin'): - archive = 'android-sdk_r{0}-windows.zip' + archive = 'sdk-tools-windows-4333796.zip' unpacked = 'android-sdk-windows' elif platform in ('darwin', ): - archive = 'android-sdk_r{0}-macosx.zip' + archive = 'sdk-tools-darwin-4333796.zip' unpacked = 'android-sdk-macosx' elif platform.startswith('linux'): - archive = 'android-sdk_r{0}-linux.tgz' + archive = 'sdk-tools-linux-4333796.zip' unpacked = 'android-sdk-linux' else: raise SystemError('Unsupported platform: {0}'.format(platform)) + if not os.path.exists(sdk_dir): + os.makedirs(sdk_dir) + archive = archive.format(self.android_sdk_version) - url = 'http://dl.google.com/android/' + url = 'http://dl.google.com/android/repository/' self.buildozer.download(url, archive, - cwd=self.buildozer.global_platform_dir) + cwd=sdk_dir) self.buildozer.info('Unpacking Android SDK') self.buildozer.file_extract(archive, - cwd=self.buildozer.global_platform_dir) - self.buildozer.file_rename(unpacked, - sdk_dir, - cwd=self.buildozer.global_platform_dir) - self.buildozer.info('Android SDK installation done.') + cwd=sdk_dir) + + self.buildozer.info('Android SDK tools base installation done.') return sdk_dir @@ -341,21 +384,24 @@ def _install_android_ndk(self): self.buildozer.info('Android NDK installation done.') return ndk_dir - def _android_list_sdk(self, include_all=False): - cmd = '{} list sdk -u -e'.format(self.android_cmd) - if include_all: - cmd += ' -a' - available_packages = self.buildozer.cmd( - cmd, - cwd=self.buildozer.global_platform_dir, - get_stdout=True)[0] + def _android_list_build_tools_versions(self): + available_packages = self._sdkmanager('--list') + + lines = available_packages[0].split('\n') - # get only the line like -> id: 5 or "build-tools-19.0.1" - # and extract the name part. - print(available_packages) - return [x.split('"')[1] - for x in available_packages.splitlines() - if x.startswith('id: ')] + build_tools_versions = [] + + for line in lines: + if not line.strip().startswith('build-tools;'): + continue + package_name = line.strip().split(' ')[0] + assert package_name.count(';') == 1, ( + 'could not parse package "{}"'.format(package_name)) + version = package_name.split(';')[1] + + build_tools_versions.append(parse(version)) + + return build_tools_versions def _android_update_sdk(self, packages): from pexpect import EOF @@ -376,9 +422,6 @@ def _android_update_sdk(self, packages): break child.sendline('y') - def _build_package_string(self, package_name, version): - return '{}-{}'.format(package_name, version) - def _read_version_subdir(self, *args): versions = [] if not os.path.exists(join(*args)): @@ -420,68 +463,38 @@ def _install_android_packages(self): if self.buildozer.state.get(cache_key, None) == cache_value: return True - # 3 pass installation. - if not os.access(self.android_cmd, os.X_OK): - self.buildozer.cmd('chmod ug+x {}'.format(self.android_cmd)) - # 1. update the tool and platform-tools if needed - packages = self._android_list_sdk() - skip_upd = self.buildozer.config.getdefault('app', - 'android.skip_update', False) - if 'tools' in packages or 'platform-tools' in packages: - if not skip_upd: - if WSL: - # WSL (Windows Subsystem for Linux) allows running - # linux from windows 10, but some windows - # limitations still apply, namely you can't rename a - # directory that a program was started from, which - # is what the tools updates cause, and we end up - # with an empty dir, so we need to run from a - # different place, and the updater is still looking - # for things in tools, and specifically renames the - # tool dir, hence, moving and making a symlink - # works. - sh.mv( - join(self.android_sdk_dir, 'tools'), - join(self.android_sdk_dir, 'tools.save') - ) - sh.ln( - '-s', - join(self.android_sdk_dir, 'tools.save'), - join(self.android_sdk_dir, 'tools') - ) - old_android_cmd = self.android_cmd - self.android_cmd = join( - self.android_sdk_dir, - 'tools.save', - self.android_cmd.split('/')[-1] - ) - - self._android_update_sdk('tools,platform-tools') - - if WSL: - self.android_cmd = old_android_cmd - sh.rm('-rf', join(self.android_sdk_dir, 'tools.save')) - else: - self.buildozer.info('Skipping Android SDK update due to spec file setting') + + skip_upd = self.buildozer.config.getdefault( + 'app', 'android.skip_update', False) + + if not skip_upd: + # just calling sdkmanager with the items will install them if necessary + self._sdkmanager('tools', 'platform-tools') + self._sdkmanager('--update') + else: + self.buildozer.info('Skipping Android SDK update due to spec file setting') + self.buildozer.info('Note: this also prevents installing missing ' + 'SDK components') # 2. install the latest build tool - v_build_tools = self._read_version_subdir(self.android_sdk_dir, + installed_v_build_tools = self._read_version_subdir(self.android_sdk_dir, 'build-tools') - packages = self._android_list_sdk(include_all=True) - ver = self._find_latest_package(packages, 'build-tools-') - if ver and ver > v_build_tools and not skip_upd: - self._android_update_sdk(self._build_package_string('build-tools', ver)) + available_v_build_tools = self._android_list_build_tools_versions() + if not available_v_build_tools: + self.buildozer.warning('Did not find any build tools available to download') + + latest_v_build_tools = sorted(available_v_build_tools)[-1] + if latest_v_build_tools > installed_v_build_tools and not skip_upd: + self._sdkmanager('"build-tools;{}"'.format(latest_v_build_tools)) + # 2. check aidl can be run self._check_aidl(v_build_tools) # 3. finally, install the android for the current api android_platform = join(self.android_sdk_dir, 'platforms', 'android-{0}'.format(self.android_api)) - if not self.buildozer.file_exists(android_platform): - packages = self._android_list_sdk() - android_package = 'android-{}'.format(self.android_api) - if android_package in packages and not skip_upd: - self._android_update_sdk(android_package) + if not self.buildozer.file_exists(android_platform) and not skip_upd: + self._sdkmanager('"platforms;android-{}"'.format(self.android_api)) self.buildozer.info('Android packages installation done.') @@ -586,81 +599,190 @@ def _install_p4a(self): options = "--user" if "VIRTUAL_ENV" in os.environ or "CONDA_PREFIX" in os.environ: options = "" + print('pa dir', self.pa_dir) + print('pip_deps', pip_deps) cmd('{} -m pip install -q {} {}'.format(executable, options, " ".join(pip_deps))) - def get_available_packages(self): - available_modules = self.buildozer.cmd('./distribute.sh -l', - cwd=self.pa_dir, - get_stdout=True)[0] - if not available_modules.startswith('Available modules:'): - self.buildozer.error('Python-for-android invalid output for -l') - return available_modules[19:].splitlines()[0].split() - def compile_platform(self): - # for android, the compilation depends really on the app requirements. - # compile the distribution only if the requirements changed. - last_requirements = self.buildozer.state.get('android.requirements', - '') - app_requirements = self.buildozer.config.getlist('app', 'requirements', - '') - - # we need to extract the requirements that python-for-android knows - # about - available_modules = self.get_available_packages() - onlyname = lambda x: x.split('==')[0] - android_requirements = [x - for x in app_requirements - if onlyname(x) in available_modules] - - need_compile = 0 - if last_requirements != android_requirements: - need_compile = 1 - + app_requirements = self.buildozer.config.getlist( + 'app', 'requirements', '') dist_name = self.buildozer.config.get('app', 'package.name') - dist_dir = join(self.pa_dir, 'dist', dist_name) - dist_file = join(dist_dir, 'private', 'include', 'python2.7', - 'pyconfig.h') - if not exists(dist_file): - need_compile = 1 + local_recipes = self.get_local_recipes_dir() + requirements = ','.join(app_requirements) + options = [] - # len('requirements.source.') == 20, so use name[20:] source_dirs = { 'P4A_{}_DIR'.format(name[20:]): realpath(expanduser(value)) for name, value in self.buildozer.config.items('app') if name.startswith('requirements.source.') - } + } if source_dirs: self.buildozer.environ.update(source_dirs) self.buildozer.info('Using custom source dirs:\n {}'.format( '\n '.join(['{} = {}'.format(k, v) for k, v in source_dirs.items()]))) - last_source_requirements = self.buildozer.state.get( - 'android.requirements.source', {}) - if source_dirs != last_source_requirements: - need_compile = 1 + if self.buildozer.config.getbooldefault('app', 'android.copy_libs', True): + options.append("--copy-libs") + # support for recipes in a local directory within the project + if local_recipes: + options.append('--local-recipes') + options.append(local_recipes) + config = self.buildozer.config + self._p4a( + ("create --dist_name={} --bootstrap={} --requirements={} " + "--arch {} {}").format( + dist_name, self._p4a_bootstrap, requirements, + config.getdefault('app', 'android.arch', "armeabi-v7a"), " ".join(options)), + get_stdout=True)[0] - if not need_compile: - self.buildozer.info('Distribution already compiled, pass.') - return + def get_available_packages(self): + return True - modules_str = ' '.join(android_requirements) - cmd = self.buildozer.cmd - self.buildozer.debug('Clean and build python-for-android') - self.buildozer.rmdir(dist_dir) # Delete existing distribution to stop - # p4a complaining - cmd('./distribute.sh -m "{0}" -d "{1}"'.format(modules_str, dist_name), - cwd=self.pa_dir) - self.buildozer.debug('Remove temporary build files') - self.buildozer.rmdir(join(self.pa_dir, 'build')) - self.buildozer.rmdir(join(self.pa_dir, '.packages')) - self.buildozer.rmdir(join(self.pa_dir, 'src', 'jni', 'obj', 'local')) - self.buildozer.info('Distribution compiled.') - - # ensure we will not compile again - self.buildozer.state['android.requirements'] = android_requirements - self.buildozer.state['android.requirements.source'] = source_dirs - self.buildozer.state.sync() + def get_dist_dir(self, dist_name): + return join(self._build_dir, 'dists', dist_name) + + def get_local_recipes_dir(self): + local_recipes = self.buildozer.config.getdefault('app', 'p4a.local_recipes') + return realpath(expanduser(local_recipes)) if local_recipes else None + + def execute_build_package(self, build_cmd): + # wrapper from previous old_toolchain to new toolchain + dist_name = self.buildozer.config.get('app', 'package.name') + local_recipes = self.get_local_recipes_dir() + cmd = [self.p4a_apk_cmd, "--dist_name", dist_name] + for args in build_cmd: + option, values = args[0], args[1:] + if option == "debug": + continue + elif option == "release": + cmd.append("--release") + if self.check_p4a_sign_env(True): + cmd.append("--sign") + continue + if option == "--window": + cmd.append("--window") + elif option == "--sdk": + cmd.append("--android_api") + cmd.extend(values) + else: + cmd.extend(args) + + # support for presplash background color + presplash_color = self.buildozer.config.getdefault('app', 'android.presplash_color', None) + if presplash_color: + cmd.append('--presplash-color') + cmd.append("'{}'".format(presplash_color)) + + # support for services + services = self.buildozer.config.getlist('app', 'services', []) + for service in services: + cmd.append("--service") + cmd.append(service) + + # support for copy-libs + if self.buildozer.config.getbooldefault('app', 'android.copy_libs', True): + cmd.append("--copy-libs") + + # support for recipes in a local directory within the project + if local_recipes: + cmd.append('--local-recipes') + cmd.append(local_recipes) + + # support for blacklist/whitelist filename + whitelist_src = self.buildozer.config.getdefault('app', 'android.whitelist_src', None) + blacklist_src = self.buildozer.config.getdefault('app', 'android.blacklist_src', None) + if whitelist_src: + cmd.append('--whitelist') + cmd.append(realpath(whitelist_src)) + if blacklist_src: + cmd.append('--blacklist') + cmd.append(realpath(blacklist_src)) + + # support for aars + aars = self.buildozer.config.getlist('app', 'android.add_aars', []) + for aar in aars: + cmd.append('--add-aar') + cmd.append(realpath(aar)) + + # support for gradle dependencies + gradle_dependencies = self.buildozer.config.getlist('app', 'android.gradle_dependencies', []) + for gradle_dependency in gradle_dependencies: + cmd.append('--depend') + cmd.append(gradle_dependency) + + cmd.append('--arch') + cmd.append(self.buildozer.config.getdefault('app', 'android.arch', "armeabi-v7a")) + + cmd = " ".join(cmd) + self._p4a(cmd) + + def get_release_mode(self): + if self.check_p4a_sign_env(): + return "release" + return "release-unsigned" + + def check_p4a_sign_env(self, error=False): + keys = ["KEYALIAS", "KEYSTORE_PASSWD", "KEYSTORE", "KEYALIAS_PASSWD"] + check = True + for key in keys: + key = "P4A_RELEASE_{}".format(key) + if key not in os.environ: + if error: + self.buildozer.error( + ("Asking for release but {} is missing" + "--sign will not be passed").format(key)) + check = False + return check + + def cmd_run(self, *args): + entrypoint = self.buildozer.config.getdefault( + 'app', 'android.entrypoint') + if not entrypoint: + self.buildozer.config.set('app', 'android.entrypoint', 'org.kivy.android.PythonActivity') + + super(TargetAndroid, self).cmd_run(*args) + + entrypoint = self.buildozer.config.getdefault( + 'app', 'android.entrypoint', 'org.renpy.android.PythonActivity') + package = self._get_package() + + # push on the device + for serial in self.serials: + self.buildozer.environ['ANDROID_SERIAL'] = serial + self.buildozer.info('Run on {}'.format(serial)) + self.buildozer.cmd( + '{adb} shell am start -n {package}/{entry} -a {entry}'.format( + adb=self.adb_cmd, + package=package, + entry=entrypoint), + cwd=self.buildozer.global_platform_dir) + self.buildozer.environ.pop('ANDROID_SERIAL', None) + + self.buildozer.info('Application started.') + + def cmd_p4a(self, *args): + ''' + Run p4a commands. Args must come after --, or + use --alias to make an alias + ''' + self.check_requirements() + self.install_platform() + args = args[0] + if args and args[0] == '--alias': + print('To set up p4a in this shell session, execute:') + print(' alias p4a=$(buildozer {} p4a --alias 2>&1 >/dev/null)' + .format(self.targetname)) + sys.stderr.write('PYTHONPATH={} {}\n'.format(self.pa_dir, self._p4a_cmd)) + else: + self._p4a(' '.join(args) if args else '') + + def cmd_clean(self, *args): + ''' + Clean the build and distribution + ''' + self._p4a("clean_builds") + self._p4a("clean_dists") def _get_package(self): config = self.buildozer.config @@ -678,22 +800,6 @@ def _generate_whitelist(self, dist_dir): for wl in p4a_whitelist: fd.write(wl + '\n') - def get_dist_dir(self, dist_name): - return join(self.pa_dir, 'dist', dist_name) - - @property - def dist_dir(self): - dist_name = self.buildozer.config.get('app', 'package.name') - return self.get_dist_dir(dist_name) - - def execute_build_package(self, build_cmd): - dist_name = self.buildozer.config.get('app', 'package.name') - cmd = [self.p4a_apk_cmd] - for args in build_cmd: - cmd.append(" ".join(args)) - cmd = " ".join(cmd) - self.buildozer.cmd(cmd, cwd=self.get_dist_dir(dist_name)) - def build_package(self): dist_name = self.buildozer.config.get('app', 'package.name') dist_dir = self.get_dist_dir(dist_name) @@ -892,9 +998,6 @@ def build_package(self): self.buildozer.state['android:latestapk'] = apk_dest self.buildozer.state['android:latestmode'] = self.build_mode - def get_release_mode(self): - return "release-unsigned" - def _update_libraries_references(self, dist_dir): # ensure the project.properties exist project_fn = join(dist_dir, 'project.properties') @@ -1029,27 +1132,6 @@ def cmd_deploy(self, *args): self.buildozer.info('Application pushed.') - def cmd_run(self, *args): - super(TargetAndroid, self).cmd_run(*args) - - entrypoint = self.buildozer.config.getdefault( - 'app', 'android.entrypoint', 'org.renpy.android.PythonActivity') - package = self._get_package() - - # push on the device - for serial in self.serials: - self.buildozer.environ['ANDROID_SERIAL'] = serial - self.buildozer.info('Run on {}'.format(serial)) - self.buildozer.cmd( - '{adb} shell am start -n {package}/{entry} -a {entry}'.format( - adb=self.adb_cmd, - package=package, - entry=entrypoint), - cwd=self.buildozer.global_platform_dir) - self.buildozer.environ.pop('ANDROID_SERIAL', None) - - self.buildozer.info('Application started.') - def cmd_logcat(self, *args): '''Show the log from the device ''' diff --git a/buildozer/targets/android_new.py b/buildozer/targets/android_new.py deleted file mode 100644 index 1fcc29652..000000000 --- a/buildozer/targets/android_new.py +++ /dev/null @@ -1,217 +0,0 @@ -# coding=utf-8 -''' -Android target, based on python-for-android project -''' - -import sys -import os - -from buildozer import USE_COLOR -from buildozer.targets.android import TargetAndroid -from os.path import join, expanduser, realpath - - -class TargetAndroidNew(TargetAndroid): - targetname = 'android' - p4a_branch = "master" - p4a_directory = "python-for-android-new-toolchain" - p4a_apk_cmd = "apk --debug --bootstrap=" - extra_p4a_args = '' - - def __init__(self, *args, **kwargs): - super(TargetAndroidNew, self).__init__(*args, **kwargs) - self._build_dir = join(self.buildozer.platform_dir, 'build') - executable = sys.executable or 'python' - self._p4a_cmd = '{} -m pythonforandroid.toolchain '.format(executable) - self._p4a_bootstrap = self.buildozer.config.getdefault( - 'app', 'p4a.bootstrap', 'sdl2') - self.p4a_apk_cmd += self._p4a_bootstrap - color = 'always' if USE_COLOR else 'never' - self.extra_p4a_args = ' --color={} --storage-dir="{}"'.format( - color, self._build_dir) - - # minapi should match ndk-api, so can use the same default if - # nothing is specified - ndk_api = self.buildozer.config.getdefault( - 'app', 'android.ndk_api', self.android_minapi) - self.extra_p4a_args += ' --ndk-api={}'.format(ndk_api) - - hook = self.buildozer.config.getdefault("app", "p4a.hook", None) - if hook is not None: - self.extra_p4a_args += ' --hook={}'.format(realpath(hook)) - port = self.buildozer.config.getdefault('app', 'p4a.port', None) - if port is not None: - self.extra_p4a_args += ' --port={}'.format(port) - - def _p4a(self, cmd, **kwargs): - if not hasattr(self, "pa_dir"): - self.pa_dir = join(self.buildozer.platform_dir, self.p4a_directory) - kwargs.setdefault('cwd', self.pa_dir) - return self.buildozer.cmd(self._p4a_cmd + cmd + self.extra_p4a_args, **kwargs) - - def get_available_packages(self): - return True - - def compile_platform(self): - app_requirements = self.buildozer.config.getlist( - 'app', 'requirements', '') - dist_name = self.buildozer.config.get('app', 'package.name') - local_recipes = self.get_local_recipes_dir() - requirements = ','.join(app_requirements) - options = [] - - source_dirs = { - 'P4A_{}_DIR'.format(name[20:]): realpath(expanduser(value)) - for name, value in self.buildozer.config.items('app') - if name.startswith('requirements.source.') - } - if source_dirs: - self.buildozer.environ.update(source_dirs) - self.buildozer.info('Using custom source dirs:\n {}'.format( - '\n '.join(['{} = {}'.format(k, v) - for k, v in source_dirs.items()]))) - - if self.buildozer.config.getbooldefault('app', 'android.copy_libs', True): - options.append("--copy-libs") - # support for recipes in a local directory within the project - if local_recipes: - options.append('--local-recipes') - options.append(local_recipes) - config = self.buildozer.config - self._p4a( - ("create --dist_name={} --bootstrap={} --requirements={} " - "--arch {} {}").format( - dist_name, self._p4a_bootstrap, requirements, - config.getdefault('app', 'android.arch', "armeabi-v7a"), " ".join(options)), - get_stdout=True)[0] - - def get_dist_dir(self, dist_name): - return join(self._build_dir, 'dists', dist_name) - - def get_local_recipes_dir(self): - local_recipes = self.buildozer.config.getdefault('app', 'p4a.local_recipes') - return realpath(expanduser(local_recipes)) if local_recipes else None - - def execute_build_package(self, build_cmd): - # wrapper from previous old_toolchain to new toolchain - dist_name = self.buildozer.config.get('app', 'package.name') - local_recipes = self.get_local_recipes_dir() - cmd = [self.p4a_apk_cmd, "--dist_name", dist_name] - for args in build_cmd: - option, values = args[0], args[1:] - if option == "debug": - continue - elif option == "release": - cmd.append("--release") - if self.check_p4a_sign_env(True): - cmd.append("--sign") - continue - if option == "--window": - cmd.append("--window") - elif option == "--sdk": - cmd.append("--android_api") - cmd.extend(values) - else: - cmd.extend(args) - - # support for presplash background color - presplash_color = self.buildozer.config.getdefault('app', 'android.presplash_color', None) - if presplash_color: - cmd.append('--presplash-color') - cmd.append("'{}'".format(presplash_color)) - - # support for services - services = self.buildozer.config.getlist('app', 'services', []) - for service in services: - cmd.append("--service") - cmd.append(service) - - # support for copy-libs - if self.buildozer.config.getbooldefault('app', 'android.copy_libs', True): - cmd.append("--copy-libs") - - # support for recipes in a local directory within the project - if local_recipes: - cmd.append('--local-recipes') - cmd.append(local_recipes) - - # support for blacklist/whitelist filename - whitelist_src = self.buildozer.config.getdefault('app', 'android.whitelist_src', None) - blacklist_src = self.buildozer.config.getdefault('app', 'android.blacklist_src', None) - if whitelist_src: - cmd.append('--whitelist') - cmd.append(realpath(whitelist_src)) - if blacklist_src: - cmd.append('--blacklist') - cmd.append(realpath(blacklist_src)) - - # support for aars - aars = self.buildozer.config.getlist('app', 'android.add_aars', []) - for aar in aars: - cmd.append('--add-aar') - cmd.append(realpath(aar)) - - # support for gradle dependencies - gradle_dependencies = self.buildozer.config.getlist('app', 'android.gradle_dependencies', []) - for gradle_dependency in gradle_dependencies: - cmd.append('--depend') - cmd.append(gradle_dependency) - - cmd.append('--arch') - cmd.append(self.buildozer.config.getdefault('app', 'android.arch', "armeabi-v7a")) - - cmd = " ".join(cmd) - self._p4a(cmd) - - def get_release_mode(self): - if self.check_p4a_sign_env(): - return "release" - return "release-unsigned" - - def check_p4a_sign_env(self, error=False): - keys = ["KEYALIAS", "KEYSTORE_PASSWD", "KEYSTORE", "KEYALIAS_PASSWD"] - check = True - for key in keys: - key = "P4A_RELEASE_{}".format(key) - if key not in os.environ: - if error: - self.buildozer.error( - ("Asking for release but {} is missing" - "--sign will not be passed").format(key)) - check = False - return check - - def cmd_run(self, *args): - entrypoint = self.buildozer.config.getdefault( - 'app', 'android.entrypoint') - if not entrypoint: - self.buildozer.config.set('app', 'android.entrypoint', 'org.kivy.android.PythonActivity') - return super(TargetAndroidNew, self).cmd_run(*args) - - def cmd_p4a(self, *args): - ''' - Run p4a commands. Args must come after --, or - use --alias to make an alias - ''' - self.check_requirements() - self.install_platform() - args = args[0] - if args and args[0] == '--alias': - print('To set up p4a in this shell session, execute:') - print(' alias p4a=$(buildozer {} p4a --alias 2>&1 >/dev/null)' - .format(self.targetname)) - sys.stderr.write('PYTHONPATH={} {}\n'.format(self.pa_dir, self._p4a_cmd)) - else: - self._p4a(' '.join(args) if args else '') - - def cmd_clean(self, *args): - ''' - Clean the build and distribution - ''' - self._p4a("clean_builds") - self._p4a("clean_dists") - - -def get_target(buildozer): - buildozer.targetname = "android" - return TargetAndroidNew(buildozer)