|
@@ -775,6 +775,7 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
|
|
|
}
|
|
|
|
|
|
void _write_tmp_manifest(const Ref<EditorExportPreset> &p_preset, bool p_give_internet, bool p_debug) {
|
|
|
+ print_verbose("Building temporary manifest..");
|
|
|
String manifest_text =
|
|
|
"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
|
|
|
"<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
|
|
@@ -795,6 +796,8 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
|
|
|
manifest_text += _get_application_tag(p_preset, plugins_names);
|
|
|
manifest_text += "</manifest>\n";
|
|
|
String manifest_path = vformat("res://android/build/src/%s/AndroidManifest.xml", (p_debug ? "debug" : "release"));
|
|
|
+
|
|
|
+ print_verbose("Storing manifest into " + manifest_path + ": " + "\n" + manifest_text);
|
|
|
store_string_at_path(manifest_path, manifest_text);
|
|
|
}
|
|
|
|
|
@@ -1476,14 +1479,19 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
|
|
|
|
|
|
if (!project_splash_path.is_empty()) {
|
|
|
splash_image.instance();
|
|
|
+ print_verbose("Loading splash image: " + project_splash_path);
|
|
|
const Error err = ImageLoader::load_image(project_splash_path, splash_image);
|
|
|
if (err) {
|
|
|
+ if (OS::get_singleton()->is_stdout_verbose()) {
|
|
|
+ print_error("- unable to load splash image from " + project_splash_path + " (" + itos(err) + ")");
|
|
|
+ }
|
|
|
splash_image.unref();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (splash_image.is_null()) {
|
|
|
// Use the default
|
|
|
+ print_verbose("Using default splash image.");
|
|
|
splash_image = Ref<Image>(memnew(Image(boot_splash_png)));
|
|
|
}
|
|
|
|
|
@@ -1494,6 +1502,7 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
|
|
|
bg_color = boot_splash_bg_color;
|
|
|
}
|
|
|
|
|
|
+ print_verbose("Creating splash background color image.");
|
|
|
splash_bg_color_image.instance();
|
|
|
splash_bg_color_image->create(splash_image->get_width(), splash_image->get_height(), false, splash_image->get_format());
|
|
|
splash_bg_color_image->fill(bg_color);
|
|
@@ -1508,19 +1517,24 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
|
|
|
|
|
|
// Regular icon: user selection -> project icon -> default.
|
|
|
String path = static_cast<String>(p_preset->get(launcher_icon_option)).strip_edges();
|
|
|
+ print_verbose("Loading regular icon from " + path);
|
|
|
if (path.is_empty() || ImageLoader::load_image(path, icon) != OK) {
|
|
|
+ print_verbose("- falling back to project icon: " + project_icon_path);
|
|
|
ImageLoader::load_image(project_icon_path, icon);
|
|
|
}
|
|
|
|
|
|
// Adaptive foreground: user selection -> regular icon (user selection -> project icon -> default).
|
|
|
path = static_cast<String>(p_preset->get(launcher_adaptive_icon_foreground_option)).strip_edges();
|
|
|
+ print_verbose("Loading adaptive foreground icon from " + path);
|
|
|
if (path.is_empty() || ImageLoader::load_image(path, foreground) != OK) {
|
|
|
+ print_verbose("- falling back to using the regular icon");
|
|
|
foreground = icon;
|
|
|
}
|
|
|
|
|
|
// Adaptive background: user selection -> default.
|
|
|
path = static_cast<String>(p_preset->get(launcher_adaptive_icon_background_option)).strip_edges();
|
|
|
if (!path.is_empty()) {
|
|
|
+ print_verbose("Loading adaptive background icon from " + path);
|
|
|
ImageLoader::load_image(path, background);
|
|
|
}
|
|
|
}
|
|
@@ -1542,6 +1556,7 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
|
|
|
const Ref<Image> &background) {
|
|
|
// Store the splash image
|
|
|
if (splash_image.is_valid() && !splash_image->is_empty()) {
|
|
|
+ print_verbose("Storing splash image in " + String(SPLASH_IMAGE_EXPORT_PATH));
|
|
|
Vector<uint8_t> data;
|
|
|
_load_image_data(splash_image, data);
|
|
|
store_image(SPLASH_IMAGE_EXPORT_PATH, data);
|
|
@@ -1549,6 +1564,7 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
|
|
|
|
|
|
// Store the splash bg color image
|
|
|
if (splash_bg_color_image.is_valid() && !splash_bg_color_image->is_empty()) {
|
|
|
+ print_verbose("Storing splash background image in " + String(SPLASH_BG_COLOR_PATH));
|
|
|
Vector<uint8_t> data;
|
|
|
_load_image_data(splash_bg_color_image, data);
|
|
|
store_image(SPLASH_BG_COLOR_PATH, data);
|
|
@@ -1559,12 +1575,14 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
|
|
|
|
|
|
for (int i = 0; i < icon_densities_count; ++i) {
|
|
|
if (main_image.is_valid() && !main_image->is_empty()) {
|
|
|
+ print_verbose("Processing launcher icon for dimension " + itos(launcher_icons[i].dimensions) + " into " + launcher_icons[i].export_path);
|
|
|
Vector<uint8_t> data;
|
|
|
_process_launcher_icons(launcher_icons[i].export_path, main_image, launcher_icons[i].dimensions, data);
|
|
|
store_image(launcher_icons[i], data);
|
|
|
}
|
|
|
|
|
|
if (foreground.is_valid() && !foreground->is_empty()) {
|
|
|
+ print_verbose("Processing launcher adaptive icon foreground for dimension " + itos(launcher_adaptive_icon_foregrounds[i].dimensions) + " into " + launcher_adaptive_icon_foregrounds[i].export_path);
|
|
|
Vector<uint8_t> data;
|
|
|
_process_launcher_icons(launcher_adaptive_icon_foregrounds[i].export_path, foreground,
|
|
|
launcher_adaptive_icon_foregrounds[i].dimensions, data);
|
|
@@ -1572,6 +1590,7 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
|
|
|
}
|
|
|
|
|
|
if (background.is_valid() && !background->is_empty()) {
|
|
|
+ print_verbose("Processing launcher adaptive icon background for dimension " + itos(launcher_adaptive_icon_backgrounds[i].dimensions) + " into " + launcher_adaptive_icon_backgrounds[i].export_path);
|
|
|
Vector<uint8_t> data;
|
|
|
_process_launcher_icons(launcher_adaptive_icon_backgrounds[i].export_path, background,
|
|
|
launcher_adaptive_icon_backgrounds[i].dimensions, data);
|
|
@@ -2239,6 +2258,7 @@ public:
|
|
|
String release_password = p_preset->get("keystore/release_password");
|
|
|
|
|
|
String apksigner = get_apksigner_path();
|
|
|
+ print_verbose("Starting signing of the " + export_label + " binary using " + apksigner);
|
|
|
if (!FileAccess::exists(apksigner)) {
|
|
|
EditorNode::add_io_error("'apksigner' could not be found.\nPlease check the command is available in the Android SDK build-tools directory.\nThe resulting " + export_label + " is unsigned.");
|
|
|
return OK;
|
|
@@ -2287,6 +2307,10 @@ public:
|
|
|
args.push_back("--ks-key-alias");
|
|
|
args.push_back(user);
|
|
|
args.push_back(export_path);
|
|
|
+ if (p_debug) {
|
|
|
+ // We only print verbose logs for debug builds to avoid leaking release keystore credentials.
|
|
|
+ print_verbose("Signing debug binary using: " + String("\n") + apksigner + " " + join_list(args, String(" ")));
|
|
|
+ }
|
|
|
int retval;
|
|
|
OS::get_singleton()->execute(apksigner, args, nullptr, &retval);
|
|
|
if (retval) {
|
|
@@ -2302,24 +2326,41 @@ public:
|
|
|
args.push_back("verify");
|
|
|
args.push_back("--verbose");
|
|
|
args.push_back(export_path);
|
|
|
+ if (p_debug) {
|
|
|
+ print_verbose("Verifying signed build using: " + String("\n") + apksigner + " " + join_list(args, String(" ")));
|
|
|
+ }
|
|
|
|
|
|
OS::get_singleton()->execute(apksigner, args, nullptr, &retval);
|
|
|
if (retval) {
|
|
|
EditorNode::add_io_error("'apksigner' verification of " + export_label + " failed.");
|
|
|
return ERR_CANT_CREATE;
|
|
|
}
|
|
|
+
|
|
|
+ print_verbose("Successfully completed signing build.");
|
|
|
return OK;
|
|
|
}
|
|
|
|
|
|
void _clear_assets_directory() {
|
|
|
DirAccessRef da_res = DirAccess::create(DirAccess::ACCESS_RESOURCES);
|
|
|
if (da_res->dir_exists("res://android/build/assets")) {
|
|
|
+ print_verbose("Clearing assets directory..");
|
|
|
DirAccessRef da_assets = DirAccess::open("res://android/build/assets");
|
|
|
da_assets->erase_contents_recursive();
|
|
|
da_res->remove("res://android/build/assets");
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ String join_list(List<String> parts, const String &separator) const {
|
|
|
+ String ret;
|
|
|
+ for (int i = 0; i < parts.size(); ++i) {
|
|
|
+ if (i > 0) {
|
|
|
+ ret += separator;
|
|
|
+ }
|
|
|
+ ret += parts[i];
|
|
|
+ }
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0) override {
|
|
|
int export_format = int(p_preset->get("custom_template/export_format"));
|
|
|
bool should_sign = p_preset->get("package/signed");
|
|
@@ -2339,6 +2380,15 @@ public:
|
|
|
bool apk_expansion = p_preset->get("apk_expansion/enable");
|
|
|
Vector<String> enabled_abis = get_enabled_abis(p_preset);
|
|
|
|
|
|
+ print_verbose("Exporting for Android...");
|
|
|
+ print_verbose("- debug build: " + bool_to_string(p_debug));
|
|
|
+ print_verbose("- export path: " + p_path);
|
|
|
+ print_verbose("- export format: " + itos(export_format));
|
|
|
+ print_verbose("- sign build: " + bool_to_string(should_sign));
|
|
|
+ print_verbose("- custom build enabled: " + bool_to_string(use_custom_build));
|
|
|
+ print_verbose("- apk expansion enabled: " + bool_to_string(apk_expansion));
|
|
|
+ print_verbose("- enabled abis: " + String(",").join(enabled_abis));
|
|
|
+
|
|
|
Ref<Image> splash_image;
|
|
|
Ref<Image> splash_bg_color_image;
|
|
|
load_splash_refs(splash_image, splash_bg_color_image);
|
|
@@ -2374,14 +2424,17 @@ public:
|
|
|
}
|
|
|
|
|
|
if (use_custom_build) {
|
|
|
+ print_verbose("Starting custom build..");
|
|
|
//test that installed build version is alright
|
|
|
{
|
|
|
+ print_verbose("Checking build version..");
|
|
|
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();
|
|
|
+ print_verbose("- build version: " + version);
|
|
|
f->close();
|
|
|
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));
|
|
@@ -2389,7 +2442,8 @@ public:
|
|
|
}
|
|
|
}
|
|
|
String sdk_path = EDITOR_GET("export/android/android_sdk_path");
|
|
|
- ERR_FAIL_COND_V_MSG(sdk_path == "", ERR_UNCONFIGURED, "Android SDK path must be configured in Editor Settings at 'export/android/android_sdk_path'.");
|
|
|
+ ERR_FAIL_COND_V_MSG(sdk_path.is_empty(), ERR_UNCONFIGURED, "Android SDK path must be configured in Editor Settings at 'export/android/android_sdk_path'.");
|
|
|
+ print_verbose("Android sdk path: " + sdk_path);
|
|
|
|
|
|
// TODO: should we use "package/name" or "application/config/name"?
|
|
|
String project_name = get_project_name(p_preset->get("package/name"));
|
|
@@ -2405,20 +2459,24 @@ public:
|
|
|
//stores all the project files inside the Gradle project directory. Also includes all ABIs
|
|
|
_clear_assets_directory();
|
|
|
if (!apk_expansion) {
|
|
|
+ print_verbose("Exporting project files..");
|
|
|
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 {
|
|
|
+ print_verbose("Saving apk expansion file..");
|
|
|
err = save_apk_expansion_file(p_preset, p_path);
|
|
|
if (err != OK) {
|
|
|
EditorNode::add_io_error("Could not write expansion package file!");
|
|
|
return err;
|
|
|
}
|
|
|
}
|
|
|
+ print_verbose("Storing command line flags..");
|
|
|
store_file_at_path("res://android/build/assets/_cl_", command_line_flags);
|
|
|
|
|
|
+ print_verbose("Updating ANDROID_HOME environment to " + sdk_path);
|
|
|
OS::get_singleton()->set_environment("ANDROID_HOME", sdk_path); //set and overwrite if required
|
|
|
String build_command;
|
|
|
|
|
@@ -2458,6 +2516,8 @@ public:
|
|
|
cmdline.push_back(apk_build_command);
|
|
|
}
|
|
|
|
|
|
+ cmdline.push_back("-p"); // argument to specify the start directory.
|
|
|
+ cmdline.push_back(build_path); // start directory.
|
|
|
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.
|
|
@@ -2467,6 +2527,13 @@ public:
|
|
|
cmdline.push_back("-Pplugins_maven_repos=" + custom_maven_repos); // argument to specify the list of custom maven repos for the plugins dependencies.
|
|
|
cmdline.push_back("-Pperform_zipalign=" + zipalign_flag); // argument to specify whether the build should be zipaligned.
|
|
|
cmdline.push_back("-Pperform_signing=" + sign_flag); // argument to specify whether the build should be signed.
|
|
|
+
|
|
|
+ // NOTE: The release keystore is not included in the verbose logging
|
|
|
+ // to avoid accidentally leaking sensitive information when sharing verbose logs for troubleshooting.
|
|
|
+ // Any non-sensitive additions to the command line arguments must be done above this section.
|
|
|
+ // Sensitive additions must be done below the logging statement.
|
|
|
+ print_verbose("Build Android project using gradle command: " + String("\n") + build_command + " " + join_list(cmdline, String(" ")));
|
|
|
+
|
|
|
if (should_sign && !p_debug) {
|
|
|
// Pass the release keystore info as well
|
|
|
String release_keystore = p_preset->get("keystore/release");
|
|
@@ -2481,8 +2548,6 @@ public:
|
|
|
cmdline.push_back("-Prelease_keystore_alias=" + release_username); // argument to specify the release keystore alias.
|
|
|
cmdline.push_back("-Prelease_keystore_password=" + release_password); // argument to specity the release keystore password.
|
|
|
}
|
|
|
- cmdline.push_back("-p"); // argument to specify the start directory.
|
|
|
- cmdline.push_back(build_path); // start directory.
|
|
|
|
|
|
int result = EditorNode::get_singleton()->execute_and_show_output(TTR("Building Android Project (gradle)"), build_command, cmdline);
|
|
|
if (result != 0) {
|
|
@@ -2513,15 +2578,18 @@ public:
|
|
|
copy_args.push_back("-Pexport_path=file:" + export_path);
|
|
|
copy_args.push_back("-Pexport_filename=" + export_filename);
|
|
|
|
|
|
+ print_verbose("Copying Android binary using gradle command: " + String("\n") + build_command + " " + join_list(copy_args, String(" ")));
|
|
|
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;
|
|
|
}
|
|
|
|
|
|
+ print_verbose("Successfully completed Android custom build.");
|
|
|
return OK;
|
|
|
}
|
|
|
// This is the start of the Legacy build system
|
|
|
+ print_verbose("Starting legacy build system..");
|
|
|
if (p_debug)
|
|
|
src_apk = p_preset->get("custom_template/debug");
|
|
|
else
|