axmol/tools/console/plugins/plugin_compile/build_android.py

686 lines
28 KiB
Python

#!/usr/bin/python
# build_native.py
# Build native codes
import sys
import os, os.path
import shutil
from optparse import OptionParser
import axmol
from MultiLanguage import MultiLanguage
import axmol_project
import json
import re
from xml.dom import minidom
if(sys.version_info.major < 3):
import project_compile
BUILD_CFIG_FILE="build-cfg.json"
class AndroidBuilder(object):
CFG_KEY_COPY_TO_ASSETS = "copy_to_assets"
CFG_KEY_MUST_COPY_TO_ASSERTS = "must_copy_to_assets"
CFG_KEY_STORE = "key_store"
CFG_KEY_STORE_PASS = "key_store_pass"
CFG_KEY_ALIAS = "alias"
CFG_KEY_ALIAS_PASS = "alias_pass"
GRADLE_KEY_STORE = "RELEASE_STORE_FILE"
GRADLE_KEY_ALIAS = "RELEASE_KEY_ALIAS"
GRADLE_KEY_STORE_PASS = "RELEASE_STORE_PASSWORD"
GRADLE_KEY_ALIAS_PASS = "RELEASE_KEY_PASSWORD"
GRADLE_PROP_TARGET_VERSION = 'PROP_TARGET_SDK_VERSION'
GRADLE_PROP_BUILD_TYPE = 'PROP_BUILD_TYPE'
GRADLE_PROP_APP_ABI = 'PROP_APP_ABI'
GRADLE_PROP_COMPILE_SCRIPT = 'PROP_COMPILE_SCRIPT'
GRADLE_PROP_LUA_ENCRYPT = 'PROP_LUA_ENCRYPT'
GRADLE_PROP_LUA_ENCRYPT_KEY = 'PROP_LUA_ENCRYPT_KEY'
GRADLE_PROP_LUA_ENCRYPT_SIGN = 'PROP_LUA_ENCRYPT_SIGN'
def __init__(self, verbose, app_android_root, no_res, proj_obj, mode, build_type, app_abi, gradle_support_ndk=False):
self._verbose = verbose
self.app_android_root = app_android_root
self._no_res = no_res
self._project = proj_obj
self.gradle_support_ndk = gradle_support_ndk
self.app_abi = app_abi
self.mode = mode
self.build_type = build_type
# check environment variable
self.sdk_root = axmol.check_environment_variable('ANDROID_HOME')
self.ant_root = None
if os.path.exists(os.path.join(self.app_android_root, "gradle.properties")):
self.sign_prop_file = os.path.join(self.app_android_root, "gradle.properties")
elif os.path.exists(os.path.join(self.app_android_root, 'app', "gradle.properties")):
self.sign_prop_file = os.path.join(self.app_android_root, 'app', "gradle.properties")
else:
raise axmol.CCPluginError(MultiLanguage.get_string('COMPILE_GRADLE_PROPERTIES_NOT_FOUND'),
axmol.CCPluginError.ERROR_PATH_NOT_FOUND)
self._parse_cfg()
def _run_cmd(self, command, cwd=None):
axmol.CMDRunner.run_cmd(command, self._verbose, cwd=cwd)
def _parse_cfg(self):
# get the properties for sign release apk
self.key_store_str = AndroidBuilder.GRADLE_KEY_STORE
self.key_alias_str = AndroidBuilder.GRADLE_KEY_ALIAS
self.key_store_pass_str = AndroidBuilder.GRADLE_KEY_STORE_PASS
self.key_alias_pass_str = AndroidBuilder.GRADLE_KEY_ALIAS_PASS
if self.gradle_support_ndk:
return
self.cfg_path = os.path.join(self.app_android_root, BUILD_CFIG_FILE)
try:
f = open(self.cfg_path)
cfg = json.load(f, encoding='utf8')
f.close()
except Exception:
raise axmol.CCPluginError(MultiLanguage.get_string('COMPILE_ERROR_PARSE_CFG_FAILED_FMT', self.cfg_path),
axmol.CCPluginError.ERROR_PARSE_FILE)
if axmol.dict_contains(cfg, project_compile.CCPluginCompile.CFG_KEY_MUST_COPY_RESOURCES):
if self._no_res:
self.res_files = cfg[project_compile.CCPluginCompile.CFG_KEY_MUST_COPY_RESOURCES]
else:
self.res_files = cfg[project_compile.CCPluginCompile.CFG_KEY_MUST_COPY_RESOURCES] + cfg[project_compile.CCPluginCompile.CFG_KEY_COPY_RESOURCES]
else:
self.res_files = cfg[project_compile.CCPluginCompile.CFG_KEY_COPY_RESOURCES]
move_cfg = {}
self.key_store = None
if axmol.dict_contains(cfg, AndroidBuilder.CFG_KEY_STORE):
self.key_store = cfg[AndroidBuilder.CFG_KEY_STORE]
move_cfg[self.key_store_str] = self.key_store
del cfg[AndroidBuilder.CFG_KEY_STORE]
self.key_store_pass = None
if axmol.dict_contains(cfg, AndroidBuilder.CFG_KEY_STORE_PASS):
self.key_store_pass = cfg[AndroidBuilder.CFG_KEY_STORE_PASS]
move_cfg[self.key_store_pass_str] = self.key_store_pass
del cfg[AndroidBuilder.CFG_KEY_STORE_PASS]
self.alias = None
if axmol.dict_contains(cfg, AndroidBuilder.CFG_KEY_ALIAS):
self.alias = cfg[AndroidBuilder.CFG_KEY_ALIAS]
move_cfg[self.key_alias_str] = self.alias
del cfg[AndroidBuilder.CFG_KEY_ALIAS]
self.alias_pass = None
if axmol.dict_contains(cfg, AndroidBuilder.CFG_KEY_ALIAS_PASS):
self.alias_pass = cfg[AndroidBuilder.CFG_KEY_ALIAS_PASS]
move_cfg[self.key_alias_pass_str] = self.alias_pass
del cfg[AndroidBuilder.CFG_KEY_ALIAS_PASS]
if len(move_cfg) > 0:
# move the config into ant.properties
self._move_cfg(move_cfg)
with open(self.cfg_path, 'w') as outfile:
json.dump(cfg, outfile, sort_keys = True, indent = 4)
outfile.close()
def has_keystore_in_signprops(self):
keystore = None
pattern = re.compile(r"^RELEASE_STORE_FILE=(.+)")
try:
file_obj = open(self.sign_prop_file)
for line in file_obj:
str1 = line.replace(' ', '')
str2 = str1.replace('\t', '')
match = pattern.match(str2)
if match is not None:
keystore = match.group(1)
break
file_obj.close()
except:
pass
if keystore is None:
return False
else:
return True
def _write_sign_properties(self, cfg):
file_obj = open(self.sign_prop_file, "a+")
for key in cfg.keys():
str_cfg = "%s=%s\n" % (key, cfg[key])
file_obj.write(str_cfg)
file_obj.close()
def _move_cfg(self, cfg):
if not self.has_keystore_in_signprops():
self._write_sign_properties(cfg)
def remove_c_libs(self, libs_dir):
for file_name in os.listdir(libs_dir):
lib_file = os.path.join(libs_dir, file_name)
if os.path.isfile(lib_file):
ext = os.path.splitext(lib_file)[1]
if ext == ".a" or ext == ".so":
os.remove(lib_file)
def _get_android_sdk_tools_ver(self, sdk_tools_path):
cfg_file = os.path.join(sdk_tools_path, 'source.properties')
if os.path.isfile(cfg_file):
f = open(cfg_file)
lines = f.readlines()
pattern = r'^Pkg\.Revision=(\d+)\.(\d+)'
for l in lines:
match = re.match(pattern, l.strip())
if match:
return ((int)(match.group(1)), (int)(match.group(2)))
raise axmol.CCPluginError(MultiLanguage.get_string('COMPILE_ERROR_UNKNOWN_ANDROID_SDK_TOOLS_VERSION'),
axmol.CCPluginError.ERROR_PATH_NOT_FOUND)
def _update_project_properties(self, folder_path, target_str):
props_path = os.path.join(folder_path, 'project.properties')
f = open(props_path)
lines = f.readlines()
f.close()
pattern = r'^target=(.*)$'
matched = False
new_line = 'target=%s\n' % target_str
for i in range(0, len(lines)):
l = lines[i]
match = re.match(pattern, l.strip())
if match:
lines[i] = new_line
matched = True
if not matched:
lines.append('\n')
lines.append(new_line)
f = open(props_path, 'w')
f.writelines(lines)
f.close()
def _write_local_properties(self, folder_path):
local_porps_path = os.path.join(folder_path, 'local.properties')
sdk_dir = self.sdk_root
# ndk_dir = axmol.check_environment_variable('ANDROID_NDK')
if axmol.os_is_win32():
# On Windows, the path should be like:
# sdk.dir = C:\\path\\android-sdk
sdk_dir = sdk_dir.replace('\\', '\\\\')
# ndk_dir = ndk_dir.replace('\\', '\\\\')
lines = [
'sdk.dir=%s\n' % sdk_dir,
# 'ndk.dir=%s\n' % ndk_dir
]
f = open(local_porps_path, 'w')
f.writelines(lines)
f.close()
def update_project(self, android_platform):
if self.gradle_support_ndk:
# If gradle supports ndk build, should write local.properties manually
self._write_local_properties(self.app_android_root)
return
manifest_path = os.path.join(self.app_android_root, 'app')
# check the android platform
target_str = self.check_android_platform(self.sdk_root, android_platform, manifest_path)
# should manually update the project
self._write_local_properties(manifest_path)
self._update_project_properties(manifest_path, target_str)
# copy the local.properties to the app_android_root
file_name = 'local.properties'
src_path = os.path.normpath(os.path.join(manifest_path, file_name))
dst_path = os.path.normpath(os.path.join(self.app_android_root, file_name))
if src_path != dst_path:
if os.path.isfile(dst_path):
os.remove(dst_path)
shutil.copy(src_path, dst_path)
def get_toolchain_version(self, ndk_root, compile_obj):
# it should be possible to override the toolchain
if 'NDK_TOOLCHAIN_VERSION' in os.environ:
return os.environ['NDK_TOOLCHAIN_VERSION']
return '4.9'
def do_ndk_build(self, ndk_build_param, mode, build_type, compile_obj):
axmol.Logging.info(MultiLanguage.get_string('COMPILE_INFO_NDK_BUILD_TYPE', build_type))
ndk_root = axmol.check_environment_variable('ANDROID_NDK')
toolchain_version = self.get_toolchain_version(ndk_root, compile_obj)
ndk_work_dir = os.path.join(self.app_android_root, 'app')
reload(sys)
sys.setdefaultencoding('utf8')
ndk_path = axmol.CMDRunner.convert_path_to_cmd(os.path.join(ndk_root, "ndk-build"))
# delete template static and dynamic files
obj_local_dir = os.path.join(ndk_work_dir, "obj", "local")
if os.path.isdir(obj_local_dir):
for abi_dir in os.listdir(obj_local_dir):
static_file_path = os.path.join(ndk_work_dir, "obj", "local", abi_dir)
if os.path.isdir(static_file_path):
self.remove_c_libs(static_file_path)
if ndk_build_param is None:
ndk_build_cmd = '%s -C %s' % (ndk_path, ndk_work_dir)
else:
ndk_build_cmd = '%s -C %s %s' % (ndk_path, ndk_work_dir, ' '.join(ndk_build_param))
ndk_build_cmd = '%s NDK_TOOLCHAIN_VERSION=%s' % (ndk_build_cmd, toolchain_version)
if mode == 'debug':
ndk_build_cmd = '%s NDK_DEBUG=1' % ndk_build_cmd
self._run_cmd(ndk_build_cmd)
def _xml_attr(self, dir, file_name, node_name, attr):
doc = minidom.parse(os.path.join(dir, file_name))
return doc.getElementsByTagName(node_name)[0].getAttribute(attr)
def update_lib_projects(self, sdk_root, sdk_tool_path, android_platform, property_path):
property_file = os.path.join(property_path, "project.properties")
if not os.path.isfile(property_file):
return
patten = re.compile(r'^android\.library\.reference\.[\d]+=(.+)')
for line in open(property_file):
str1 = line.replace(' ', '')
str2 = str1.replace('\t', '')
match = patten.match(str2)
if match is not None:
# a lib project is found
lib_path = match.group(1)
abs_lib_path = os.path.join(property_path, lib_path)
abs_lib_path = os.path.normpath(abs_lib_path)
if os.path.isdir(abs_lib_path):
target_str = self.check_android_platform(sdk_root, android_platform, abs_lib_path)
command = "%s update lib-project -p %s -t %s" % (axmol.CMDRunner.convert_path_to_cmd(sdk_tool_path), abs_lib_path, target_str)
self._run_cmd(command)
self.update_lib_projects(sdk_root, sdk_tool_path, android_platform, abs_lib_path)
def get_api_level(self, target_str, raise_error=True):
match = re.match(r'android-(\d+)', target_str)
if match is not None:
ret = int(match.group(1))
else:
if raise_error:
raise axmol.CCPluginError(MultiLanguage.get_string('COMPILE_ERROR_NOT_VALID_AP_FMT', target_str),
axmol.CCPluginError.ERROR_PARSE_FILE)
else:
ret = -1
return ret
def get_target_config(self, proj_path):
property_file = os.path.join(proj_path, "project.properties")
if not os.path.isfile(property_file):
raise axmol.CCPluginError(MultiLanguage.get_string('COMPILE_ERROR_FILE_NOT_FOUND_FMT', property_file),
axmol.CCPluginError.ERROR_PATH_NOT_FOUND)
patten = re.compile(r'^target=(.+)')
for line in open(property_file):
str1 = line.replace(' ', '')
str2 = str1.replace('\t', '')
match = patten.match(str2)
if match is not None:
target = match.group(1)
target_num = self.get_api_level(target)
if target_num > 0:
return target_num
raise axmol.CCPluginError(MultiLanguage.get_string('COMPILE_ERROR_TARGET_NOT_FOUND_FMT', property_file),
axmol.CCPluginError.ERROR_PARSE_FILE)
# check the selected android platform
def check_android_platform(self, sdk_root, android_platform, proj_path):
ret = android_platform
if android_platform is None:
min_platform = self.get_target_config(proj_path)
# not specified platform, use the one in project.properties
ret = 'android-%d' % min_platform
ret_path = os.path.join(axmol.CMDRunner.convert_path_to_python(sdk_root), "platforms", ret)
if not os.path.isdir(ret_path):
raise axmol.CCPluginError(MultiLanguage.get_string('COMPILE_ERROR_NO_AP_IN_SDK_FMT', ret),
axmol.CCPluginError.ERROR_PATH_NOT_FOUND)
return ret
def gradle_build_apk(self, mode, android_platform, compile_obj):
# check the compileSdkVersion & buildToolsVersion
check_file = os.path.join(self.app_android_root, 'app', 'build.gradle')
f = open(check_file)
lines = f.readlines()
f.close()
compile_sdk_ver = None
build_tools_ver = None
compile_sdk_pattern = r'compileSdkVersion[ \t]+([\d]+)'
build_tools_pattern = r'buildToolsVersion[ \t]+"(.+)"'
for line in lines:
line_str = line.strip()
match1 = re.match(compile_sdk_pattern, line_str)
if match1:
compile_sdk_ver = match1.group(1)
match2 = re.match(build_tools_pattern, line_str)
if match2:
build_tools_ver = match2.group(1)
if compile_sdk_ver is not None:
# check the compileSdkVersion
check_folder_name = 'android-%s' % compile_sdk_ver
check_path = os.path.join(self.sdk_root, 'platforms', check_folder_name)
if not os.path.isdir(check_path):
axmol.Logging.warning(MultiLanguage.get_string('COMPILE_WARNING_COMPILE_SDK_FMT',
(compile_sdk_ver, check_path)))
if build_tools_ver is not None:
# check the buildToolsVersion
check_path = os.path.join(self.sdk_root, 'build-tools', build_tools_ver)
if not os.path.isdir(check_path):
axmol.Logging.warning(MultiLanguage.get_string('COMPILE_WARNING_BUILD_TOOLS_FMT',
(build_tools_ver, check_path)))
# invoke gradlew for gradle building
if axmol.os_is_win32():
gradle_path = os.path.join(self.app_android_root, 'gradlew.bat')
else:
gradle_path = os.path.join(self.app_android_root, 'gradlew')
if not os.path.isfile(gradle_path):
raise axmol.CCPluginError(MultiLanguage.get_string('COMPILE_ERROR_GRALEW_NOT_EXIST_FMT', gradle_path),
axmol.CCPluginError.ERROR_PATH_NOT_FOUND)
mode_str = 'Debug' if mode == 'debug' else 'Release'
cmd = '"%s" --parallel --info assemble%s' % (gradle_path, mode_str)
if self.gradle_support_ndk:
add_props = {
AndroidBuilder.GRADLE_PROP_BUILD_TYPE: self.build_type
}
if android_platform:
ret = self.check_android_platform(self.sdk_root, android_platform, None)
pattern = r'android-(\d+)'
match = re.match(pattern, ret)
if match:
add_props[AndroidBuilder.GRADLE_PROP_TARGET_VERSION] = (int)(match.group(1))
if self.app_abi:
add_props[AndroidBuilder.GRADLE_PROP_APP_ABI] = ':'.join(self.app_abi.split(' '))
if self._project._is_script_project():
if compile_obj._compile_script:
add_props[AndroidBuilder.GRADLE_PROP_COMPILE_SCRIPT] = 1
else:
add_props[AndroidBuilder.GRADLE_PROP_COMPILE_SCRIPT] = 0
if self._project._is_lua_project():
if compile_obj._lua_encrypt:
add_props[AndroidBuilder.GRADLE_PROP_LUA_ENCRYPT] = 1
add_props[AndroidBuilder.GRADLE_PROP_LUA_ENCRYPT_KEY] = compile_obj._lua_encrypt_key
add_props[AndroidBuilder.GRADLE_PROP_LUA_ENCRYPT_SIGN] = compile_obj._lua_encrypt_sign
for key in add_props.keys():
cmd += ' -P%s=%s' % (key, add_props[key])
self._run_cmd(cmd, cwd=self.app_android_root)
class LuaBuildArch:
UNKNOWN = -1
ONLY_BUILD_64BIT = 1
ONLY_BUILD_32BIT = 2
BUILD_32BIT_AND_64BIT = 3
def _do_get_build_arch(self, str):
# remove the '#' and the contents after it
str = str.split('#')[0]
build_64bit = str.find('arm64-v8a') != -1
# check if need to build other architecture
build_other_arch = False
other_archs = ('armeabi-v7a', 'x86') # other arches are not supported
for arch in other_archs:
if str.find(arch) != -1:
build_other_arch = True
break
if build_64bit or build_other_arch:
if build_64bit:
if build_other_arch:
print('build 64bit and 32bit')
return self.LuaBuildArch.BUILD_32BIT_AND_64BIT
else:
print('only build 64bit')
return self.LuaBuildArch.ONLY_BUILD_64BIT
else:
print('only build 32bit')
return self.LuaBuildArch.ONLY_BUILD_32BIT
return self.LuaBuildArch.UNKNOWN
# check if arm64-v8a is set in Application.mk
def _get_build_arch(self, param_of_appabi):
# get build type from parameter
if param_of_appabi:
return self._do_get_build_arch(param_of_appabi)
# get build type from Application.mk
applicationmk_path = os.path.join(self.app_android_root, "app/jni/Application.mk")
with open(applicationmk_path) as f:
for line in f:
if line.find('APP_ABI') == -1:
continue
build_arch = self._do_get_build_arch(line)
if build_arch != self.LuaBuildArch.UNKNOWN:
return build_arch
return self.LuaBuildArch.UNKNOWN
def do_build_apk(self, mode, no_apk, no_sign, output_dir, custom_step_args, android_platform, compile_obj):
assets_dir = os.path.join(self.app_android_root, "app", "assets")
project_name = None
setting_file = os.path.join(self.app_android_root, 'settings.gradle')
if os.path.isfile(setting_file):
# get project name from settings.gradle
f = open(setting_file)
lines = f.readlines()
f.close()
pattern = r"project\(':(.*)'\)\.projectDir[ \t]*=[ \t]*new[ \t]*File\(settingsDir, 'app'\)"
for line in lines:
line_str = line.strip()
match = re.match(pattern, line_str)
if match:
project_name = match.group(1)
break
if project_name is None:
# use default project name
project_name = 'app'
gen_apk_folder = os.path.join(self.app_android_root, 'app/build/outputs/apk', mode)
# gradle supports copy assets & compile scripts from engine 3.15
if not self.gradle_support_ndk:
# copy resources
self._copy_resources(custom_step_args, assets_dir)
# check the project config & compile the script files
if self._project._is_lua_project():
src_dir = os.path.join(assets_dir, 'src')
build_arch = self._get_build_arch(compile_obj.app_abi)
# only build 64bit
if build_arch == self.LuaBuildArch.ONLY_BUILD_64BIT:
dst_dir = os.path.join(assets_dir, 'src/64bit')
is_compiled = compile_obj.compile_lua_scripts(src_dir, dst_dir, True)
if is_compiled:
# remove unneeded lua files
compile_obj._remove_file_with_ext(src_dir, '.lua')
shutil.rmtree(os.path.join(src_dir, 'axmol'))
# only build 32bit
if build_arch == self.LuaBuildArch.ONLY_BUILD_32BIT:
# build 32-bit bytecode
compile_obj.compile_lua_scripts(src_dir, src_dir, False)
# build 32bit and 64bit
if build_arch == self.LuaBuildArch.BUILD_32BIT_AND_64BIT:
# build 64-bit bytecode
dst_dir = os.path.join(assets_dir, 'src/64bit')
compile_obj.compile_lua_scripts(src_dir, dst_dir, True)
# build 32-bit bytecode
compile_obj.compile_lua_scripts(src_dir, src_dir, False)
if build_arch == self.LuaBuildArch.UNKNOWN:
# haven't set APP_ABI in parameter and Application.mk, default build 32bit
compile_obj.compile_lua_scripts(src_dir, src_dir, False)
if self._project._is_js_project():
compile_obj.compile_js_scripts(assets_dir, assets_dir)
if not no_apk:
# gather the sign info if necessary
if not no_sign:
if mode == "release" and not self.has_keystore_in_signprops():
self._gather_sign_info()
# build apk
self.gradle_build_apk(mode, android_platform, compile_obj)
# copy the apk to output dir
if output_dir:
# support generate unsigned apk
if mode == "release" and no_sign:
apk_name = '%s-%s-unsigned.apk' % (project_name, mode)
else:
apk_name = '%s-%s.apk' % (project_name, mode)
gen_apk_path = os.path.join(gen_apk_folder, apk_name)
if not os.path.exists(output_dir):
os.makedirs(output_dir)
shutil.copy(gen_apk_path, output_dir)
axmol.Logging.info(MultiLanguage.get_string('COMPILE_INFO_MOVE_APK_FMT', output_dir))
if mode == "release" and not no_sign:
signed_name = "%s-%s-signed.apk" % (project_name, mode)
apk_path = os.path.join(output_dir, signed_name)
if os.path.exists(apk_path):
os.remove(apk_path)
os.rename(os.path.join(output_dir, apk_name), apk_path)
else:
apk_path = os.path.join(output_dir, apk_name)
return apk_path
else:
raise axmol.CCPluginError(MultiLanguage.get_string('COMPILE_ERROR_NOT_SPECIFY_OUTPUT'),
axmol.CCPluginError.ERROR_WRONG_ARGS)
def _gather_sign_info(self):
user_cfg = {}
# get the path of keystore file
while True:
inputed = self._get_user_input(MultiLanguage.get_string('COMPILE_TIP_INPUT_KEYSTORE'))
inputed = inputed.strip()
if not os.path.isabs(inputed):
start_path = os.path.join(self.app_android_root, 'app')
abs_path = os.path.join(start_path, inputed)
else:
abs_path = inputed
if os.path.isfile(abs_path):
user_cfg[self.key_store_str] = inputed.replace('\\', '/')
break
else:
axmol.Logging.warning(MultiLanguage.get_string('COMPILE_INFO_NOT_A_FILE'))
# get the alias of keystore file
user_cfg[self.key_alias_str] = self._get_user_input(MultiLanguage.get_string('COMPILE_TIP_INPUT_ALIAS'))
# get the keystore password
user_cfg[self.key_store_pass_str] = self._get_user_input(MultiLanguage.get_string('COMPILE_TIP_INPUT_KEY_PASS'))
# get the alias password
user_cfg[self.key_alias_pass_str] = self._get_user_input(MultiLanguage.get_string('COMPILE_TIP_INPUT_ALIAS_PASS'))
# write the config into ant.properties
self._write_sign_properties(user_cfg)
def _get_user_input(self, tip_msg):
axmol.Logging.warning(tip_msg)
ret = None
while True:
ret = axmol.get_input()
break
return ret
def _copy_resources(self, custom_step_args, assets_dir):
app_android_root = self.app_android_root
res_files = self.res_files
# remove app_android_root/assets if it exists
if os.path.isdir(assets_dir):
shutil.rmtree(assets_dir)
# generate parameters for custom steps
target_platform = axmol_project.Platforms.ANDROID
cur_custom_step_args = custom_step_args.copy()
cur_custom_step_args["assets-dir"] = assets_dir
# make dir
os.mkdir(assets_dir)
# invoke custom step : pre copy assets
self._project.invoke_custom_step_script(axmol_project.Project.CUSTOM_STEP_PRE_COPY_ASSETS, target_platform, cur_custom_step_args)
# copy resources
for cfg in res_files:
axmol.copy_files_with_config(cfg, app_android_root, assets_dir)
# invoke custom step : post copy assets
self._project.invoke_custom_step_script(axmol_project.Project.CUSTOM_STEP_POST_COPY_ASSETS, target_platform, cur_custom_step_args)
def get_apk_info(self):
manifest_path = os.path.join(self.app_android_root, 'app')
gradle_cfg_path = os.path.join(manifest_path, 'build.gradle')
package = None
if os.path.isfile(gradle_cfg_path):
# get package name from build.gradle
f = open(gradle_cfg_path)
for line in f.readlines():
line_str = line.strip()
pattern = r'applicationId[ \t]+"(.*)"'
match = re.match(pattern, line_str)
if match:
package = match.group(1)
break
if package is None:
# get package name from AndroidManifest.xml
package = self._xml_attr(manifest_path, 'AndroidManifest.xml', 'manifest', 'package')
activity_name = self._xml_attr(manifest_path, 'AndroidManifest.xml', 'activity', 'android:name')
if activity_name.startswith('.'):
activity = package + activity_name
else:
activity = activity_name
ret = (package, activity)
return ret