Update gradle build files to automatically perform signing and zipalign tasks for custom builds.

This commit is contained in:
Fredia Huya-Kouadio 2020-11-21 14:09:33 -08:00
parent 6bd4074f76
commit 918b218b55
4 changed files with 94 additions and 100 deletions

View file

@ -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<String> 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<EditorExportPreset> &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<PluginConfig> 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;
}

View file

@ -291,7 +291,7 @@ String _get_application_tag(const Ref<EditorExportPreset> &p_preset, const Strin
String manifest_application_text =
" <application android:label=\"@string/godot_project_name_string\"\n"
" android:allowBackup=\"false\" tools:ignore=\"GoogleAppIndexingWarning\"\n"
" android:icon=\"@mipmap/icon\">)\n\n"
" android:icon=\"@mipmap/icon\">\n\n"
" <meta-data tools:node=\"remove\" android:name=\"xr_mode_metadata_name\" />\n";
manifest_application_text += _get_plugins_tag(plugins_names);

View file

@ -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 {

View file

@ -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)
}