diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp index 9288fff82f0..d24c96f87a2 100644 --- a/platform/android/export/export.cpp +++ b/platform/android/export/export.cpp @@ -1982,15 +1982,6 @@ public: err += "\n"; valid = false; } - - // Check for the build-tools directory. - DirAccessRef build_tools_da = DirAccess::open(sdk_path.plus_file("build-tools"), &errn); - if (errn != OK) { - err += TTR("Invalid Android SDK path for custom build in Editor Settings."); - err += TTR("Missing 'build-tools' directory!"); - err += "\n"; - valid = false; - } } if (!FileAccess::exists("res://android/build/build.gradle")) { @@ -2275,65 +2266,6 @@ public: } } - Error _zip_align_project(const String &sdk_path, const String &unaligned_file_path, const String &aligned_file_path) { - // Look for the zipalign tool. - String zipalign_command_name; -#ifdef WINDOWS_ENABLED - zipalign_command_name = "zipalign.exe"; -#else - zipalign_command_name = "zipalign"; -#endif - - String zipalign_command; - Error errn; - String build_tools_dir = sdk_path.plus_file("build-tools"); - DirAccessRef da = DirAccess::open(build_tools_dir, &errn); - if (errn != OK) { - return errn; - } - - // There are additional versions directories we need to go through. - da->list_dir_begin(); - String sub_dir = da->get_next(); - while (!sub_dir.empty()) { - if (!sub_dir.begins_with(".") && da->current_is_dir()) { - // Check if the tool is here. - String tool_path = build_tools_dir.plus_file(sub_dir).plus_file(zipalign_command_name); - if (FileAccess::exists(tool_path)) { - zipalign_command = tool_path; - break; - } - } - sub_dir = da->get_next(); - } - da->list_dir_end(); - - if (zipalign_command.empty()) { - EditorNode::get_singleton()->show_warning(TTR("Unable to find the zipalign tool.")); - return ERR_CANT_CREATE; - } - - List zipalign_args; - zipalign_args.push_back("-f"); - zipalign_args.push_back("-v"); - zipalign_args.push_back("4"); - zipalign_args.push_back(unaligned_file_path); // source file - zipalign_args.push_back(aligned_file_path); // destination file - - int result = EditorNode::get_singleton()->execute_and_show_output(TTR("Aligning APK..."), zipalign_command, zipalign_args); - if (result != 0) { - EditorNode::get_singleton()->show_warning(TTR("Unable to complete APK alignment.")); - return ERR_CANT_CREATE; - } - - // Delete the unaligned path. - errn = da->remove(unaligned_file_path); - if (errn != OK) { - EditorNode::get_singleton()->show_warning(TTR("Unable to delete unaligned APK.")); - } - return OK; - } - virtual Error export_project(const Ref &p_preset, bool p_debug, const String &p_path, int p_flags = 0) override { ExportNotifier notifier(*this, p_preset, p_debug, p_path, p_flags); @@ -2445,6 +2377,8 @@ public: 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); + String sign_flag = _signed ? "true" : "false"; + String zipalign_flag = "true"; Vector enabled_plugins = get_enabled_plugins(p_preset); String local_plugins_binaries = get_plugins_binaries(BINARY_TYPE_LOCAL, enabled_plugins); @@ -2473,15 +2407,25 @@ public: 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. + 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. + if (_signed && !p_debug) { + // Pass the release keystore info as well + 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"); + if (!FileAccess::exists(release_keystore)) { + EditorNode::add_io_error("Could not find keystore, unable to export."); + return ERR_FILE_CANT_OPEN; + } + + cmdline.push_back("-Prelease_keystore_file=" + release_keystore); // argument to specify the release keystore file. + 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. - /*{ used for debug - int ec; - String pipe; - OS::get_singleton()->execute(build_command, cmdline, true, nullptr, nullptr, &ec); - print_line("exit code: " + itos(ec)); - } - */ + int result = EditorNode::get_singleton()->execute_and_show_output(TTR("Building Android Project (gradle)"), build_command, cmdline); if (result != 0) { 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.")); @@ -2502,16 +2446,11 @@ public: copy_args.push_back(build_path); // start directory. String export_filename = p_path.get_file(); - if (export_format == 0) { - // By default, generated apk are not aligned. - export_filename += ".unaligned"; - } String export_path = p_path.get_base_dir(); if (export_path.is_rel_path()) { export_path = OS::get_singleton()->get_resource_dir().plus_file(export_path); } export_path = ProjectSettings::get_singleton()->globalize_path(export_path).simplify_path(); - String export_file_path = export_path.plus_file(export_filename); copy_args.push_back("-Pexport_path=file:" + export_path); copy_args.push_back("-Pexport_filename=" + export_filename); @@ -2521,20 +2460,6 @@ public: EditorNode::get_singleton()->show_warning(TTR("Unable to copy and rename export file, check gradle project directory for outputs.")); return ERR_CANT_CREATE; } - if (_signed) { - err = sign_apk(p_preset, p_debug, export_file_path, ep); - if (err != OK) { - return err; - } - } - - if (export_format == 0) { - // Perform zip alignment - err = _zip_align_project(sdk_path, export_file_path, export_path.plus_file(p_path.get_file())); - if (err != OK) { - return err; - } - } return OK; } diff --git a/platform/android/export/gradle_export_util.h b/platform/android/export/gradle_export_util.h index 3bc3651712e..a9f38869e0e 100644 --- a/platform/android/export/gradle_export_util.h +++ b/platform/android/export/gradle_export_util.h @@ -291,7 +291,7 @@ String _get_application_tag(const Ref &p_preset, const Strin String manifest_application_text = " )\n\n" + " android:icon=\"@mipmap/icon\">\n\n" " \n"; manifest_application_text += _get_plugins_tag(plugins_names); diff --git a/platform/android/java/app/build.gradle b/platform/android/java/app/build.gradle index 6de1d2dd308..53d11fda5b8 100644 --- a/platform/android/java/app/build.gradle +++ b/platform/android/java/app/build.gradle @@ -106,10 +106,41 @@ android { // doNotStrip '**/*.so' } - // Both signing and zip-aligning will be done at export time - buildTypes.all { buildType -> - buildType.zipAlignEnabled false - buildType.signingConfig null + signingConfigs { + release { + File keystoreFile = new File(getReleaseKeystoreFile()) + if (keystoreFile.isFile()) { + storeFile keystoreFile + storePassword getReleaseKeystorePassword() + keyAlias getReleaseKeyAlias() + keyPassword getReleaseKeystorePassword() + } + } + } + + buildTypes { + + debug { + // Signing and zip-aligning are skipped for prebuilt builds, but + // performed for custom builds. + zipAlignEnabled shouldZipAlign() + if (shouldSign()) { + signingConfig signingConfigs.debug + } else { + signingConfig null + } + } + + release { + // Signing and zip-aligning are skipped for prebuilt builds, but + // performed for custom builds. + zipAlignEnabled shouldZipAlign() + if (shouldSign()) { + signingConfig signingConfigs.release + } else { + signingConfig null + } + } } sourceSets { diff --git a/platform/android/java/app/config.gradle b/platform/android/java/app/config.gradle index e6c45b73a70..80cf6f7ede9 100644 --- a/platform/android/java/app/config.gradle +++ b/platform/android/java/app/config.gradle @@ -34,7 +34,11 @@ ext.getExportVersionCode = { -> if (versionCode == null || versionCode.isEmpty()) { versionCode = "1" } - return Integer.parseInt(versionCode) + try { + return Integer.parseInt(versionCode) + } catch (NumberFormatException ignored) { + return 1 + } } ext.getExportVersionName = { -> @@ -136,3 +140,37 @@ ext.getGodotPluginsLocalBinaries = { -> return binDeps } + +ext.getReleaseKeystoreFile = { -> + String keystoreFile = project.hasProperty("release_keystore_file") ? project.property("release_keystore_file") : "" + if (keystoreFile == null || keystoreFile.isEmpty()) { + keystoreFile = "." + } + return keystoreFile +} + +ext.getReleaseKeystorePassword = { -> + String keystorePassword = project.hasProperty("release_keystore_password") ? project.property("release_keystore_password") : "" + return keystorePassword +} + +ext.getReleaseKeyAlias = { -> + String keyAlias = project.hasProperty("release_keystore_alias") ? project.property("release_keystore_alias") : "" + return keyAlias +} + +ext.shouldZipAlign = { -> + String zipAlignFlag = project.hasProperty("perform_zipalign") ? project.property("perform_zipalign") : "" + if (zipAlignFlag == null || zipAlignFlag.isEmpty()) { + zipAlignFlag = "false" + } + return Boolean.parseBoolean(zipAlignFlag) +} + +ext.shouldSign = { -> + String signFlag = project.hasProperty("perform_signing") ? project.property("perform_signing") : "" + if (signFlag == null || signFlag.isEmpty()) { + signFlag = "false" + } + return Boolean.parseBoolean(signFlag) +}