From 29a71edd76be09f2b612f5c75fa939b156751751 Mon Sep 17 00:00:00 2001 From: Aman Jain Date: Wed, 8 Jul 2020 10:36:00 -0400 Subject: [PATCH 1/7] Utility methods for writing files to Gradle project. --- platform/android/export/gradle_export_util.h | 101 +++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 platform/android/export/gradle_export_util.h diff --git a/platform/android/export/gradle_export_util.h b/platform/android/export/gradle_export_util.h new file mode 100644 index 00000000000..603ff5d0c2b --- /dev/null +++ b/platform/android/export/gradle_export_util.h @@ -0,0 +1,101 @@ +/*************************************************************************/ +/* gradle_export_util.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef GODOT_GRADLE_EXPORT_UTIL_H +#define GODOT_GRADLE_EXPORT_UTIL_H + +#include "core/io/zip_io.h" +#include "core/os/dir_access.h" +#include "core/os/file_access.h" +#include "core/os/os.h" +#include "editor/editor_export.h" + +// Utility method used to create a directory. +Error create_directory(const String &p_dir) { + if (!DirAccess::exists(p_dir)) { + DirAccess *filesystem_da = DirAccess::create(DirAccess::ACCESS_RESOURCES); + ERR_FAIL_COND_V_MSG(!filesystem_da, ERR_CANT_CREATE, "Cannot create directory '" + p_dir + "'."); + Error err = filesystem_da->make_dir_recursive(p_dir); + ERR_FAIL_COND_V_MSG(err, ERR_CANT_CREATE, "Cannot create directory '" + p_dir + "'."); + memdelete(filesystem_da); + } + return OK; +} + +// Implementation of EditorExportSaveSharedObject. +// This method will only be called as an input to export_project_files. +// This method lets the .so files for all ABIs to be copied +// into the gradle project from the .AAR file +Error ignore_so_file(void *p_userdata, const SharedObject &p_so) { + return OK; +} + +// Writes p_data into a file at p_path, creating directories if necessary. +// Note: this will overwrite the file at p_path if it already exists. +Error store_file_at_path(const String &p_path, const Vector &p_data) { + String dir = p_path.get_base_dir(); + Error err = create_directory(dir); + if (err != OK) { + return err; + } + FileAccess *fa = FileAccess::open(p_path, FileAccess::WRITE); + ERR_FAIL_COND_V_MSG(!fa, ERR_CANT_CREATE, "Cannot create file '" + p_path + "'."); + fa->store_buffer(p_data.ptr(), p_data.size()); + memdelete(fa); + return OK; +} + +// Writes string p_data into a file at p_path, creating directories if necessary. +// Note: this will overwrite the file at p_path if it already exists. +Error store_string_at_path(const String &p_path, const String &p_data) { + String dir = p_path.get_base_dir(); + Error err = create_directory(dir); + if (err != OK) { + return err; + } + FileAccess *fa = FileAccess::open(p_path, FileAccess::WRITE); + ERR_FAIL_COND_V_MSG(!fa, ERR_CANT_CREATE, "Cannot create file '" + p_path + "'."); + fa->store_string(p_data); + memdelete(fa); + return OK; +} + +// Implementation of EditorExportSaveFunction. +// This method will only be called as an input to export_project_files. +// It is used by the export_project_files method to save all the asset files into the gradle project. +// It's functionality mirrors that of the method save_apk_file. +// This method will be called ONLY when custom build is enabled. +Error rename_and_store_file_in_gradle_project(void *p_userdata, const String &p_path, const Vector &p_data, int p_file, int p_total) { + String dst_path = p_path.replace_first("res://", "res://android/build/assets/"); + Error err = store_file_at_path(dst_path, p_data); + return err; +} + +#endif //GODOT_GRADLE_EXPORT_UTIL_H From 824f0b05697b4177e0a9bd5834755d03e4ce1067 Mon Sep 17 00:00:00 2001 From: Aman Jain Date: Fri, 26 Jun 2020 14:58:16 -0400 Subject: [PATCH 2/7] Refactored permissions and command line flags into separate methods --- platform/android/export/export.cpp | 287 +++++++++++++++-------------- 1 file changed, 147 insertions(+), 140 deletions(-) diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp index f4adef1b948..be919013956 100644 --- a/platform/android/export/export.cpp +++ b/platform/android/export/export.cpp @@ -744,8 +744,40 @@ class EditorExportPlatformAndroid : public EditorExportPlatform { return OK; } - void _fix_manifest(const Ref &p_preset, Vector &p_manifest, bool p_give_internet) { + void _get_permissions(const Ref &p_preset, bool p_give_internet, Vector &r_permissions) { + const char **aperms = android_perms; + while (*aperms) { + bool enabled = p_preset->get("permissions/" + String(*aperms).to_lower()); + if (enabled) { + r_permissions.push_back("android.permission." + String(*aperms)); + } + aperms++; + } + PoolStringArray user_perms = p_preset->get("permissions/custom_permissions"); + for (int i = 0; i < user_perms.size(); i++) { + String user_perm = user_perms[i].strip_edges(); + if (!user_perm.empty()) { + r_permissions.push_back(user_perm); + } + } + if (p_give_internet) { + if (r_permissions.find("android.permission.INTERNET") == -1) { + r_permissions.push_back("android.permission.INTERNET"); + } + } + int xr_mode_index = p_preset->get("xr_features/xr_mode"); + if (xr_mode_index == 1 /* XRMode.OVR */) { + int hand_tracking_index = p_preset->get("xr_features/hand_tracking"); // 0: none, 1: optional, 2: required + if (hand_tracking_index > 0) { + if (r_permissions.find("com.oculus.permission.HAND_TRACKING") == -1) { + r_permissions.push_back("com.oculus.permission.HAND_TRACKING"); + } + } + } + } + + void _fix_manifest(const Ref &p_preset, Vector &p_manifest, bool p_give_internet) { // Leaving the unused types commented because looking these constants up // again later would be annoying // const int CHUNK_AXML_FILE = 0x00080003; @@ -791,29 +823,8 @@ class EditorExportPlatformAndroid : public EditorExportPlatform { String plugins_names = get_plugins_names(get_enabled_plugins(p_preset)); Vector perms; - - const char **aperms = android_perms; - while (*aperms) { - - bool enabled = p_preset->get("permissions/" + String(*aperms).to_lower()); - if (enabled) - perms.push_back("android.permission." + String(*aperms)); - aperms++; - } - - PoolStringArray user_perms = p_preset->get("permissions/custom_permissions"); - - for (int i = 0; i < user_perms.size(); i++) { - String user_perm = user_perms[i].strip_edges(); - if (!user_perm.empty()) { - perms.push_back(user_perm); - } - } - - if (p_give_internet) { - if (perms.find("android.permission.INTERNET") == -1) - perms.push_back("android.permission.INTERNET"); - } + // Write permissions into the perms variable. + _get_permissions(p_preset, p_give_internet, perms); while (ofs < (uint32_t)p_manifest.size()) { @@ -1000,10 +1011,6 @@ class EditorExportPlatformAndroid : public EditorExportPlatform { feature_names.push_back("oculus.software.handtracking"); feature_required_list.push_back(hand_tracking_index == 2); feature_versions.push_back(-1); // no version attribute should be added. - - if (perms.find("com.oculus.permission.HAND_TRACKING") == -1) { - perms.push_back("com.oculus.permission.HAND_TRACKING"); - } } } @@ -1289,7 +1296,6 @@ class EditorExportPlatformAndroid : public EditorExportPlatform { } static String _parse_string(const uint8_t *p_bytes, bool p_utf8) { - uint32_t offset = 0; uint32_t len = 0; @@ -1341,13 +1347,13 @@ class EditorExportPlatformAndroid : public EditorExportPlatform { return str; } } - void _fix_resources(const Ref &p_preset, Vector &p_manifest) { + void _fix_resources(const Ref &p_preset, Vector &r_manifest) { const int UTF8_FLAG = 0x00000100; - uint32_t string_block_len = decode_uint32(&p_manifest[16]); - uint32_t string_count = decode_uint32(&p_manifest[20]); - uint32_t string_flags = decode_uint32(&p_manifest[28]); + uint32_t string_block_len = decode_uint32(&r_manifest[16]); + uint32_t string_count = decode_uint32(&r_manifest[20]); + uint32_t string_flags = decode_uint32(&r_manifest[28]); const uint32_t string_table_begins = 40; Vector string_table; @@ -1356,10 +1362,10 @@ class EditorExportPlatformAndroid : public EditorExportPlatform { for (uint32_t i = 0; i < string_count; i++) { - uint32_t offset = decode_uint32(&p_manifest[string_table_begins + i * 4]); + uint32_t offset = decode_uint32(&r_manifest[string_table_begins + i * 4]); offset += string_table_begins + string_count * 4; - String str = _parse_string(&p_manifest[offset], string_flags & UTF8_FLAG); + String str = _parse_string(&r_manifest[offset], string_flags & UTF8_FLAG); if (str.begins_with("godot-project-name")) { @@ -1388,7 +1394,7 @@ class EditorExportPlatformAndroid : public EditorExportPlatform { for (uint32_t i = 0; i < string_table_begins; i++) { - ret.write[i] = p_manifest[i]; + ret.write[i] = r_manifest[i]; } int ofs = 0; @@ -1424,15 +1430,15 @@ class EditorExportPlatformAndroid : public EditorExportPlatform { //append the rest... int rest_from = 12 + string_block_len; int rest_to = ret.size(); - int rest_len = (p_manifest.size() - rest_from); - ret.resize(ret.size() + (p_manifest.size() - rest_from)); + int rest_len = (r_manifest.size() - rest_from); + ret.resize(ret.size() + (r_manifest.size() - rest_from)); for (int i = 0; i < rest_len; i++) { - ret.write[rest_to + i] = p_manifest[rest_from + i]; + ret.write[rest_to + i] = r_manifest[rest_from + i]; } //finally update the size encode_uint32(ret.size(), &ret.write[4]); - p_manifest = ret; + r_manifest = ret; //printf("end\n"); } @@ -2276,6 +2282,79 @@ public: return have_plugins_changed || first_build; } + Error get_command_line_flags(const Ref &p_preset, const String &p_path, int p_flags, Vector &r_command_line_flags) { + String cmdline = p_preset->get("command_line/extra_args"); + Vector command_line_strings = cmdline.strip_edges().split(" "); + for (int i = 0; i < command_line_strings.size(); i++) { + if (command_line_strings[i].strip_edges().length() == 0) { + command_line_strings.remove(i); + i--; + } + } + + gen_export_flags(command_line_strings, p_flags); + + bool apk_expansion = p_preset->get("apk_expansion/enable"); + if (apk_expansion) { + int version_code = p_preset->get("version/code"); + String package_name = p_preset->get("package/unique_name"); + String apk_file_name = "main." + itos(version_code) + "." + get_package_name(package_name) + ".obb"; + String fullpath = p_path.get_base_dir().plus_file(apk_file_name); + String apk_expansion_public_key = p_preset->get("apk_expansion/public_key"); + Error err = save_pack(p_preset, fullpath); + + if (err != OK) { + EditorNode::add_io_error("Could not write expansion package file: " + apk_file_name); + return err; + } + + command_line_strings.push_back("--use_apk_expansion"); + command_line_strings.push_back("--apk_expansion_md5"); + command_line_strings.push_back(FileAccess::get_md5(fullpath)); + command_line_strings.push_back("--apk_expansion_key"); + command_line_strings.push_back(apk_expansion_public_key.strip_edges()); + } + + int xr_mode_index = p_preset->get("xr_features/xr_mode"); + if (xr_mode_index == 1) { + command_line_strings.push_back("--xr_mode_ovr"); + } else { // XRMode.REGULAR is the default. + command_line_strings.push_back("--xr_mode_regular"); + } + + bool use_32_bit_framebuffer = p_preset->get("graphics/32_bits_framebuffer"); + if (use_32_bit_framebuffer) { + command_line_strings.push_back("--use_depth_32"); + } + + bool immersive = p_preset->get("screen/immersive_mode"); + if (immersive) { + command_line_strings.push_back("--use_immersive"); + } + + bool debug_opengl = p_preset->get("screen/opengl_debug"); + if (debug_opengl) { + command_line_strings.push_back("--debug_opengl"); + } + + if (command_line_strings.size()) { + r_command_line_flags.resize(4); + encode_uint32(command_line_strings.size(), &r_command_line_flags.write[0]); + for (int i = 0; i < command_line_strings.size(); i++) { + print_line(itos(i) + " param: " + command_line_strings[i]); + CharString command_line_argument = command_line_strings[i].utf8(); + int base = r_command_line_flags.size(); + int length = command_line_argument.length(); + if (length == 0) + continue; + r_command_line_flags.resize(base + 4 + length); + encode_uint32(length, &r_command_line_flags.write[base]); + copymem(&r_command_line_flags.write[base + 4], command_line_argument.ptr(), length); + } + } + return OK; + } + virtual Error export_project(const Ref &p_preset, bool p_debug, const String &p_path, int p_flags = 0) { ExportNotifier notifier(*this, p_preset, p_debug, p_path, p_flags); @@ -2416,20 +2495,13 @@ public: zipFile unaligned_apk = zipOpen2(tmp_unaligned_path.utf8().get_data(), APPEND_STATUS_CREATE, NULL, &io2); - bool use_32_fb = p_preset->get("graphics/32_bits_framebuffer"); - bool immersive = p_preset->get("screen/immersive_mode"); - bool debug_opengl = p_preset->get("screen/opengl_debug"); - bool _signed = p_preset->get("package/signed"); - - bool apk_expansion = p_preset->get("apk_expansion/enable"); - String cmdline = p_preset->get("command_line/extra_args"); - int version_code = p_preset->get("version/code"); String version_name = p_preset->get("version/name"); String package_name = p_preset->get("package/unique_name"); + bool apk_expansion = p_preset->get("apk_expansion/enable"); String apk_expansion_pkey = p_preset->get("apk_expansion/public_key"); String release_keystore = p_preset->get("keystore/release"); @@ -2564,105 +2636,42 @@ public: CLEANUP_AND_RETURN(ERR_SKIP); } Error err = OK; - Vector cl = cmdline.strip_edges().split(" "); - for (int i = 0; i < cl.size(); i++) { - if (cl[i].strip_edges().length() == 0) { - cl.remove(i); - i--; - } - } - - gen_export_flags(cl, p_flags); if (p_flags & DEBUG_FLAG_DUMB_CLIENT) { - APKExportData ed; ed.ep = &ep; ed.apk = unaligned_apk; err = export_project_files(p_preset, ignore_apk_file, &ed, save_apk_so); - } else { - //all files - - if (apk_expansion) { - - String apkfname = "main." + itos(version_code) + "." + get_package_name(package_name) + ".obb"; - String fullpath = p_path.get_base_dir().plus_file(apkfname); - err = save_pack(p_preset, fullpath); - - if (err != OK) { - unzClose(pkg); - EditorNode::add_io_error("Could not write expansion package file: " + apkfname); - - CLEANUP_AND_RETURN(ERR_SKIP); - } - - cl.push_back("--use_apk_expansion"); - cl.push_back("--apk_expansion_md5"); - cl.push_back(FileAccess::get_md5(fullpath)); - cl.push_back("--apk_expansion_key"); - cl.push_back(apk_expansion_pkey.strip_edges()); - - } else { - - APKExportData ed; - ed.ep = &ep; - ed.apk = unaligned_apk; - - err = export_project_files(p_preset, save_apk_file, &ed, save_apk_so); - } + } else if (!apk_expansion) { + APKExportData ed; + ed.ep = &ep; + ed.apk = unaligned_apk; + err = export_project_files(p_preset, save_apk_file, &ed, save_apk_so); } - int xr_mode_index = p_preset->get("xr_features/xr_mode"); - if (xr_mode_index == 1 /* XRMode.OVR */) { - cl.push_back("--xr_mode_ovr"); - } else { - // XRMode.REGULAR is the default. - cl.push_back("--xr_mode_regular"); + if (err != OK) { + unzClose(pkg); + EditorNode::add_io_error("Could not export project files"); + CLEANUP_AND_RETURN(ERR_SKIP); } - if (use_32_fb) - cl.push_back("--use_depth_32"); + Vector command_line_flags; + // Write command line flags into the command_line_flags variable. + err = get_command_line_flags(p_preset, p_path, p_flags, command_line_flags); - if (immersive) - cl.push_back("--use_immersive"); - - if (debug_opengl) - cl.push_back("--debug_opengl"); - - if (cl.size()) { - //add comandline - Vector clf; - clf.resize(4); - encode_uint32(cl.size(), &clf.write[0]); - for (int i = 0; i < cl.size(); i++) { - - print_line(itos(i) + " param: " + cl[i]); - CharString txt = cl[i].utf8(); - int base = clf.size(); - int length = txt.length(); - if (!length) - continue; - clf.resize(base + 4 + length); - encode_uint32(length, &clf.write[base]); - copymem(&clf.write[base + 4], txt.ptr(), length); - } - - zip_fileinfo zipfi = get_zip_fileinfo(); - - zipOpenNewFileInZip(unaligned_apk, - "assets/_cl_", - &zipfi, - NULL, - 0, - NULL, - 0, - NULL, - 0, // No compress (little size gain and potentially slower startup) - Z_DEFAULT_COMPRESSION); - - zipWriteInFileInZip(unaligned_apk, clf.ptr(), clf.size()); - zipCloseFileInZip(unaligned_apk); - } + zip_fileinfo zipfi = get_zip_fileinfo(); + zipOpenNewFileInZip(unaligned_apk, + "assets/_cl_", + &zipfi, + NULL, + 0, + NULL, + 0, + NULL, + 0, // No compress (little size gain and potentially slower startup) + Z_DEFAULT_COMPRESSION); + zipWriteInFileInZip(unaligned_apk, command_line_flags.ptr(), command_line_flags.size()); + zipCloseFileInZip(unaligned_apk); zipClose(unaligned_apk, NULL); unzClose(pkg); @@ -2813,12 +2822,10 @@ public: memset(extra + info.size_file_extra, 0, padding); - // write - zip_fileinfo zipfi = get_zip_fileinfo(); - + zip_fileinfo fileinfo = get_zip_fileinfo(); zipOpenNewFileInZip2(final_apk, file.utf8().get_data(), - &zipfi, + &fileinfo, extra, info.size_file_extra + padding, NULL, From ee9127bd202afe955f17fb5f8a1a0c635706a322 Mon Sep 17 00:00:00 2001 From: Aman Jain Date: Wed, 1 Jul 2020 11:06:50 -0400 Subject: [PATCH 3/7] Create strings.xml files to mimic behavior of _fix_resources method --- platform/android/export/export.cpp | 18 ++++++-- platform/android/export/gradle_export_util.h | 44 +++++++++++++++++++ .../values-ar/godot_project_name_string.xml} | 1 + .../values-bg/godot_project_name_string.xml} | 1 + .../values-ca/godot_project_name_string.xml} | 1 + .../values-cs/godot_project_name_string.xml} | 1 + .../values-da/godot_project_name_string.xml} | 1 + .../values-de/godot_project_name_string.xml} | 1 + .../values-el/godot_project_name_string.xml} | 1 + .../values-en/godot_project_name_string.xml} | 1 + .../godot_project_name_string.xml} | 1 + .../values-es/godot_project_name_string.xml} | 1 + .../values-fa/godot_project_name_string.xml | 5 +++ .../values-fi/godot_project_name_string.xml} | 1 + .../values-fr/godot_project_name_string.xml} | 1 + .../values-hi/godot_project_name_string.xml} | 1 + .../values-hr/godot_project_name_string.xml} | 1 + .../values-hu/godot_project_name_string.xml} | 1 + .../values-in/godot_project_name_string.xml | 5 +++ .../values-it/godot_project_name_string.xml} | 1 + .../values-iw/godot_project_name_string.xml | 5 +++ .../values-ja/godot_project_name_string.xml} | 1 + .../values-ko/godot_project_name_string.xml | 5 +++ .../values-lt/godot_project_name_string.xml} | 1 + .../values-lv/godot_project_name_string.xml} | 1 + .../values-nb/godot_project_name_string.xml} | 1 + .../values-nl/godot_project_name_string.xml} | 1 + .../values-pl/godot_project_name_string.xml} | 1 + .../values-pt/godot_project_name_string.xml} | 1 + .../values-ro/godot_project_name_string.xml} | 1 + .../values-ru/godot_project_name_string.xml} | 1 + .../values-sk/godot_project_name_string.xml} | 1 + .../values-sl/godot_project_name_string.xml} | 1 + .../values-sr/godot_project_name_string.xml} | 1 + .../values-sv/godot_project_name_string.xml} | 1 + .../values-th/godot_project_name_string.xml} | 1 + .../values-tl/godot_project_name_string.xml} | 1 + .../values-tr/godot_project_name_string.xml} | 1 + .../values-uk/godot_project_name_string.xml} | 1 + .../values-vi/godot_project_name_string.xml} | 1 + .../godot_project_name_string.xml} | 1 + .../godot_project_name_string.xml} | 1 + .../values-zh/godot_project_name_string.xml} | 1 + .../res/values/godot_project_name_string.xml | 5 +++ .../java/lib/res/values-fa/strings.xml | 1 - .../java/lib/res/values-in/strings.xml | 4 -- .../java/lib/res/values-iw/strings.xml | 4 -- .../java/lib/res/values-ko/strings.xml | 1 - 48 files changed, 121 insertions(+), 13 deletions(-) rename platform/android/java/{lib/res/values-ar/strings.xml => app/res/values-ar/godot_project_name_string.xml} (69%) rename platform/android/java/{lib/res/values-bg/strings.xml => app/res/values-bg/godot_project_name_string.xml} (69%) rename platform/android/java/{lib/res/values-ca/strings.xml => app/res/values-ca/godot_project_name_string.xml} (69%) rename platform/android/java/{lib/res/values-cs/strings.xml => app/res/values-cs/godot_project_name_string.xml} (69%) rename platform/android/java/{lib/res/values-da/strings.xml => app/res/values-da/godot_project_name_string.xml} (69%) rename platform/android/java/{lib/res/values-de/strings.xml => app/res/values-de/godot_project_name_string.xml} (69%) rename platform/android/java/{lib/res/values-el/strings.xml => app/res/values-el/godot_project_name_string.xml} (69%) rename platform/android/java/{lib/res/values-en/strings.xml => app/res/values-en/godot_project_name_string.xml} (69%) rename platform/android/java/{lib/res/values-es-rES/strings.xml => app/res/values-es-rES/godot_project_name_string.xml} (70%) rename platform/android/java/{lib/res/values-es/strings.xml => app/res/values-es/godot_project_name_string.xml} (69%) create mode 100644 platform/android/java/app/res/values-fa/godot_project_name_string.xml rename platform/android/java/{lib/res/values-fi/strings.xml => app/res/values-fi/godot_project_name_string.xml} (69%) rename platform/android/java/{lib/res/values-fr/strings.xml => app/res/values-fr/godot_project_name_string.xml} (69%) rename platform/android/java/{lib/res/values-hi/strings.xml => app/res/values-hi/godot_project_name_string.xml} (69%) rename platform/android/java/{lib/res/values-hr/strings.xml => app/res/values-hr/godot_project_name_string.xml} (69%) rename platform/android/java/{lib/res/values-hu/strings.xml => app/res/values-hu/godot_project_name_string.xml} (69%) create mode 100644 platform/android/java/app/res/values-in/godot_project_name_string.xml rename platform/android/java/{lib/res/values-it/strings.xml => app/res/values-it/godot_project_name_string.xml} (69%) create mode 100644 platform/android/java/app/res/values-iw/godot_project_name_string.xml rename platform/android/java/{lib/res/values-ja/strings.xml => app/res/values-ja/godot_project_name_string.xml} (69%) create mode 100644 platform/android/java/app/res/values-ko/godot_project_name_string.xml rename platform/android/java/{lib/res/values-lt/strings.xml => app/res/values-lt/godot_project_name_string.xml} (69%) rename platform/android/java/{lib/res/values-lv/strings.xml => app/res/values-lv/godot_project_name_string.xml} (69%) rename platform/android/java/{lib/res/values-nb/strings.xml => app/res/values-nb/godot_project_name_string.xml} (69%) rename platform/android/java/{lib/res/values-nl/strings.xml => app/res/values-nl/godot_project_name_string.xml} (69%) rename platform/android/java/{lib/res/values-pl/strings.xml => app/res/values-pl/godot_project_name_string.xml} (69%) rename platform/android/java/{lib/res/values-pt/strings.xml => app/res/values-pt/godot_project_name_string.xml} (69%) rename platform/android/java/{lib/res/values-ro/strings.xml => app/res/values-ro/godot_project_name_string.xml} (69%) rename platform/android/java/{lib/res/values-ru/strings.xml => app/res/values-ru/godot_project_name_string.xml} (69%) rename platform/android/java/{lib/res/values-sk/strings.xml => app/res/values-sk/godot_project_name_string.xml} (69%) rename platform/android/java/{lib/res/values-sl/strings.xml => app/res/values-sl/godot_project_name_string.xml} (69%) rename platform/android/java/{lib/res/values-sr/strings.xml => app/res/values-sr/godot_project_name_string.xml} (69%) rename platform/android/java/{lib/res/values-sv/strings.xml => app/res/values-sv/godot_project_name_string.xml} (69%) rename platform/android/java/{lib/res/values-th/strings.xml => app/res/values-th/godot_project_name_string.xml} (69%) rename platform/android/java/{lib/res/values-tl/strings.xml => app/res/values-tl/godot_project_name_string.xml} (69%) rename platform/android/java/{lib/res/values-tr/strings.xml => app/res/values-tr/godot_project_name_string.xml} (69%) rename platform/android/java/{lib/res/values-uk/strings.xml => app/res/values-uk/godot_project_name_string.xml} (69%) rename platform/android/java/{lib/res/values-vi/strings.xml => app/res/values-vi/godot_project_name_string.xml} (69%) rename platform/android/java/{lib/res/values-zh-rHK/strings.xml => app/res/values-zh-rHK/godot_project_name_string.xml} (70%) rename platform/android/java/{lib/res/values-zh-rTW/strings.xml => app/res/values-zh-rTW/godot_project_name_string.xml} (70%) rename platform/android/java/{lib/res/values-zh-rCN/strings.xml => app/res/values-zh/godot_project_name_string.xml} (69%) create mode 100644 platform/android/java/app/res/values/godot_project_name_string.xml delete mode 100644 platform/android/java/lib/res/values-in/strings.xml delete mode 100644 platform/android/java/lib/res/values-iw/strings.xml diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp index be919013956..fab96fe6844 100644 --- a/platform/android/export/export.cpp +++ b/platform/android/export/export.cpp @@ -43,6 +43,7 @@ #include "editor/editor_log.h" #include "editor/editor_node.h" #include "editor/editor_settings.h" +#include "platform/android/export/gradle_export_util.h" #include "platform/android/logo.gen.h" #include "platform/android/plugin/godot_plugin_config.h" #include "platform/android/run_icon.gen.h" @@ -2363,9 +2364,10 @@ public: EditorProgress ep("export", "Exporting for Android", 105, true); - if (bool(p_preset->get("custom_template/use_custom_build"))) { //custom build - //re-generate build.gradle and AndroidManifest.xml + bool use_custom_build = bool(p_preset->get("custom_template/use_custom_build")); + if (use_custom_build) { + //re-generate build.gradle and AndroidManifest.xml { //test that installed build version is alright FileAccessRef f = FileAccess::open("res://android/.build_version", FileAccess::READ); if (!f) { @@ -2378,6 +2380,14 @@ public: return ERR_UNCONFIGURED; } } + + // TODO: should we use "package/name" or "application/config/name"? + String project_name = get_project_name(p_preset->get("package/name")); + // instead of calling _fix_resources + Error err = _create_project_name_strings_files(p_preset, project_name); + if (err != OK) { + EditorNode::add_io_error("Unable to overwrite res://android/build/res/*.xml files with project name"); + } //build project if custom build is enabled String sdk_path = EDITOR_GET("export/android/custom_build_sdk_path"); @@ -2566,7 +2576,9 @@ public: } if (file == "resources.arsc") { - _fix_resources(p_preset, data); + if (!use_custom_build) { + _fix_resources(p_preset, data); + } } for (int i = 0; i < icon_densities_count; ++i) { diff --git a/platform/android/export/gradle_export_util.h b/platform/android/export/gradle_export_util.h index 603ff5d0c2b..622860c3071 100644 --- a/platform/android/export/gradle_export_util.h +++ b/platform/android/export/gradle_export_util.h @@ -37,6 +37,13 @@ #include "core/os/os.h" #include "editor/editor_export.h" +const String godot_project_name_xml_string = R"( + + + %s + +)"; + // Utility method used to create a directory. Error create_directory(const String &p_dir) { if (!DirAccess::exists(p_dir)) { @@ -98,4 +105,41 @@ Error rename_and_store_file_in_gradle_project(void *p_userdata, const String &p_ return err; } +// Creates strings.xml files inside the gradle project for different locales. +Error _create_project_name_strings_files(const Ref &p_preset, const String &project_name) { + // Stores the string into the default values directory. + String processed_default_xml_string = vformat(godot_project_name_xml_string, project_name.xml_escape(true)); + store_string_at_path("res://android/build/res/values/godot_project_name_string.xml", processed_default_xml_string); + + // Searches the Gradle project res/ directory to find all supported locales + DirAccessRef da = DirAccess::open("res://android/build/res"); + if (!da) { + return ERR_CANT_OPEN; + } + da->list_dir_begin(); + while (true) { + String file = da->get_next(); + if (file == "") { + break; + } + if (!file.begins_with("values-")) { + // NOTE: This assumes all directories that start with "values-" are for localization. + continue; + } + String locale = file.replace("values-", "").replace("-r", "_"); + String property_name = "application/config/name_" + locale; + String locale_directory = "res://android/build/res/" + file + "/godot_project_name_string.xml"; + if (ProjectSettings::get_singleton()->has_setting(property_name)) { + String locale_project_name = ProjectSettings::get_singleton()->get(property_name); + String processed_xml_string = vformat(godot_project_name_xml_string, locale_project_name.xml_escape(true)); + store_string_at_path(locale_directory, processed_xml_string); + } else { + // TODO: Once the legacy build system is deprecated we don't need to have xml files for this else branch + store_string_at_path(locale_directory, processed_default_xml_string); + } + } + da->list_dir_end(); + return OK; +} + #endif //GODOT_GRADLE_EXPORT_UTIL_H diff --git a/platform/android/java/lib/res/values-ar/strings.xml b/platform/android/java/app/res/values-ar/godot_project_name_string.xml similarity index 69% rename from platform/android/java/lib/res/values-ar/strings.xml rename to platform/android/java/app/res/values-ar/godot_project_name_string.xml index 77cd61ea51d..23aa5cf3e12 100644 --- a/platform/android/java/lib/res/values-ar/strings.xml +++ b/platform/android/java/app/res/values-ar/godot_project_name_string.xml @@ -1,4 +1,5 @@ + godot-project-name-ar diff --git a/platform/android/java/lib/res/values-bg/strings.xml b/platform/android/java/app/res/values-bg/godot_project_name_string.xml similarity index 69% rename from platform/android/java/lib/res/values-bg/strings.xml rename to platform/android/java/app/res/values-bg/godot_project_name_string.xml index 0f42d1f22b6..dbb7e04ae5c 100644 --- a/platform/android/java/lib/res/values-bg/strings.xml +++ b/platform/android/java/app/res/values-bg/godot_project_name_string.xml @@ -1,4 +1,5 @@ + godot-project-name-bg diff --git a/platform/android/java/lib/res/values-ca/strings.xml b/platform/android/java/app/res/values-ca/godot_project_name_string.xml similarity index 69% rename from platform/android/java/lib/res/values-ca/strings.xml rename to platform/android/java/app/res/values-ca/godot_project_name_string.xml index 291a44d5e2e..709d0961e6f 100644 --- a/platform/android/java/lib/res/values-ca/strings.xml +++ b/platform/android/java/app/res/values-ca/godot_project_name_string.xml @@ -1,4 +1,5 @@ + godot-project-name-ca diff --git a/platform/android/java/lib/res/values-cs/strings.xml b/platform/android/java/app/res/values-cs/godot_project_name_string.xml similarity index 69% rename from platform/android/java/lib/res/values-cs/strings.xml rename to platform/android/java/app/res/values-cs/godot_project_name_string.xml index 83ff73e12a3..ab248a8032a 100644 --- a/platform/android/java/lib/res/values-cs/strings.xml +++ b/platform/android/java/app/res/values-cs/godot_project_name_string.xml @@ -1,4 +1,5 @@ + godot-project-name-cs diff --git a/platform/android/java/lib/res/values-da/strings.xml b/platform/android/java/app/res/values-da/godot_project_name_string.xml similarity index 69% rename from platform/android/java/lib/res/values-da/strings.xml rename to platform/android/java/app/res/values-da/godot_project_name_string.xml index fd251a7c90f..906bf44f57a 100644 --- a/platform/android/java/lib/res/values-da/strings.xml +++ b/platform/android/java/app/res/values-da/godot_project_name_string.xml @@ -1,4 +1,5 @@ + godot-project-name-da diff --git a/platform/android/java/lib/res/values-de/strings.xml b/platform/android/java/app/res/values-de/godot_project_name_string.xml similarity index 69% rename from platform/android/java/lib/res/values-de/strings.xml rename to platform/android/java/app/res/values-de/godot_project_name_string.xml index f6e80b0b1ab..0cacb0175f8 100644 --- a/platform/android/java/lib/res/values-de/strings.xml +++ b/platform/android/java/app/res/values-de/godot_project_name_string.xml @@ -1,4 +1,5 @@ + godot-project-name-de diff --git a/platform/android/java/lib/res/values-el/strings.xml b/platform/android/java/app/res/values-el/godot_project_name_string.xml similarity index 69% rename from platform/android/java/lib/res/values-el/strings.xml rename to platform/android/java/app/res/values-el/godot_project_name_string.xml index adcdf13eb1c..047de616a54 100644 --- a/platform/android/java/lib/res/values-el/strings.xml +++ b/platform/android/java/app/res/values-el/godot_project_name_string.xml @@ -1,4 +1,5 @@ + godot-project-name-el diff --git a/platform/android/java/lib/res/values-en/strings.xml b/platform/android/java/app/res/values-en/godot_project_name_string.xml similarity index 69% rename from platform/android/java/lib/res/values-en/strings.xml rename to platform/android/java/app/res/values-en/godot_project_name_string.xml index 1b251c9ab65..bb3a5dbef37 100644 --- a/platform/android/java/lib/res/values-en/strings.xml +++ b/platform/android/java/app/res/values-en/godot_project_name_string.xml @@ -1,4 +1,5 @@ + godot-project-name-en diff --git a/platform/android/java/lib/res/values-es-rES/strings.xml b/platform/android/java/app/res/values-es-rES/godot_project_name_string.xml similarity index 70% rename from platform/android/java/lib/res/values-es-rES/strings.xml rename to platform/android/java/app/res/values-es-rES/godot_project_name_string.xml index b580a8270b1..d4537f34969 100644 --- a/platform/android/java/lib/res/values-es-rES/strings.xml +++ b/platform/android/java/app/res/values-es-rES/godot_project_name_string.xml @@ -1,4 +1,5 @@ + godot-project-name-es_ES diff --git a/platform/android/java/lib/res/values-es/strings.xml b/platform/android/java/app/res/values-es/godot_project_name_string.xml similarity index 69% rename from platform/android/java/lib/res/values-es/strings.xml rename to platform/android/java/app/res/values-es/godot_project_name_string.xml index 6aedd6870bc..d63a16022e9 100644 --- a/platform/android/java/lib/res/values-es/strings.xml +++ b/platform/android/java/app/res/values-es/godot_project_name_string.xml @@ -1,4 +1,5 @@ + godot-project-name-es diff --git a/platform/android/java/app/res/values-fa/godot_project_name_string.xml b/platform/android/java/app/res/values-fa/godot_project_name_string.xml new file mode 100644 index 00000000000..c303f13d5fb --- /dev/null +++ b/platform/android/java/app/res/values-fa/godot_project_name_string.xml @@ -0,0 +1,5 @@ + + + + godot-project-name-fa + diff --git a/platform/android/java/lib/res/values-fi/strings.xml b/platform/android/java/app/res/values-fi/godot_project_name_string.xml similarity index 69% rename from platform/android/java/lib/res/values-fi/strings.xml rename to platform/android/java/app/res/values-fi/godot_project_name_string.xml index bd7ef059ab6..bd6005574a0 100644 --- a/platform/android/java/lib/res/values-fi/strings.xml +++ b/platform/android/java/app/res/values-fi/godot_project_name_string.xml @@ -1,4 +1,5 @@ + godot-project-name-fi diff --git a/platform/android/java/lib/res/values-fr/strings.xml b/platform/android/java/app/res/values-fr/godot_project_name_string.xml similarity index 69% rename from platform/android/java/lib/res/values-fr/strings.xml rename to platform/android/java/app/res/values-fr/godot_project_name_string.xml index 03994099cf8..2e94b65a20d 100644 --- a/platform/android/java/lib/res/values-fr/strings.xml +++ b/platform/android/java/app/res/values-fr/godot_project_name_string.xml @@ -1,4 +1,5 @@ + godot-project-name-fr diff --git a/platform/android/java/lib/res/values-hi/strings.xml b/platform/android/java/app/res/values-hi/godot_project_name_string.xml similarity index 69% rename from platform/android/java/lib/res/values-hi/strings.xml rename to platform/android/java/app/res/values-hi/godot_project_name_string.xml index 60d3b468618..0bf75dcd563 100644 --- a/platform/android/java/lib/res/values-hi/strings.xml +++ b/platform/android/java/app/res/values-hi/godot_project_name_string.xml @@ -1,4 +1,5 @@ + godot-project-name-hi diff --git a/platform/android/java/lib/res/values-hr/strings.xml b/platform/android/java/app/res/values-hr/godot_project_name_string.xml similarity index 69% rename from platform/android/java/lib/res/values-hr/strings.xml rename to platform/android/java/app/res/values-hr/godot_project_name_string.xml index e552a6f6ec2..d3f75910f92 100644 --- a/platform/android/java/lib/res/values-hr/strings.xml +++ b/platform/android/java/app/res/values-hr/godot_project_name_string.xml @@ -1,4 +1,5 @@ + godot-project-name-hr diff --git a/platform/android/java/lib/res/values-hu/strings.xml b/platform/android/java/app/res/values-hu/godot_project_name_string.xml similarity index 69% rename from platform/android/java/lib/res/values-hu/strings.xml rename to platform/android/java/app/res/values-hu/godot_project_name_string.xml index ed21411acbd..012b613af3d 100644 --- a/platform/android/java/lib/res/values-hu/strings.xml +++ b/platform/android/java/app/res/values-hu/godot_project_name_string.xml @@ -1,4 +1,5 @@ + godot-project-name-hu diff --git a/platform/android/java/app/res/values-in/godot_project_name_string.xml b/platform/android/java/app/res/values-in/godot_project_name_string.xml new file mode 100644 index 00000000000..eedecff7a11 --- /dev/null +++ b/platform/android/java/app/res/values-in/godot_project_name_string.xml @@ -0,0 +1,5 @@ + + + + godot-project-name-in + diff --git a/platform/android/java/lib/res/values-it/strings.xml b/platform/android/java/app/res/values-it/godot_project_name_string.xml similarity index 69% rename from platform/android/java/lib/res/values-it/strings.xml rename to platform/android/java/app/res/values-it/godot_project_name_string.xml index 880b87e030b..7e734047c47 100644 --- a/platform/android/java/lib/res/values-it/strings.xml +++ b/platform/android/java/app/res/values-it/godot_project_name_string.xml @@ -1,4 +1,5 @@ + godot-project-name-it diff --git a/platform/android/java/app/res/values-iw/godot_project_name_string.xml b/platform/android/java/app/res/values-iw/godot_project_name_string.xml new file mode 100644 index 00000000000..03893f0cbb8 --- /dev/null +++ b/platform/android/java/app/res/values-iw/godot_project_name_string.xml @@ -0,0 +1,5 @@ + + + + godot-project-name-iw + diff --git a/platform/android/java/lib/res/values-ja/strings.xml b/platform/android/java/app/res/values-ja/godot_project_name_string.xml similarity index 69% rename from platform/android/java/lib/res/values-ja/strings.xml rename to platform/android/java/app/res/values-ja/godot_project_name_string.xml index 27d3ba521ee..f9dd4fab0d5 100644 --- a/platform/android/java/lib/res/values-ja/strings.xml +++ b/platform/android/java/app/res/values-ja/godot_project_name_string.xml @@ -1,4 +1,5 @@ + godot-project-name-ja diff --git a/platform/android/java/app/res/values-ko/godot_project_name_string.xml b/platform/android/java/app/res/values-ko/godot_project_name_string.xml new file mode 100644 index 00000000000..26f5dac176c --- /dev/null +++ b/platform/android/java/app/res/values-ko/godot_project_name_string.xml @@ -0,0 +1,5 @@ + + + + godot-project-name-ko + diff --git a/platform/android/java/lib/res/values-lt/strings.xml b/platform/android/java/app/res/values-lt/godot_project_name_string.xml similarity index 69% rename from platform/android/java/lib/res/values-lt/strings.xml rename to platform/android/java/app/res/values-lt/godot_project_name_string.xml index 10a93926db0..1c2e976cc50 100644 --- a/platform/android/java/lib/res/values-lt/strings.xml +++ b/platform/android/java/app/res/values-lt/godot_project_name_string.xml @@ -1,4 +1,5 @@ + godot-project-name-lt diff --git a/platform/android/java/lib/res/values-lv/strings.xml b/platform/android/java/app/res/values-lv/godot_project_name_string.xml similarity index 69% rename from platform/android/java/lib/res/values-lv/strings.xml rename to platform/android/java/app/res/values-lv/godot_project_name_string.xml index 4f230b97f87..b5e638ed736 100644 --- a/platform/android/java/lib/res/values-lv/strings.xml +++ b/platform/android/java/app/res/values-lv/godot_project_name_string.xml @@ -1,4 +1,5 @@ + godot-project-name-lv diff --git a/platform/android/java/lib/res/values-nb/strings.xml b/platform/android/java/app/res/values-nb/godot_project_name_string.xml similarity index 69% rename from platform/android/java/lib/res/values-nb/strings.xml rename to platform/android/java/app/res/values-nb/godot_project_name_string.xml index a85a3da39a4..e6d89d6a3f3 100644 --- a/platform/android/java/lib/res/values-nb/strings.xml +++ b/platform/android/java/app/res/values-nb/godot_project_name_string.xml @@ -1,4 +1,5 @@ + godot-project-name-nb diff --git a/platform/android/java/lib/res/values-nl/strings.xml b/platform/android/java/app/res/values-nl/godot_project_name_string.xml similarity index 69% rename from platform/android/java/lib/res/values-nl/strings.xml rename to platform/android/java/app/res/values-nl/godot_project_name_string.xml index c459f643976..93cb3a3878d 100644 --- a/platform/android/java/lib/res/values-nl/strings.xml +++ b/platform/android/java/app/res/values-nl/godot_project_name_string.xml @@ -1,4 +1,5 @@ + godot-project-name-nl diff --git a/platform/android/java/lib/res/values-pl/strings.xml b/platform/android/java/app/res/values-pl/godot_project_name_string.xml similarity index 69% rename from platform/android/java/lib/res/values-pl/strings.xml rename to platform/android/java/app/res/values-pl/godot_project_name_string.xml index 34a846cc78b..e5d6ac74fb4 100644 --- a/platform/android/java/lib/res/values-pl/strings.xml +++ b/platform/android/java/app/res/values-pl/godot_project_name_string.xml @@ -1,4 +1,5 @@ + godot-project-name-pl diff --git a/platform/android/java/lib/res/values-pt/strings.xml b/platform/android/java/app/res/values-pt/godot_project_name_string.xml similarity index 69% rename from platform/android/java/lib/res/values-pt/strings.xml rename to platform/android/java/app/res/values-pt/godot_project_name_string.xml index 5f7a875eb54..a4624655c5b 100644 --- a/platform/android/java/lib/res/values-pt/strings.xml +++ b/platform/android/java/app/res/values-pt/godot_project_name_string.xml @@ -1,4 +1,5 @@ + godot-project-name-pt diff --git a/platform/android/java/lib/res/values-ro/strings.xml b/platform/android/java/app/res/values-ro/godot_project_name_string.xml similarity index 69% rename from platform/android/java/lib/res/values-ro/strings.xml rename to platform/android/java/app/res/values-ro/godot_project_name_string.xml index de990e789be..19e026637e0 100644 --- a/platform/android/java/lib/res/values-ro/strings.xml +++ b/platform/android/java/app/res/values-ro/godot_project_name_string.xml @@ -1,4 +1,5 @@ + godot-project-name-ro diff --git a/platform/android/java/lib/res/values-ru/strings.xml b/platform/android/java/app/res/values-ru/godot_project_name_string.xml similarity index 69% rename from platform/android/java/lib/res/values-ru/strings.xml rename to platform/android/java/app/res/values-ru/godot_project_name_string.xml index 73d8a27443c..284845241f0 100644 --- a/platform/android/java/lib/res/values-ru/strings.xml +++ b/platform/android/java/app/res/values-ru/godot_project_name_string.xml @@ -1,4 +1,5 @@ + godot-project-name-ru diff --git a/platform/android/java/lib/res/values-sk/strings.xml b/platform/android/java/app/res/values-sk/godot_project_name_string.xml similarity index 69% rename from platform/android/java/lib/res/values-sk/strings.xml rename to platform/android/java/app/res/values-sk/godot_project_name_string.xml index 053960efeda..f8ab4a5b594 100644 --- a/platform/android/java/lib/res/values-sk/strings.xml +++ b/platform/android/java/app/res/values-sk/godot_project_name_string.xml @@ -1,4 +1,5 @@ + godot-project-name-sk diff --git a/platform/android/java/lib/res/values-sl/strings.xml b/platform/android/java/app/res/values-sl/godot_project_name_string.xml similarity index 69% rename from platform/android/java/lib/res/values-sl/strings.xml rename to platform/android/java/app/res/values-sl/godot_project_name_string.xml index d6dff8289a0..98bd53e8d21 100644 --- a/platform/android/java/lib/res/values-sl/strings.xml +++ b/platform/android/java/app/res/values-sl/godot_project_name_string.xml @@ -1,4 +1,5 @@ + godot-project-name-sl diff --git a/platform/android/java/lib/res/values-sr/strings.xml b/platform/android/java/app/res/values-sr/godot_project_name_string.xml similarity index 69% rename from platform/android/java/lib/res/values-sr/strings.xml rename to platform/android/java/app/res/values-sr/godot_project_name_string.xml index b7e79e89ea8..3f400f2a4d4 100644 --- a/platform/android/java/lib/res/values-sr/strings.xml +++ b/platform/android/java/app/res/values-sr/godot_project_name_string.xml @@ -1,4 +1,5 @@ + godot-project-name-sr diff --git a/platform/android/java/lib/res/values-sv/strings.xml b/platform/android/java/app/res/values-sv/godot_project_name_string.xml similarity index 69% rename from platform/android/java/lib/res/values-sv/strings.xml rename to platform/android/java/app/res/values-sv/godot_project_name_string.xml index 9436c3870ac..8670b7c9aaf 100644 --- a/platform/android/java/lib/res/values-sv/strings.xml +++ b/platform/android/java/app/res/values-sv/godot_project_name_string.xml @@ -1,4 +1,5 @@ + godot-project-name-sv diff --git a/platform/android/java/lib/res/values-th/strings.xml b/platform/android/java/app/res/values-th/godot_project_name_string.xml similarity index 69% rename from platform/android/java/lib/res/values-th/strings.xml rename to platform/android/java/app/res/values-th/godot_project_name_string.xml index 629d77b9c25..a1cc1bcd495 100644 --- a/platform/android/java/lib/res/values-th/strings.xml +++ b/platform/android/java/app/res/values-th/godot_project_name_string.xml @@ -1,4 +1,5 @@ + godot-project-name-th diff --git a/platform/android/java/lib/res/values-tl/strings.xml b/platform/android/java/app/res/values-tl/godot_project_name_string.xml similarity index 69% rename from platform/android/java/lib/res/values-tl/strings.xml rename to platform/android/java/app/res/values-tl/godot_project_name_string.xml index f8832d6b1fb..6d66d114cf4 100644 --- a/platform/android/java/lib/res/values-tl/strings.xml +++ b/platform/android/java/app/res/values-tl/godot_project_name_string.xml @@ -1,4 +1,5 @@ + godot-project-name-tl diff --git a/platform/android/java/lib/res/values-tr/strings.xml b/platform/android/java/app/res/values-tr/godot_project_name_string.xml similarity index 69% rename from platform/android/java/lib/res/values-tr/strings.xml rename to platform/android/java/app/res/values-tr/godot_project_name_string.xml index f3a8f57de46..ba3bd7de36f 100644 --- a/platform/android/java/lib/res/values-tr/strings.xml +++ b/platform/android/java/app/res/values-tr/godot_project_name_string.xml @@ -1,4 +1,5 @@ + godot-project-name-tr diff --git a/platform/android/java/lib/res/values-uk/strings.xml b/platform/android/java/app/res/values-uk/godot_project_name_string.xml similarity index 69% rename from platform/android/java/lib/res/values-uk/strings.xml rename to platform/android/java/app/res/values-uk/godot_project_name_string.xml index 8ba2bf86aa6..5f14ab25a08 100644 --- a/platform/android/java/lib/res/values-uk/strings.xml +++ b/platform/android/java/app/res/values-uk/godot_project_name_string.xml @@ -1,4 +1,5 @@ + godot-project-name-uk diff --git a/platform/android/java/lib/res/values-vi/strings.xml b/platform/android/java/app/res/values-vi/godot_project_name_string.xml similarity index 69% rename from platform/android/java/lib/res/values-vi/strings.xml rename to platform/android/java/app/res/values-vi/godot_project_name_string.xml index 8bf063ed823..295378e111d 100644 --- a/platform/android/java/lib/res/values-vi/strings.xml +++ b/platform/android/java/app/res/values-vi/godot_project_name_string.xml @@ -1,4 +1,5 @@ + godot-project-name-vi diff --git a/platform/android/java/lib/res/values-zh-rHK/strings.xml b/platform/android/java/app/res/values-zh-rHK/godot_project_name_string.xml similarity index 70% rename from platform/android/java/lib/res/values-zh-rHK/strings.xml rename to platform/android/java/app/res/values-zh-rHK/godot_project_name_string.xml index 8a6269da0f4..40ab0f285a3 100644 --- a/platform/android/java/lib/res/values-zh-rHK/strings.xml +++ b/platform/android/java/app/res/values-zh-rHK/godot_project_name_string.xml @@ -1,4 +1,5 @@ + godot-project-name-zh_HK diff --git a/platform/android/java/lib/res/values-zh-rTW/strings.xml b/platform/android/java/app/res/values-zh-rTW/godot_project_name_string.xml similarity index 70% rename from platform/android/java/lib/res/values-zh-rTW/strings.xml rename to platform/android/java/app/res/values-zh-rTW/godot_project_name_string.xml index b1bb39d5d64..095bd564e28 100644 --- a/platform/android/java/lib/res/values-zh-rTW/strings.xml +++ b/platform/android/java/app/res/values-zh-rTW/godot_project_name_string.xml @@ -1,4 +1,5 @@ + godot-project-name-zh_TW diff --git a/platform/android/java/lib/res/values-zh-rCN/strings.xml b/platform/android/java/app/res/values-zh/godot_project_name_string.xml similarity index 69% rename from platform/android/java/lib/res/values-zh-rCN/strings.xml rename to platform/android/java/app/res/values-zh/godot_project_name_string.xml index 6668c56bd91..31aa8c273ab 100644 --- a/platform/android/java/lib/res/values-zh-rCN/strings.xml +++ b/platform/android/java/app/res/values-zh/godot_project_name_string.xml @@ -1,4 +1,5 @@ + godot-project-name-zh diff --git a/platform/android/java/app/res/values/godot_project_name_string.xml b/platform/android/java/app/res/values/godot_project_name_string.xml new file mode 100644 index 00000000000..7ec27388966 --- /dev/null +++ b/platform/android/java/app/res/values/godot_project_name_string.xml @@ -0,0 +1,5 @@ + + + + godot-project-name + diff --git a/platform/android/java/lib/res/values-fa/strings.xml b/platform/android/java/lib/res/values-fa/strings.xml index f1e29013c46..60b01accf13 100644 --- a/platform/android/java/lib/res/values-fa/strings.xml +++ b/platform/android/java/lib/res/values-fa/strings.xml @@ -1,6 +1,5 @@ - godot-project-name-fa آیا می خواهید بر روی اتصال داده همراه دانلود را شروع کنید؟ بر اساس نوع سطح داده شما این ممکن است برای شما هزینه مالی داشته باشد. اگر نمی خواهید بر روی اتصال داده همراه دانلود را شروع کنید ، دانلود به صورت خودکار در زمان دسترسی به وای-فای شروع می شود. ادامه دانلود diff --git a/platform/android/java/lib/res/values-in/strings.xml b/platform/android/java/lib/res/values-in/strings.xml deleted file mode 100644 index 169b65decb7..00000000000 --- a/platform/android/java/lib/res/values-in/strings.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - godot-project-name-id - diff --git a/platform/android/java/lib/res/values-iw/strings.xml b/platform/android/java/lib/res/values-iw/strings.xml deleted file mode 100644 index b4826798c7e..00000000000 --- a/platform/android/java/lib/res/values-iw/strings.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - godot-project-name-he - diff --git a/platform/android/java/lib/res/values-ko/strings.xml b/platform/android/java/lib/res/values-ko/strings.xml index efc5c7e015d..7b62345977a 100644 --- a/platform/android/java/lib/res/values-ko/strings.xml +++ b/platform/android/java/lib/res/values-ko/strings.xml @@ -1,6 +1,5 @@ - godot-project-name-ko 모바일 네트워크를 사용하여 다운로드 하시겠습니까? 남은 데이터 사용량에 따라, 요금이 부과될 수 있습니다. 모바일 네트워크를 사용하여 다운로드 하지 않을 경우, 와이파이 연결이 가능할 때 자동적으로 다운로드가 이루어집니다. 다운로드 계속하기 From a323a1eacd88cc1a4a50e7cf15010c848a13644e Mon Sep 17 00:00:00 2001 From: Aman Jain Date: Wed, 22 Jul 2020 15:52:26 -0400 Subject: [PATCH 4/7] Added methods to copy project icon files to Gradle project --- platform/android/export/export.cpp | 153 +++++++++++++++++++---------- 1 file changed, 99 insertions(+), 54 deletions(-) diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp index fab96fe6844..412e4a12188 100644 --- a/platform/android/export/export.cpp +++ b/platform/android/export/export.cpp @@ -1443,23 +1443,81 @@ class EditorExportPlatformAndroid : public EditorExportPlatform { //printf("end\n"); } - void _process_launcher_icons(const String &p_processing_file_name, const Ref &p_source_image, const LauncherIcon p_icon, Vector &p_data) { - if (p_processing_file_name == p_icon.export_path) { - Ref working_image = p_source_image; + void _process_launcher_icons(const String &p_file_name, const Ref &p_source_image, int dimension, Vector &p_data) { + Ref working_image = p_source_image; - if (p_source_image->get_width() != p_icon.dimensions || p_source_image->get_height() != p_icon.dimensions) { - working_image = p_source_image->duplicate(); - working_image->resize(p_icon.dimensions, p_icon.dimensions, Image::Interpolation::INTERPOLATE_LANCZOS); + if (p_source_image->get_width() != dimension || p_source_image->get_height() != dimension) { + working_image = p_source_image->duplicate(); + working_image->resize(dimension, dimension, Image::Interpolation::INTERPOLATE_LANCZOS); + } + + PoolVector png_buffer; + Error err = PNGDriverCommon::image_to_png(working_image, png_buffer); + if (err == OK) { + p_data.resize(png_buffer.size()); + memcpy(p_data.ptrw(), png_buffer.read().ptr(), p_data.size()); + } else { + String err_str = String("Failed to convert resized icon (") + p_file_name + ") to png."; + WARN_PRINT(err_str.utf8().get_data()); + } + } + + void load_icon_refs(const Ref &p_preset, Ref &icon, Ref &foreground, Ref &background) { + String project_icon_path = ProjectSettings::get_singleton()->get("application/config/icon"); + + icon.instance(); + foreground.instance(); + background.instance(); + + // Regular icon: user selection -> project icon -> default. + String path = static_cast(p_preset->get(launcher_icon_option)).strip_edges(); + if (path.empty() || ImageLoader::load_image(path, icon) != OK) { + ImageLoader::load_image(project_icon_path, icon); + } + + // Adaptive foreground: user selection -> regular icon (user selection -> project icon -> default). + path = static_cast(p_preset->get(launcher_adaptive_icon_foreground_option)).strip_edges(); + if (path.empty() || ImageLoader::load_image(path, foreground) != OK) { + foreground = icon; + } + + // Adaptive background: user selection -> default. + path = static_cast(p_preset->get(launcher_adaptive_icon_background_option)).strip_edges(); + if (!path.empty()) { + ImageLoader::load_image(path, background); + } + } + + void store_image(const LauncherIcon launcher_icon, const Vector &data) { + String img_path = launcher_icon.export_path; + img_path = img_path.insert(0, "res://android/build/"); + store_file_at_path(img_path, data); + } + + void _copy_icons_to_gradle_project(const Ref &p_preset, const Ref &main_image, + const Ref &foreground, const Ref &background) { + // Prepare images to be resized for the icons. If some image ends up being uninitialized, + // the default image from the export template will be used. + + for (int i = 0; i < icon_densities_count; ++i) { + if (main_image.is_valid() && !main_image->empty()) { + Vector data; + _process_launcher_icons(launcher_icons[i].export_path, main_image, launcher_icons[i].dimensions, data); + store_image(launcher_icons[i], data); } - PoolVector png_buffer; - Error err = PNGDriverCommon::image_to_png(working_image, png_buffer); - if (err == OK) { - p_data.resize(png_buffer.size()); - memcpy(p_data.ptrw(), png_buffer.read().ptr(), p_data.size()); - } else { - String err_str = String("Failed to convert resized icon (") + p_processing_file_name + ") to png."; - WARN_PRINT(err_str.utf8().get_data()); + if (foreground.is_valid() && !foreground->empty()) { + Vector data; + _process_launcher_icons(launcher_adaptive_icon_foregrounds[i].export_path, foreground, + launcher_adaptive_icon_foregrounds[i].dimensions, data); + store_image(launcher_adaptive_icon_foregrounds[i], data); + } + + if (background.is_valid() && !background->empty()) { + Vector data; + _process_launcher_icons(launcher_adaptive_icon_backgrounds[i].export_path, background, + launcher_adaptive_icon_backgrounds[i].dimensions, data); + store_image(launcher_adaptive_icon_backgrounds[i], data); } } } @@ -2366,6 +2424,12 @@ public: bool use_custom_build = bool(p_preset->get("custom_template/use_custom_build")); + Ref main_image; + Ref foreground; + Ref background; + + load_icon_refs(p_preset, main_image, foreground, background); + if (use_custom_build) { //re-generate build.gradle and AndroidManifest.xml { //test that installed build version is alright @@ -2388,6 +2452,9 @@ public: if (err != OK) { EditorNode::add_io_error("Unable to overwrite res://android/build/res/*.xml files with project name"); } + // Copies the project icon files into the appropriate Gradle project directory + _copy_icons_to_gradle_project(p_preset, main_image, foreground, background); + //build project if custom build is enabled String sdk_path = EDITOR_GET("export/android/custom_build_sdk_path"); @@ -2520,34 +2587,7 @@ public: Vector enabled_abis = get_enabled_abis(p_preset); - String project_icon_path = ProjectSettings::get_singleton()->get("application/config/icon"); - // Prepare images to be resized for the icons. If some image ends up being uninitialized, the default image from the export template will be used. - Ref launcher_icon_image; - Ref launcher_adaptive_icon_foreground_image; - Ref launcher_adaptive_icon_background_image; - - launcher_icon_image.instance(); - launcher_adaptive_icon_foreground_image.instance(); - launcher_adaptive_icon_background_image.instance(); - - // Regular icon: user selection -> project icon -> default. - String path = static_cast(p_preset->get(launcher_icon_option)).strip_edges(); - if (path.empty() || ImageLoader::load_image(path, launcher_icon_image) != OK) { - ImageLoader::load_image(project_icon_path, launcher_icon_image); - } - - // Adaptive foreground: user selection -> regular icon (user selection -> project icon -> default). - path = static_cast(p_preset->get(launcher_adaptive_icon_foreground_option)).strip_edges(); - if (path.empty() || ImageLoader::load_image(path, launcher_adaptive_icon_foreground_image) != OK) { - launcher_adaptive_icon_foreground_image = launcher_icon_image; - } - - // Adaptive background: user selection -> default. - path = static_cast(p_preset->get(launcher_adaptive_icon_background_option)).strip_edges(); - if (!path.empty()) { - ImageLoader::load_image(path, launcher_adaptive_icon_background_image); - } Vector invalid_abis(enabled_abis); while (ret == UNZ_OK) { @@ -2575,21 +2615,26 @@ public: _fix_manifest(p_preset, data, p_flags & (DEBUG_FLAG_DUMB_CLIENT | DEBUG_FLAG_REMOTE_DEBUG)); } - if (file == "resources.arsc") { - if (!use_custom_build) { + if (!use_custom_build) { + if (file == "resources.arsc") { _fix_resources(p_preset, data); } - } - - for (int i = 0; i < icon_densities_count; ++i) { - if (launcher_icon_image.is_valid() && !launcher_icon_image->empty()) { - _process_launcher_icons(file, launcher_icon_image, launcher_icons[i], data); - } - if (launcher_adaptive_icon_foreground_image.is_valid() && !launcher_adaptive_icon_foreground_image->empty()) { - _process_launcher_icons(file, launcher_adaptive_icon_foreground_image, launcher_adaptive_icon_foregrounds[i], data); - } - if (launcher_adaptive_icon_background_image.is_valid() && !launcher_adaptive_icon_background_image->empty()) { - _process_launcher_icons(file, launcher_adaptive_icon_background_image, launcher_adaptive_icon_backgrounds[i], data); + for (int i = 0; i < icon_densities_count; ++i) { + if (main_image.is_valid() && !main_image->empty()) { + if (file == launcher_icons[i].export_path) { + _process_launcher_icons(file, main_image, launcher_icons[i].dimensions, data); + } + } + if (foreground.is_valid() && !foreground->empty()) { + if (file == launcher_adaptive_icon_foregrounds[i].export_path) { + _process_launcher_icons(file, foreground, launcher_adaptive_icon_foregrounds[i].dimensions, data); + } + } + if (background.is_valid() && !background->empty()) { + if (file == launcher_adaptive_icon_backgrounds[i].export_path) { + _process_launcher_icons(file, background, launcher_adaptive_icon_backgrounds[i].dimensions, data); + } + } } } From 452af201b0c35ba315d50080dbba3534d13d5d3f Mon Sep 17 00:00:00 2001 From: Aman Jain Date: Thu, 23 Jul 2020 12:17:02 -0400 Subject: [PATCH 5/7] Write an AndroidManifest.xml file to be merged with app module's manifest. --- platform/android/export/export.cpp | 42 ++++++-- platform/android/export/gradle_export_util.h | 100 +++++++++++++++++++ platform/android/java/app/build.gradle | 2 + platform/android/java/app/config.gradle | 16 +++ 4 files changed, 153 insertions(+), 7 deletions(-) diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp index 412e4a12188..bf2104648a1 100644 --- a/platform/android/export/export.cpp +++ b/platform/android/export/export.cpp @@ -778,6 +778,30 @@ class EditorExportPlatformAndroid : public EditorExportPlatform { } } + void _write_tmp_manifest(const Ref &p_preset, bool p_give_internet, bool p_debug) { + String manifest_text = + "\n" + "\n"; + + manifest_text += _get_screen_sizes_tag(p_preset); + manifest_text += _get_gles_tag(); + + Vector perms; + _get_permissions(p_preset, p_give_internet, perms); + for (int i = 0; i < perms.size(); i++) { + manifest_text += vformat(" \n", perms.get(i)); + } + + manifest_text += _get_xr_features_tag(p_preset); + manifest_text += _get_instrumentation_tag(p_preset); + String plugins_names = get_plugins_names(get_enabled_plugins(p_preset)); + manifest_text += _get_application_tag(p_preset, plugins_names); + manifest_text += "\n"; + String manifest_path = vformat("res://android/build/src/%s/AndroidManifest.xml", (p_debug ? "debug" : "release")); + store_string_at_path(manifest_path, manifest_text); + } + void _fix_manifest(const Ref &p_preset, Vector &p_manifest, bool p_give_internet) { // Leaving the unused types commented because looking these constants up // again later would be annoying @@ -2423,6 +2447,7 @@ public: EditorProgress ep("export", "Exporting for Android", 105, true); bool use_custom_build = bool(p_preset->get("custom_template/use_custom_build")); + bool p_give_internet = p_flags & (DEBUG_FLAG_DUMB_CLIENT | DEBUG_FLAG_REMOTE_DEBUG); Ref main_image; Ref foreground; @@ -2452,9 +2477,10 @@ public: if (err != OK) { EditorNode::add_io_error("Unable to overwrite res://android/build/res/*.xml files with project name"); } - // Copies the project icon files into the appropriate Gradle project directory + // Copies the project icon files into the appropriate Gradle project directory. _copy_icons_to_gradle_project(p_preset, main_image, foreground, background); - + // Write an AndroidManifest.xml file into the Gradle project directory. + _write_tmp_manifest(p_preset, p_give_internet, p_debug); //build project if custom build is enabled String sdk_path = EDITOR_GET("export/android/custom_build_sdk_path"); @@ -2476,6 +2502,8 @@ public: build_command = build_path.plus_file(build_command); String package_name = get_package_name(p_preset->get("package/unique_name")); + String version_code = itos(p_preset->get("version/code")); + String version_name = p_preset->get("version/name"); Vector enabled_plugins = get_enabled_plugins(p_preset); String local_plugins_binaries = get_plugins_binaries(BINARY_TYPE_LOCAL, enabled_plugins); @@ -2489,6 +2517,8 @@ public: } cmdline.push_back("build"); cmdline.push_back("-Pexport_package_name=" + package_name); // argument to specify the package name. + cmdline.push_back("-Pexport_version_code=" + version_code); // argument to specify the version code. + cmdline.push_back("-Pexport_version_name=" + version_name); // argument to specify the version name. cmdline.push_back("-Pplugins_local_binaries=" + local_plugins_binaries); // argument to specify the list of plugins local dependencies. cmdline.push_back("-Pplugins_remote_binaries=" + remote_plugins_binaries); // argument to specify the list of plugins remote dependencies. cmdline.push_back("-Pplugins_maven_repos=" + custom_maven_repos); // argument to specify the list of custom maven repos for the plugins dependencies. @@ -2610,12 +2640,10 @@ public: unzCloseCurrentFile(pkg); //write - - if (file == "AndroidManifest.xml") { - _fix_manifest(p_preset, data, p_flags & (DEBUG_FLAG_DUMB_CLIENT | DEBUG_FLAG_REMOTE_DEBUG)); - } - if (!use_custom_build) { + if (file == "AndroidManifest.xml") { + _fix_manifest(p_preset, data, p_give_internet); + } if (file == "resources.arsc") { _fix_resources(p_preset, data); } diff --git a/platform/android/export/gradle_export_util.h b/platform/android/export/gradle_export_util.h index 622860c3071..209a664f8f9 100644 --- a/platform/android/export/gradle_export_util.h +++ b/platform/android/export/gradle_export_util.h @@ -142,4 +142,104 @@ Error _create_project_name_strings_files(const Ref &p_preset return OK; } +String bool_to_string(bool v) { + return v ? "true" : "false"; +} + +String _get_gles_tag() { + bool min_gles3 = ProjectSettings::get_singleton()->get("rendering/quality/driver/driver_name") == "GLES3" && + !ProjectSettings::get_singleton()->get("rendering/quality/driver/fallback_to_gles2"); + return min_gles3 ? " \n" : ""; +} + +String _get_screen_sizes_tag(const Ref &p_preset) { + String manifest_screen_sizes = " get(feature_name)); + String xml_entry = vformat("\n android:%sScreens=\"%s\"", sizes[i], feature_support); + manifest_screen_sizes += xml_entry; + } + manifest_screen_sizes += " />\n"; + return manifest_screen_sizes; +} + +String _get_xr_features_tag(const Ref &p_preset) { + String manifest_xr_features; + bool uses_xr = (int)(p_preset->get("xr_features/xr_mode")) == 1; + if (uses_xr) { + int dof_index = p_preset->get("xr_features/degrees_of_freedom"); // 0: none, 1: 3dof and 6dof, 2: 6dof + if (dof_index == 1) { + manifest_xr_features += " \n"; + } else if (dof_index == 2) { + manifest_xr_features += " \n"; + } + int hand_tracking_index = p_preset->get("xr_features/hand_tracking"); // 0: none, 1: optional, 2: required + if (hand_tracking_index == 1) { + manifest_xr_features += " \n"; + } else if (hand_tracking_index == 2) { + manifest_xr_features += " \n"; + } + } + return manifest_xr_features; +} + +String _get_instrumentation_tag(const Ref &p_preset) { + String package_name = p_preset->get("package/unique_name"); + String manifest_instrumentation_text = vformat( + " \n", + package_name); + return manifest_instrumentation_text; +} + +String _get_plugins_tag(const String &plugins_names) { + if (!plugins_names.empty()) { + return vformat(" \n", plugins_names); + } else { + return " \n"; + } +} + +String _get_activity_tag(const Ref &p_preset) { + bool uses_xr = (int)(p_preset->get("xr_features/xr_mode")) == 1; + String orientation = (int)(p_preset->get("screen/orientation")) == 1 ? "portrait" : "landscape"; + String manifest_activity_text = vformat( + " \n", + orientation); + if (uses_xr) { + String focus_awareness = bool_to_string(p_preset->get("xr_features/focus_awareness")); + manifest_activity_text += vformat(" \n", focus_awareness); + } else { + manifest_activity_text += " \n"; + } + manifest_activity_text += " \n"; + return manifest_activity_text; +} + +String _get_application_tag(const Ref &p_preset, const String &plugins_names) { + bool uses_xr = (int)(p_preset->get("xr_features/xr_mode")) == 1; + String manifest_application_text = + " )\n\n" + " \n"; + + manifest_application_text += _get_plugins_tag(plugins_names); + if (uses_xr) { + manifest_application_text += " \n"; + } + manifest_application_text += _get_activity_tag(p_preset); + manifest_application_text += " \n"; + return manifest_application_text; +} + #endif //GODOT_GRADLE_EXPORT_UTIL_H diff --git a/platform/android/java/app/build.gradle b/platform/android/java/app/build.gradle index f1fd716cb49..68c18935d81 100644 --- a/platform/android/java/app/build.gradle +++ b/platform/android/java/app/build.gradle @@ -94,6 +94,8 @@ android { // Feel free to modify the application id to your own. applicationId getExportPackageName() + versionCode getExportVersionCode() + versionName getExportVersionName() minSdkVersion versions.minSdk targetSdkVersion versions.targetSdk //CHUNK_ANDROID_DEFAULTCONFIG_BEGIN diff --git a/platform/android/java/app/config.gradle b/platform/android/java/app/config.gradle index acfdef531e9..7d5d2381001 100644 --- a/platform/android/java/app/config.gradle +++ b/platform/android/java/app/config.gradle @@ -28,6 +28,22 @@ ext.getExportPackageName = { -> return appId } +ext.getExportVersionCode = { -> + String versionCode = project.hasProperty("export_version_code") ? project.property("export_version_code") : "" + if (versionCode == null || versionCode.isEmpty()) { + versionCode = "1" + } + return Integer.parseInt(versionCode) +} + +ext.getExportVersionName = { -> + String versionName = project.hasProperty("export_version_name") ? project.property("export_version_name") : "" + if (versionName == null || versionName.isEmpty()) { + versionName = "1.0" + } + return versionName +} + final String PLUGIN_VALUE_SEPARATOR_REGEX = "\\|" /** From 654342d3bf8ac5e3b4beb00f6ffb8400c0478dcf Mon Sep 17 00:00:00 2001 From: Aman Jain Date: Mon, 27 Jul 2020 11:14:16 -0400 Subject: [PATCH 6/7] refactor apk signing into it's own method --- platform/android/export/export.cpp | 177 +++++++++++++++-------------- 1 file changed, 92 insertions(+), 85 deletions(-) diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp index bf2104648a1..bac8ff98bfb 100644 --- a/platform/android/export/export.cpp +++ b/platform/android/export/export.cpp @@ -2438,6 +2438,95 @@ public: return OK; } + Error sign_apk(const Ref &p_preset, bool p_debug, String apk_path, EditorProgress ep) { + String release_keystore = p_preset->get("keystore/release"); + String release_username = p_preset->get("keystore/release_user"); + String release_password = p_preset->get("keystore/release_password"); + + String jarsigner = EditorSettings::get_singleton()->get("export/android/jarsigner"); + if (!FileAccess::exists(jarsigner)) { + EditorNode::add_io_error("'jarsigner' could not be found.\nPlease supply a path in the Editor Settings.\nThe resulting APK is unsigned."); + return OK; + } + + String keystore; + String password; + String user; + if (p_debug) { + + keystore = p_preset->get("keystore/debug"); + password = p_preset->get("keystore/debug_password"); + user = p_preset->get("keystore/debug_user"); + + if (keystore.empty()) { + + keystore = EditorSettings::get_singleton()->get("export/android/debug_keystore"); + password = EditorSettings::get_singleton()->get("export/android/debug_keystore_pass"); + user = EditorSettings::get_singleton()->get("export/android/debug_keystore_user"); + } + + if (ep.step("Signing debug APK...", 103)) { + return ERR_SKIP; + } + + } else { + keystore = release_keystore; + password = release_password; + user = release_username; + + if (ep.step("Signing release APK...", 103)) { + return ERR_SKIP; + } + } + + if (!FileAccess::exists(keystore)) { + EditorNode::add_io_error("Could not find keystore, unable to export."); + return ERR_FILE_CANT_OPEN; + } + + List args; + args.push_back("-digestalg"); + args.push_back("SHA-256"); + args.push_back("-sigalg"); + args.push_back("SHA256withRSA"); + String tsa_url = EditorSettings::get_singleton()->get("export/android/timestamping_authority_url"); + if (tsa_url != "") { + args.push_back("-tsa"); + args.push_back(tsa_url); + } + args.push_back("-verbose"); + args.push_back("-keystore"); + args.push_back(keystore); + args.push_back("-storepass"); + args.push_back(password); + args.push_back(apk_path); + args.push_back(user); + int retval; + OS::get_singleton()->execute(jarsigner, args, true, NULL, NULL, &retval); + if (retval) { + EditorNode::add_io_error("'jarsigner' returned with error #" + itos(retval)); + return ERR_CANT_CREATE; + } + + if (ep.step("Verifying APK...", 104)) { + return ERR_SKIP; + } + + args.clear(); + args.push_back("-verify"); + args.push_back("-keystore"); + args.push_back(keystore); + args.push_back(apk_path); + args.push_back("-verbose"); + + OS::get_singleton()->execute(jarsigner, args, true, NULL, NULL, &retval); + if (retval) { + EditorNode::add_io_error("'jarsigner' verification of APK failed. Make sure to use a jarsigner from OpenJDK 8."); + return ERR_CANT_CREATE; + } + return OK; + } + virtual Error export_project(const Ref &p_preset, bool p_debug, const String &p_path, int p_flags = 0) { ExportNotifier notifier(*this, p_preset, p_debug, p_path, p_flags); @@ -2611,10 +2700,6 @@ public: bool apk_expansion = p_preset->get("apk_expansion/enable"); String apk_expansion_pkey = p_preset->get("apk_expansion/public_key"); - String release_keystore = p_preset->get("keystore/release"); - String release_username = p_preset->get("keystore/release_user"); - String release_password = p_preset->get("keystore/release_password"); - Vector enabled_abis = get_enabled_abis(p_preset); // Prepare images to be resized for the icons. If some image ends up being uninitialized, the default image from the export template will be used. @@ -2766,87 +2851,9 @@ public: } if (_signed) { - - String jarsigner = EditorSettings::get_singleton()->get("export/android/jarsigner"); - if (!FileAccess::exists(jarsigner)) { - EditorNode::add_io_error("'jarsigner' could not be found.\nPlease supply a path in the Editor Settings.\nThe resulting APK is unsigned."); - CLEANUP_AND_RETURN(OK); - } - - String keystore; - String password; - String user; - if (p_debug) { - - keystore = p_preset->get("keystore/debug"); - password = p_preset->get("keystore/debug_password"); - user = p_preset->get("keystore/debug_user"); - - if (keystore.empty()) { - - keystore = EditorSettings::get_singleton()->get("export/android/debug_keystore"); - password = EditorSettings::get_singleton()->get("export/android/debug_keystore_pass"); - user = EditorSettings::get_singleton()->get("export/android/debug_keystore_user"); - } - - if (ep.step("Signing debug APK...", 103)) { - CLEANUP_AND_RETURN(ERR_SKIP); - } - - } else { - keystore = release_keystore; - password = release_password; - user = release_username; - - if (ep.step("Signing release APK...", 103)) { - CLEANUP_AND_RETURN(ERR_SKIP); - } - } - - if (!FileAccess::exists(keystore)) { - EditorNode::add_io_error("Could not find keystore, unable to export."); - CLEANUP_AND_RETURN(ERR_FILE_CANT_OPEN); - } - - List args; - args.push_back("-digestalg"); - args.push_back("SHA-256"); - args.push_back("-sigalg"); - args.push_back("SHA256withRSA"); - String tsa_url = EditorSettings::get_singleton()->get("export/android/timestamping_authority_url"); - if (tsa_url != "") { - args.push_back("-tsa"); - args.push_back(tsa_url); - } - args.push_back("-verbose"); - args.push_back("-keystore"); - args.push_back(keystore); - args.push_back("-storepass"); - args.push_back(password); - args.push_back(tmp_unaligned_path); - args.push_back(user); - int retval; - OS::get_singleton()->execute(jarsigner, args, true, NULL, NULL, &retval); - if (retval) { - EditorNode::add_io_error("'jarsigner' returned with error #" + itos(retval)); - CLEANUP_AND_RETURN(ERR_CANT_CREATE); - } - - if (ep.step("Verifying APK...", 104)) { - CLEANUP_AND_RETURN(ERR_SKIP); - } - - args.clear(); - args.push_back("-verify"); - args.push_back("-keystore"); - args.push_back(keystore); - args.push_back(tmp_unaligned_path); - args.push_back("-verbose"); - - OS::get_singleton()->execute(jarsigner, args, true, NULL, NULL, &retval); - if (retval) { - EditorNode::add_io_error("'jarsigner' verification of APK failed. Make sure to use a jarsigner from OpenJDK 8."); - CLEANUP_AND_RETURN(ERR_CANT_CREATE); + err = sign_apk(p_preset, p_debug, tmp_unaligned_path, ep); + if (err != OK) { + CLEANUP_AND_RETURN(err); } } From 59da1db188baa778e29fc484e90197da2a9e1049 Mon Sep 17 00:00:00 2001 From: Aman Jain Date: Thu, 23 Jul 2020 12:17:02 -0400 Subject: [PATCH 7/7] Add 'Export App Bundle' to Android Export Options --- platform/android/export/export.cpp | 271 ++++++++++++++++-------- platform/android/java/app/build.gradle | 29 +++ platform/android/java/app/config.gradle | 31 +++ 3 files changed, 237 insertions(+), 94 deletions(-) diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp index bac8ff98bfb..7d36e24e871 100644 --- a/platform/android/export/export.cpp +++ b/platform/android/export/export.cpp @@ -1591,6 +1591,7 @@ public: r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/debug", PROPERTY_HINT_GLOBAL_FILE, "*.apk"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/release", PROPERTY_HINT_GLOBAL_FILE, "*.apk"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "custom_template/use_custom_build"), false)); + r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "custom_template/export_format", PROPERTY_HINT_ENUM, "Export APK,Export AAB"), 0)); Vector plugins_configs = get_plugins(); for (int i = 0; i < plugins_configs.size(); i++) { @@ -2050,6 +2051,13 @@ public: } } + if (int(p_preset->get("custom_template/export_format")) == 1 && /*AAB*/ + !bool(p_preset->get("custom_template/use_custom_build"))) { + valid = false; + err += TTR("\"Export AAB\" is only valid when \"Use Custom Build\" is enabled."); + err += "\n"; + } + r_error = err; return valid; } @@ -2057,6 +2065,7 @@ public: virtual List get_binary_extensions(const Ref &p_preset) const { List list; list.push_back("apk"); + list.push_back("aab"); return list; } @@ -2365,7 +2374,21 @@ public: return have_plugins_changed || first_build; } - Error get_command_line_flags(const Ref &p_preset, const String &p_path, int p_flags, Vector &r_command_line_flags) { + String get_apk_expansion_fullpath(const Ref &p_preset, const String &p_path) { + int version_code = p_preset->get("version/code"); + String package_name = p_preset->get("package/unique_name"); + String apk_file_name = "main." + itos(version_code) + "." + get_package_name(package_name) + ".obb"; + String fullpath = p_path.get_base_dir().plus_file(apk_file_name); + return fullpath; + } + + Error save_apk_expansion_file(const Ref &p_preset, const String &p_path) { + String fullpath = get_apk_expansion_fullpath(p_preset, p_path); + Error err = save_pack(p_preset, fullpath); + return err; + } + + void get_command_line_flags(const Ref &p_preset, const String &p_path, int p_flags, Vector &r_command_line_flags) { String cmdline = p_preset->get("command_line/extra_args"); Vector command_line_strings = cmdline.strip_edges().split(" "); for (int i = 0; i < command_line_strings.size(); i++) { @@ -2379,17 +2402,8 @@ public: bool apk_expansion = p_preset->get("apk_expansion/enable"); if (apk_expansion) { - int version_code = p_preset->get("version/code"); - String package_name = p_preset->get("package/unique_name"); - String apk_file_name = "main." + itos(version_code) + "." + get_package_name(package_name) + ".obb"; - String fullpath = p_path.get_base_dir().plus_file(apk_file_name); + String fullpath = get_apk_expansion_fullpath(p_preset, p_path); String apk_expansion_public_key = p_preset->get("apk_expansion/public_key"); - Error err = save_pack(p_preset, fullpath); - - if (err != OK) { - EditorNode::add_io_error("Could not write expansion package file: " + apk_file_name); - return err; - } command_line_strings.push_back("--use_apk_expansion"); command_line_strings.push_back("--apk_expansion_md5"); @@ -2435,7 +2449,6 @@ public: copymem(&r_command_line_flags.write[base + 4], command_line_argument.ptr(), length); } } - return OK; } Error sign_apk(const Ref &p_preset, bool p_debug, String apk_path, EditorProgress ep) { @@ -2532,11 +2545,16 @@ public: ExportNotifier notifier(*this, p_preset, p_debug, p_path, p_flags); String src_apk; + Error err; EditorProgress ep("export", "Exporting for Android", 105, true); bool use_custom_build = bool(p_preset->get("custom_template/use_custom_build")); + int export_format = int(p_preset->get("custom_template/export_format")); bool p_give_internet = p_flags & (DEBUG_FLAG_DUMB_CLIENT | DEBUG_FLAG_REMOTE_DEBUG); + bool _signed = p_preset->get("package/signed"); + bool apk_expansion = p_preset->get("apk_expansion/enable"); + Vector enabled_abis = get_enabled_abis(p_preset); Ref main_image; Ref foreground; @@ -2544,25 +2562,48 @@ public: load_icon_refs(p_preset, main_image, foreground, background); - if (use_custom_build) { - //re-generate build.gradle and AndroidManifest.xml - { //test that installed build version is alright - FileAccessRef f = FileAccess::open("res://android/.build_version", FileAccess::READ); - if (!f) { - EditorNode::get_singleton()->show_warning(TTR("Trying to build from a custom built template, but no version info for it exists. Please reinstall from the 'Project' menu.")); - return ERR_UNCONFIGURED; - } - String version = f->get_line().strip_edges(); - if (version != VERSION_FULL_CONFIG) { - EditorNode::get_singleton()->show_warning(vformat(TTR("Android build version mismatch:\n Template installed: %s\n Godot Version: %s\nPlease reinstall Android build template from 'Project' menu."), version, VERSION_FULL_CONFIG)); - return ERR_UNCONFIGURED; - } + Vector command_line_flags; + // Write command line flags into the command_line_flags variable. + get_command_line_flags(p_preset, p_path, p_flags, command_line_flags); + + if (export_format == 1) { + if (!p_path.ends_with(".aab")) { + EditorNode::get_singleton()->show_warning(TTR("Invalid filename! Android App Bundle requires the *.aab extension.")); + return ERR_UNCONFIGURED; } + if (apk_expansion) { + EditorNode::get_singleton()->show_warning(TTR("APK Expansion not compatible with Android App Bundle.")); + return ERR_UNCONFIGURED; + } + } + if (export_format == 0 && !p_path.ends_with(".apk")) { + EditorNode::get_singleton()->show_warning( + TTR("Invalid filename! Android APK requires the *.apk extension.")); + return ERR_UNCONFIGURED; + } + if (export_format > 1 || export_format < 0) { + EditorNode::add_io_error("Unsupported export format!\n"); + return ERR_UNCONFIGURED; //TODO: is this the right error? + } + + if (use_custom_build) { + //test that installed build version is alright + FileAccessRef f = FileAccess::open("res://android/.build_version", FileAccess::READ); + if (!f) { + EditorNode::get_singleton()->show_warning(TTR("Trying to build from a custom built template, but no version info for it exists. Please reinstall from the 'Project' menu.")); + return ERR_UNCONFIGURED; + } + String version = f->get_line().strip_edges(); + if (version != VERSION_FULL_CONFIG) { + EditorNode::get_singleton()->show_warning(vformat(TTR("Android build version mismatch:\n Template installed: %s\n Godot Version: %s\nPlease reinstall Android build template from 'Project' menu."), version, VERSION_FULL_CONFIG)); + return ERR_UNCONFIGURED; + } + String sdk_path = EDITOR_GET("export/android/custom_build_sdk_path"); + ERR_FAIL_COND_V_MSG(sdk_path == "", ERR_UNCONFIGURED, "Android SDK path must be configured in Editor Settings at 'export/android/custom_build_sdk_path'."); // TODO: should we use "package/name" or "application/config/name"? String project_name = get_project_name(p_preset->get("package/name")); - // instead of calling _fix_resources - Error err = _create_project_name_strings_files(p_preset, project_name); + err = _create_project_name_strings_files(p_preset, project_name); //project name localization. if (err != OK) { EditorNode::add_io_error("Unable to overwrite res://android/build/res/*.xml files with project name"); } @@ -2570,16 +2611,32 @@ public: _copy_icons_to_gradle_project(p_preset, main_image, foreground, background); // Write an AndroidManifest.xml file into the Gradle project directory. _write_tmp_manifest(p_preset, p_give_internet, p_debug); - //build project if custom build is enabled - String sdk_path = EDITOR_GET("export/android/custom_build_sdk_path"); - - ERR_FAIL_COND_V_MSG(sdk_path == "", ERR_UNCONFIGURED, "Android SDK path must be configured in Editor Settings at 'export/android/custom_build_sdk_path'."); - _update_custom_build_project(); + //stores all the project files inside the Gradle project directory. Also includes all ABIs + if (!apk_expansion) { + DirAccess *da_res = DirAccess::create(DirAccess::ACCESS_RESOURCES); + if (da_res->dir_exists("res://android/build/assets")) { + DirAccess *da_assets = DirAccess::open("res://android/build/assets"); + da_assets->erase_contents_recursive(); + da_res->remove("res://android/build/assets"); + } + err = export_project_files(p_preset, rename_and_store_file_in_gradle_project, NULL, ignore_so_file); + if (err != OK) { + EditorNode::add_io_error("Could not export project files to gradle project\n"); + return err; + } + } else { + err = save_apk_expansion_file(p_preset, p_path); + if (err != OK) { + EditorNode::add_io_error("Could not write expansion package file!"); + return err; + } + } + store_file_at_path("res://android/build/assets/_cl_", command_line_flags); OS::get_singleton()->set_environment("ANDROID_HOME", sdk_path); //set and overwrite if required - String build_command; + #ifdef WINDOWS_ENABLED build_command = "gradlew.bat"; #else @@ -2587,12 +2644,12 @@ public: #endif String build_path = ProjectSettings::get_singleton()->get_resource_path().plus_file("android/build"); - build_command = build_path.plus_file(build_command); String package_name = get_package_name(p_preset->get("package/unique_name")); String version_code = itos(p_preset->get("version/code")); String version_name = p_preset->get("version/name"); + String enabled_abi_string = String("|").join(enabled_abis); Vector enabled_plugins = get_enabled_plugins(p_preset); String local_plugins_binaries = get_plugins_binaries(BINARY_TYPE_LOCAL, enabled_plugins); @@ -2604,10 +2661,20 @@ public: if (clean_build_required) { cmdline.push_back("clean"); } - cmdline.push_back("build"); + + String build_type = p_debug ? "Debug" : "Release"; + if (export_format == 1) { + String bundle_build_command = vformat("bundle%s", build_type); + cmdline.push_back(bundle_build_command); + } else if (export_format == 0) { + String apk_build_command = vformat("assemble%s", build_type); + cmdline.push_back(apk_build_command); + } + cmdline.push_back("-Pexport_package_name=" + package_name); // argument to specify the package name. cmdline.push_back("-Pexport_version_code=" + version_code); // argument to specify the version code. cmdline.push_back("-Pexport_version_name=" + version_name); // argument to specify the version name. + cmdline.push_back("-Pexport_enabled_abis=" + enabled_abi_string); // argument to specify enabled ABIs. cmdline.push_back("-Pplugins_local_binaries=" + local_plugins_binaries); // argument to specify the list of plugins local dependencies. cmdline.push_back("-Pplugins_remote_binaries=" + remote_plugins_binaries); // argument to specify the list of plugins remote dependencies. cmdline.push_back("-Pplugins_maven_repos=" + custom_maven_repos); // argument to specify the list of custom maven repos for the plugins dependencies. @@ -2625,35 +2692,56 @@ public: EditorNode::get_singleton()->show_warning(TTR("Building of Android project failed, check output for the error.\nAlternatively visit docs.godotengine.org for Android build documentation.")); return ERR_CANT_CREATE; } - if (p_debug) { - src_apk = build_path.plus_file("build/outputs/apk/debug/android_debug.apk"); - } else { - src_apk = build_path.plus_file("build/outputs/apk/release/android_release.apk"); + + List copy_args; + String copy_command; + if (export_format == 1) { + copy_command = vformat("copyAndRename%sAab", build_type); + } else if (export_format == 0) { + copy_command = vformat("copyAndRename%sApk", build_type); } - if (!FileAccess::exists(src_apk)) { - EditorNode::get_singleton()->show_warning(TTR("No build apk generated at: ") + "\n" + src_apk); + copy_args.push_back(copy_command); + + copy_args.push_back("-p"); // argument to specify the start directory. + copy_args.push_back(build_path); // start directory. + + String export_filename = p_path.get_file(); + String export_path = p_path.get_base_dir(); + + copy_args.push_back("-Pexport_path=file:" + export_path); + copy_args.push_back("-Pexport_filename=" + export_filename); + + int copy_result = EditorNode::get_singleton()->execute_and_show_output(TTR("Moving output"), build_command, copy_args); + if (copy_result != 0) { + EditorNode::get_singleton()->show_warning(TTR("Unable to copy and rename export file, check gradle project directory for outputs.")); return ERR_CANT_CREATE; } - } else { + if (_signed) { + err = sign_apk(p_preset, p_debug, p_path, ep); + if (err != OK) { + return err; + } + } + return OK; + } + // This is the start of the Legacy build system + if (p_debug) + src_apk = p_preset->get("custom_template/debug"); + else + src_apk = p_preset->get("custom_template/release"); - if (p_debug) - src_apk = p_preset->get("custom_template/debug"); - else - src_apk = p_preset->get("custom_template/release"); - - src_apk = src_apk.strip_edges(); + src_apk = src_apk.strip_edges(); + if (src_apk == "") { + if (p_debug) { + src_apk = find_export_template("android_debug.apk"); + } else { + src_apk = find_export_template("android_release.apk"); + } if (src_apk == "") { - if (p_debug) { - src_apk = find_export_template("android_debug.apk"); - } else { - src_apk = find_export_template("android_release.apk"); - } - if (src_apk == "") { - EditorNode::add_io_error("Package not found: " + src_apk); - return ERR_FILE_NOT_FOUND; - } + EditorNode::add_io_error("Package not found: " + src_apk); + return ERR_FILE_NOT_FOUND; } } @@ -2670,7 +2758,6 @@ public: unzFile pkg = unzOpen2(src_apk.utf8().get_data(), &io); if (!pkg) { - EditorNode::add_io_error("Could not find template APK to export:\n" + src_apk); return ERR_FILE_NOT_FOUND; } @@ -2691,19 +2778,13 @@ public: zipFile unaligned_apk = zipOpen2(tmp_unaligned_path.utf8().get_data(), APPEND_STATUS_CREATE, NULL, &io2); - bool _signed = p_preset->get("package/signed"); String cmdline = p_preset->get("command_line/extra_args"); String version_name = p_preset->get("version/name"); String package_name = p_preset->get("package/unique_name"); - bool apk_expansion = p_preset->get("apk_expansion/enable"); String apk_expansion_pkey = p_preset->get("apk_expansion/public_key"); - Vector enabled_abis = get_enabled_abis(p_preset); - - // Prepare images to be resized for the icons. If some image ends up being uninitialized, the default image from the export template will be used. - Vector invalid_abis(enabled_abis); while (ret == UNZ_OK) { @@ -2725,28 +2806,26 @@ public: unzCloseCurrentFile(pkg); //write - if (!use_custom_build) { - if (file == "AndroidManifest.xml") { - _fix_manifest(p_preset, data, p_give_internet); - } - if (file == "resources.arsc") { - _fix_resources(p_preset, data); - } - for (int i = 0; i < icon_densities_count; ++i) { - if (main_image.is_valid() && !main_image->empty()) { - if (file == launcher_icons[i].export_path) { - _process_launcher_icons(file, main_image, launcher_icons[i].dimensions, data); - } + if (file == "AndroidManifest.xml") { + _fix_manifest(p_preset, data, p_give_internet); + } + if (file == "resources.arsc") { + _fix_resources(p_preset, data); + } + for (int i = 0; i < icon_densities_count; ++i) { + if (main_image.is_valid() && !main_image->empty()) { + if (file == launcher_icons[i].export_path) { + _process_launcher_icons(file, main_image, launcher_icons[i].dimensions, data); } - if (foreground.is_valid() && !foreground->empty()) { - if (file == launcher_adaptive_icon_foregrounds[i].export_path) { - _process_launcher_icons(file, foreground, launcher_adaptive_icon_foregrounds[i].dimensions, data); - } + } + if (foreground.is_valid() && !foreground->empty()) { + if (file == launcher_adaptive_icon_foregrounds[i].export_path) { + _process_launcher_icons(file, foreground, launcher_adaptive_icon_foregrounds[i].dimensions, data); } - if (background.is_valid() && !background->empty()) { - if (file == launcher_adaptive_icon_backgrounds[i].export_path) { - _process_launcher_icons(file, background, launcher_adaptive_icon_backgrounds[i].dimensions, data); - } + } + if (background.is_valid() && !background->empty()) { + if (file == launcher_adaptive_icon_backgrounds[i].export_path) { + _process_launcher_icons(file, background, launcher_adaptive_icon_backgrounds[i].dimensions, data); } } } @@ -2805,18 +2884,26 @@ public: if (ep.step("Adding files...", 1)) { CLEANUP_AND_RETURN(ERR_SKIP); } - Error err = OK; + err = OK; if (p_flags & DEBUG_FLAG_DUMB_CLIENT) { APKExportData ed; ed.ep = &ep; ed.apk = unaligned_apk; err = export_project_files(p_preset, ignore_apk_file, &ed, save_apk_so); - } else if (!apk_expansion) { - APKExportData ed; - ed.ep = &ep; - ed.apk = unaligned_apk; - err = export_project_files(p_preset, save_apk_file, &ed, save_apk_so); + } else { + if (apk_expansion) { + err = save_apk_expansion_file(p_preset, p_path); + if (err != OK) { + EditorNode::add_io_error("Could not write expansion package file!"); + return err; + } + } else { + APKExportData ed; + ed.ep = &ep; + ed.apk = unaligned_apk; + err = export_project_files(p_preset, save_apk_file, &ed, save_apk_so); + } } if (err != OK) { @@ -2825,10 +2912,6 @@ public: CLEANUP_AND_RETURN(ERR_SKIP); } - Vector command_line_flags; - // Write command line flags into the command_line_flags variable. - err = get_command_line_flags(p_preset, p_path, p_flags, command_line_flags); - zip_fileinfo zipfi = get_zip_fileinfo(); zipOpenNewFileInZip(unaligned_apk, "assets/_cl_", diff --git a/platform/android/java/app/build.gradle b/platform/android/java/app/build.gradle index 68c18935d81..7c8efd84755 100644 --- a/platform/android/java/app/build.gradle +++ b/platform/android/java/app/build.gradle @@ -92,6 +92,11 @@ android { ignoreAssetsPattern "!.svn:!.git:!.ds_store:!*.scc:_*:!CVS:!thumbs.db:!picasa.ini:!*~" } + ndk { + String[] export_abi_list = getExportEnabledABIs() + abiFilters export_abi_list + } + // Feel free to modify the application id to your own. applicationId getExportPackageName() versionCode getExportVersionCode() @@ -164,5 +169,29 @@ android { } } +task copyAndRenameDebugApk(type: Copy) { + from "$buildDir/outputs/apk/debug/android_debug.apk" + into getExportPath() + rename "android_debug.apk", getExportFilename() +} + +task copyAndRenameReleaseApk(type: Copy) { + from "$buildDir/outputs/apk/release/android_release.apk" + into getExportPath() + rename "android_release.apk", getExportFilename() +} + +task copyAndRenameDebugAab(type: Copy) { + from "$buildDir/outputs/bundle/debug/build-debug.aab" + into getExportPath() + rename "build-debug.aab", getExportFilename() +} + +task copyAndRenameReleaseAab(type: Copy) { + from "$buildDir/outputs/bundle/release/build-release.aab" + into getExportPath() + rename "build-release.aab", getExportFilename() +} + //CHUNK_GLOBAL_BEGIN //CHUNK_GLOBAL_END diff --git a/platform/android/java/app/config.gradle b/platform/android/java/app/config.gradle index 7d5d2381001..d1176e61962 100644 --- a/platform/android/java/app/config.gradle +++ b/platform/android/java/app/config.gradle @@ -46,6 +46,37 @@ ext.getExportVersionName = { -> final String PLUGIN_VALUE_SEPARATOR_REGEX = "\\|" +// get the list of ABIs the project should be exported to +ext.getExportEnabledABIs = { -> + String enabledABIs = project.hasProperty("export_enabled_abis") ? project.property("export_enabled_abis") : ""; + if (enabledABIs == null || enabledABIs.isEmpty()) { + enabledABIs = "armeabi-v7a|arm64-v8a|x86|x86_64|" + } + Set exportAbiFilter = []; + for (String abi_name : enabledABIs.split(PLUGIN_VALUE_SEPARATOR_REGEX)) { + if (!abi_name.trim().isEmpty()){ + exportAbiFilter.add(abi_name); + } + } + return exportAbiFilter; +} + +ext.getExportPath = { + String exportPath = project.hasProperty("export_path") ? project.property("export_path") : "" + if (exportPath == null || exportPath.isEmpty()) { + exportPath = "." + } + return exportPath +} + +ext.getExportFilename = { + String exportFilename = project.hasProperty("export_filename") ? project.property("export_filename") : "" + if (exportFilename == null || exportFilename.isEmpty()) { + exportFilename = "godot_android" + } + return exportFilename +} + /** * Parse the project properties for the 'plugins_maven_repos' property and return the list * of maven repos.