Merge pull request #806 from inclement/remove_android_old
Removed android_old and updated SDK management to work with current SDK
This commit is contained in:
commit
f815965159
5 changed files with 378 additions and 454 deletions
|
@ -134,7 +134,6 @@ Usage
|
|||
Available targets:
|
||||
android Android target, based on python-for-android project
|
||||
ios iOS target, based on kivy-ios project
|
||||
android_old Android target, based on python-for-android project (old toolchain)
|
||||
|
||||
Global commands (without target):
|
||||
distclean Clean the whole Buildozer environment.
|
||||
|
@ -153,11 +152,6 @@ Usage
|
|||
run Run the application on the device
|
||||
serve Serve the bin directory via SimpleHTTPServer
|
||||
|
||||
Target "android_old" commands:
|
||||
adb Run adb from the Android SDK. Args must come after --, or
|
||||
use --alias to make an alias
|
||||
logcat Show the log from the device
|
||||
|
||||
Target "ios" commands:
|
||||
list_identities List the available identities to use for signing.
|
||||
xcode Open the xcode project.
|
||||
|
|
|
@ -155,7 +155,6 @@ class Buildozer(object):
|
|||
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 @@ class Buildozer(object):
|
|||
# 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 @@ class Buildozer(object):
|
|||
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 @@ class Buildozer(object):
|
|||
|
||||
# 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)
|
||||
|
||||
|
|
|
@ -119,6 +119,12 @@ fullscreen = 0
|
|||
# when an update is due and you just want to test/build your package
|
||||
# android.skip_update = False
|
||||
|
||||
# (bool) If True, then automatically accept SDK license
|
||||
# agreements. This is intended for automation only. If set to False,
|
||||
# the default, you will be shown the license when first running
|
||||
# buildozer.
|
||||
# android.accept_sdk_license = False
|
||||
|
||||
# (str) Android entry point, default is ok for Kivy-based app
|
||||
#android.entrypoint = org.renpy.android.PythonActivity
|
||||
|
||||
|
|
|
@ -16,7 +16,6 @@ WSL = 'Microsoft' in uname()[2]
|
|||
|
||||
ANDROID_API = '27'
|
||||
ANDROID_MINAPI = '21'
|
||||
ANDROID_SDK_VERSION = '20'
|
||||
ANDROID_NDK_VERSION = '17c'
|
||||
APACHE_ANT_VERSION = '1.9.4'
|
||||
|
||||
|
@ -28,8 +27,7 @@ import ast
|
|||
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
|
||||
|
@ -40,17 +38,88 @@ from glob import glob
|
|||
from buildozer.libs.version import parse
|
||||
from distutils.version import LooseVersion
|
||||
|
||||
# buildozer.spec tokens that used to exist but are now ignored
|
||||
DEPRECATED_TOKENS = (('app', 'android.sdk'), )
|
||||
|
||||
# Default SDK tag to download. This is not a configurable option
|
||||
# because it doesn't seem to matter much, it is normally correct to
|
||||
# download once then update all the components as buildozer already
|
||||
# does.
|
||||
DEFAULT_SDK_TAG = '4333796'
|
||||
|
||||
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 = ''
|
||||
|
||||
@property
|
||||
def android_sdk_version(self):
|
||||
return self.buildozer.config.getdefault('app', 'android.sdk',
|
||||
ANDROID_SDK_VERSION)
|
||||
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)
|
||||
|
||||
self.warn_on_deprecated_tokens()
|
||||
|
||||
def warn_on_deprecated_tokens(self):
|
||||
for section, token in DEPRECATED_TOKENS:
|
||||
value = self.buildozer.config.getdefault(section, token, None)
|
||||
if value is not None:
|
||||
error = ('WARNING: Config token {} {} is deprecated and ignored, '
|
||||
'but you set value {}').format(section, token, value)
|
||||
self.buildozer.error(error)
|
||||
|
||||
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, **kwargs):
|
||||
"""Call the sdkmanager in our Android SDK with the given arguments."""
|
||||
# Use the android-sdk dir as cwd by default
|
||||
kwargs['cwd'] = kwargs.get(
|
||||
'cwd', os.path.join(self.buildozer.global_platform_dir,
|
||||
'android-sdk'))
|
||||
|
||||
sdkmanager_path = os.path.join(self.buildozer.global_platform_dir,
|
||||
'android-sdk',
|
||||
'tools',
|
||||
'bin',
|
||||
'sdkmanager')
|
||||
if not os.path.isfile(sdkmanager_path):
|
||||
raise BuildozerException(
|
||||
('sdkmanager path "{}" does not exist, sdkmanager is not'
|
||||
'installed'.format(sdkmanager_path)))
|
||||
|
||||
command = sdkmanager_path + ' ' + ' '.join(args)
|
||||
|
||||
return_child = kwargs.pop('return_child', False)
|
||||
if return_child:
|
||||
return self.buildozer.cmd_expect(command, **kwargs)
|
||||
else:
|
||||
kwargs['get_stdout'] = kwargs.get('get_stdout', True)
|
||||
return self.buildozer.cmd(command, **kwargs)
|
||||
|
||||
@property
|
||||
def android_ndk_version(self):
|
||||
|
@ -73,10 +142,8 @@ class TargetAndroid(Target):
|
|||
'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):
|
||||
|
@ -106,19 +173,15 @@ class TargetAndroid(Target):
|
|||
self._set_win32_java_home()
|
||||
except:
|
||||
traceback.print_exc()
|
||||
self.android_cmd = join(self.android_sdk_dir, 'tools',
|
||||
'android.bat')
|
||||
self.adb_cmd = join(self.android_sdk_dir, 'platform-tools',
|
||||
'adb.exe')
|
||||
self.javac_cmd = self._locate_java('javac.exe')
|
||||
self.keytool_cmd = self._locate_java('keytool.exe')
|
||||
elif platform in ('darwin', ):
|
||||
self.android_cmd = join(self.android_sdk_dir, 'tools', 'android')
|
||||
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')
|
||||
else:
|
||||
self.android_cmd = join(self.android_sdk_dir, 'tools', 'android')
|
||||
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')
|
||||
|
@ -172,9 +235,11 @@ class TargetAndroid(Target):
|
|||
key = 'android:available_permissions'
|
||||
key_sdk = 'android:available_permissions_sdk'
|
||||
|
||||
current_platform_tools = self._android_get_installed_platform_tools_version()
|
||||
|
||||
refresh_permissions = False
|
||||
sdk = self.buildozer.state.get(key_sdk, None)
|
||||
if not sdk or sdk != self.android_sdk_version:
|
||||
if not sdk or sdk != current_platform_tools:
|
||||
refresh_permissions = True
|
||||
if key not in self.buildozer.state:
|
||||
refresh_permissions = True
|
||||
|
@ -194,7 +259,7 @@ class TargetAndroid(Target):
|
|||
available_permissions = [x.attrib['name'] for x in fields]
|
||||
|
||||
self.buildozer.state[key] = available_permissions
|
||||
self.buildozer.state[key_sdk] = self.android_sdk_version
|
||||
self.buildozer.state[key_sdk] = current_platform_tools
|
||||
return available_permissions
|
||||
except:
|
||||
return None
|
||||
|
@ -248,30 +313,30 @@ class TargetAndroid(Target):
|
|||
|
||||
self.buildozer.info('Android SDK is missing, downloading')
|
||||
if platform in ('win32', 'cygwin'):
|
||||
archive = 'android-sdk_r{0}-windows.zip'
|
||||
archive = 'sdk-tools-windows-{}.zip'.format(DEFAULT_SDK_TAG)
|
||||
unpacked = 'android-sdk-windows'
|
||||
elif platform in ('darwin', ):
|
||||
archive = 'android-sdk_r{0}-macosx.zip'
|
||||
archive = 'sdk-tools-darwin-{}.zip'.format(DEFAULT_SDK_TAG)
|
||||
unpacked = 'android-sdk-macosx'
|
||||
elif platform.startswith('linux'):
|
||||
archive = 'android-sdk_r{0}-linux.tgz'
|
||||
archive = 'sdk-tools-linux-{}.zip'.format(DEFAULT_SDK_TAG)
|
||||
unpacked = 'android-sdk-linux'
|
||||
else:
|
||||
raise SystemError('Unsupported platform: {0}'.format(platform))
|
||||
|
||||
archive = archive.format(self.android_sdk_version)
|
||||
url = 'http://dl.google.com/android/'
|
||||
if not os.path.exists(sdk_dir):
|
||||
os.makedirs(sdk_dir)
|
||||
|
||||
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,43 +406,85 @@ class TargetAndroid(Target):
|
|||
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')
|
||||
|
||||
# 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: ')]
|
||||
lines = available_packages[0].split('\n')
|
||||
|
||||
def _android_update_sdk(self, packages):
|
||||
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_get_installed_platform_tools_version(self):
|
||||
"""
|
||||
Crudely parse out the installed platform-tools version
|
||||
"""
|
||||
|
||||
platform_tools_dir = os.path.join(
|
||||
self.android_sdk_dir,
|
||||
'platform-tools')
|
||||
|
||||
if not os.path.exists(platform_tools_dir):
|
||||
return None
|
||||
|
||||
data_file = os.path.join(platform_tools_dir, 'source.properties')
|
||||
if not os.path.exists(data_file):
|
||||
return None
|
||||
|
||||
with open(data_file, 'r') as fileh:
|
||||
lines = fileh.readlines()
|
||||
|
||||
for line in lines:
|
||||
if line.startswith('Pkg.Revision='):
|
||||
break
|
||||
else:
|
||||
self.buildozer.error('Read {} but found no Pkg.Revision'.format(data_file))
|
||||
# Don't actually exit, in case the build env is
|
||||
# okay. Something else will fault if it's important.
|
||||
return None
|
||||
|
||||
revision = line.split('=')[1].strip()
|
||||
|
||||
return revision
|
||||
|
||||
|
||||
def _android_update_sdk(self, *sdkmanager_commands):
|
||||
"""Update the tools and package-tools if possible"""
|
||||
from pexpect import EOF
|
||||
java_tool_options = environ.get('JAVA_TOOL_OPTIONS', '')
|
||||
child = self.buildozer.cmd_expect(
|
||||
'{} update sdk -u -a -t {}'.format(
|
||||
self.android_cmd,
|
||||
packages,
|
||||
cwd=self.buildozer.global_platform_dir),
|
||||
timeout=None,
|
||||
env={
|
||||
|
||||
auto_accept_license = self.buildozer.config.getdefault(
|
||||
'app', 'android.accept_sdk_license', False)
|
||||
|
||||
if auto_accept_license:
|
||||
java_tool_options = environ.get('JAVA_TOOL_OPTIONS', '')
|
||||
env = os.environ.copy()
|
||||
env.update({
|
||||
'JAVA_TOOL_OPTIONS': java_tool_options +
|
||||
' -Dfile.encoding=UTF-8'
|
||||
})
|
||||
while True:
|
||||
index = child.expect([EOF, u'[y/n]: '])
|
||||
if index == 0:
|
||||
break
|
||||
child.sendline('y')
|
||||
|
||||
def _build_package_string(self, package_name, version):
|
||||
return '{}-{}'.format(package_name, version)
|
||||
child = self._sdkmanager(
|
||||
*sdkmanager_commands,
|
||||
timeout=None,
|
||||
return_child=True,
|
||||
env=env)
|
||||
while True:
|
||||
index = child.expect([EOF, u'\(y/N\): '])
|
||||
if index == 0:
|
||||
break
|
||||
child.sendline('y')
|
||||
else:
|
||||
# the user will be prompted to read and accept the license
|
||||
self._sdkmanager(*sdkmanager_commands)
|
||||
|
||||
def _read_version_subdir(self, *args):
|
||||
versions = []
|
||||
|
@ -420,68 +527,54 @@ class TargetAndroid(Target):
|
|||
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')
|
||||
skip_upd = self.buildozer.config.getdefault(
|
||||
'app', 'android.skip_update', False)
|
||||
|
||||
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')
|
||||
if not skip_upd:
|
||||
self.buildozer.info('Installing/updating SDK platform tools if necessary')
|
||||
|
||||
# just calling sdkmanager with the items will install them if necessary
|
||||
self._android_update_sdk('tools', 'platform-tools')
|
||||
self._android_update_sdk('--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,
|
||||
self.buildozer.info('Updating SDK build tools if necessary')
|
||||
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.error('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:
|
||||
if not skip_upd:
|
||||
self._android_update_sdk(
|
||||
'"build-tools;{}"'.format(latest_v_build_tools))
|
||||
installed_v_build_tools = latest_v_build_tools
|
||||
else:
|
||||
self.buildozer.info(
|
||||
'Skipping update to build tools {} due to spec setting'.format(
|
||||
latest_v_build_tools))
|
||||
|
||||
# 2. check aidl can be run
|
||||
self._check_aidl(v_build_tools)
|
||||
self._check_aidl(installed_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))
|
||||
self.buildozer.info('Downloading platform api target if necessary')
|
||||
android_platform = join(self.android_sdk_dir, 'platforms', 'android-{}'.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 skip_upd:
|
||||
self._sdkmanager('"platforms;android-{}"'.format(self.android_api))
|
||||
else:
|
||||
self.buildozer.info(
|
||||
'Skipping install API {} platform tools due to spec setting'.format(
|
||||
self.android_api))
|
||||
|
||||
self.buildozer.info('Android packages installation done.')
|
||||
|
||||
|
@ -531,7 +624,6 @@ class TargetAndroid(Target):
|
|||
'ANDROIDNDK': self.android_ndk_dir,
|
||||
'ANDROIDAPI': self.android_api,
|
||||
'ANDROIDMINAPI': self.android_minapi,
|
||||
'ANDROIDNDKVER': 'r{}'.format(self.android_ndk_version)
|
||||
})
|
||||
|
||||
def _install_p4a(self):
|
||||
|
@ -588,79 +680,186 @@ class TargetAndroid(Target):
|
|||
options = ""
|
||||
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.')
|
||||
def get_dist_dir(self, dist_name):
|
||||
return join(self._build_dir, 'dists', dist_name)
|
||||
|
||||
# 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_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 +877,6 @@ class TargetAndroid(Target):
|
|||
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 +1075,6 @@ class TargetAndroid(Target):
|
|||
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 +1209,6 @@ class TargetAndroid(Target):
|
|||
|
||||
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
|
||||
'''
|
||||
|
|
|
@ -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)
|
Loading…
Reference in a new issue