You've already forked godot
mirror of
https://github.com/godotengine/godot.git
synced 2025-11-10 13:00:37 +00:00
Merge pull request #67668 from nikitalita/apk-signer
Improve get_apksigner_path() robustness
This commit is contained in:
@@ -2011,7 +2011,10 @@ String EditorExportPlatformAndroid::get_adb_path() {
|
|||||||
return sdk_path.path_join("platform-tools/adb" + exe_ext);
|
return sdk_path.path_join("platform-tools/adb" + exe_ext);
|
||||||
}
|
}
|
||||||
|
|
||||||
String EditorExportPlatformAndroid::get_apksigner_path() {
|
String EditorExportPlatformAndroid::get_apksigner_path(int p_target_sdk, bool p_check_executes) {
|
||||||
|
if (p_target_sdk == -1) {
|
||||||
|
p_target_sdk = DEFAULT_TARGET_SDK_VERSION;
|
||||||
|
}
|
||||||
String exe_ext = "";
|
String exe_ext = "";
|
||||||
if (OS::get_singleton()->get_name() == "Windows") {
|
if (OS::get_singleton()->get_name() == "Windows") {
|
||||||
exe_ext = ".bat";
|
exe_ext = ".bat";
|
||||||
@@ -2029,23 +2032,89 @@ String EditorExportPlatformAndroid::get_apksigner_path() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// There are additional versions directories we need to go through.
|
// There are additional versions directories we need to go through.
|
||||||
da->list_dir_begin();
|
Vector<String> dir_list = da->get_directories();
|
||||||
String sub_dir = da->get_next();
|
|
||||||
while (!sub_dir.is_empty()) {
|
// We need to use the version of build_tools that matches the Target SDK
|
||||||
if (!sub_dir.begins_with(".") && da->current_is_dir()) {
|
// If somehow we can't find that, we see if a version between 28 and the default target SDK exists.
|
||||||
// Check if the tool is here.
|
// We need to avoid versions <= 27 because they fail on Java versions >9
|
||||||
String tool_path = build_tools_dir.path_join(sub_dir).path_join(apksigner_command_name);
|
// If we can't find that, we just use the first valid version.
|
||||||
if (FileAccess::exists(tool_path)) {
|
Vector<String> ideal_versions;
|
||||||
apksigner_path = tool_path;
|
Vector<String> other_versions;
|
||||||
|
Vector<String> versions;
|
||||||
|
bool found_target_sdk = false;
|
||||||
|
// We only allow for versions <= 27 if specifically set
|
||||||
|
int min_version = p_target_sdk <= 27 ? p_target_sdk : 28;
|
||||||
|
for (String sub_dir : dir_list) {
|
||||||
|
if (!sub_dir.begins_with(".")) {
|
||||||
|
Vector<String> ver_numbers = sub_dir.split(".");
|
||||||
|
// Dir not a version number, will use as last resort
|
||||||
|
if (!ver_numbers.size() || !ver_numbers[0].is_valid_int()) {
|
||||||
|
other_versions.push_back(sub_dir);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
int ver_number = ver_numbers[0].to_int();
|
||||||
|
if (ver_number == p_target_sdk) {
|
||||||
|
found_target_sdk = true;
|
||||||
|
//ensure this is in front of the ones we check
|
||||||
|
versions.push_back(sub_dir);
|
||||||
|
} else {
|
||||||
|
if (ver_number >= min_version && ver_number <= DEFAULT_TARGET_SDK_VERSION) {
|
||||||
|
ideal_versions.push_back(sub_dir);
|
||||||
|
} else {
|
||||||
|
other_versions.push_back(sub_dir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// we will check ideal versions first, then other versions.
|
||||||
|
versions.append_array(ideal_versions);
|
||||||
|
versions.append_array(other_versions);
|
||||||
|
|
||||||
|
if (!versions.size()) {
|
||||||
|
print_error("Unable to find the 'apksigner' tool.");
|
||||||
|
return apksigner_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
int i;
|
||||||
|
bool failed = false;
|
||||||
|
String version_to_use;
|
||||||
|
|
||||||
|
List<String> args;
|
||||||
|
args.push_back("--version");
|
||||||
|
String output;
|
||||||
|
int retval;
|
||||||
|
Error err;
|
||||||
|
for (i = 0; i < versions.size(); i++) {
|
||||||
|
// Check if the tool is here.
|
||||||
|
apksigner_path = build_tools_dir.path_join(versions[i]).path_join(apksigner_command_name);
|
||||||
|
if (FileAccess::exists(apksigner_path)) {
|
||||||
|
version_to_use = versions[i];
|
||||||
|
// If we aren't exporting, just break here.
|
||||||
|
if (!p_check_executes) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// we only check to see if it executes on export because it is slow to load
|
||||||
|
err = OS::get_singleton()->execute(apksigner_path, args, &output, &retval, false);
|
||||||
|
if (err || retval) {
|
||||||
|
failed = true;
|
||||||
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sub_dir = da->get_next();
|
|
||||||
}
|
}
|
||||||
da->list_dir_end();
|
if (i == versions.size()) {
|
||||||
|
if (failed) {
|
||||||
if (apksigner_path.is_empty()) {
|
print_error("All located 'apksigner' tools in " + build_tools_dir + " failed to execute");
|
||||||
print_error("Unable to find the 'apksigner' tool.");
|
return "<FAILED>";
|
||||||
|
} else {
|
||||||
|
print_error("Unable to find the 'apksigner' tool.");
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found_target_sdk) {
|
||||||
|
print_line("Could not find version of build tools that matches Target SDK, using " + version_to_use);
|
||||||
|
} else if (failed && found_target_sdk) {
|
||||||
|
print_line("Version of build tools that matches Target SDK failed to execute, using " + version_to_use);
|
||||||
}
|
}
|
||||||
|
|
||||||
return apksigner_path;
|
return apksigner_path;
|
||||||
@@ -2165,8 +2234,12 @@ bool EditorExportPlatformAndroid::has_valid_export_configuration(const Ref<Edito
|
|||||||
valid = false;
|
valid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String target_sdk_version = p_preset->get("custom_build/target_sdk");
|
||||||
|
if (!target_sdk_version.is_valid_int()) {
|
||||||
|
target_sdk_version = itos(DEFAULT_TARGET_SDK_VERSION);
|
||||||
|
}
|
||||||
// Validate that apksigner is available
|
// Validate that apksigner is available
|
||||||
String apksigner_path = get_apksigner_path();
|
String apksigner_path = get_apksigner_path(target_sdk_version.to_int());
|
||||||
if (!FileAccess::exists(apksigner_path)) {
|
if (!FileAccess::exists(apksigner_path)) {
|
||||||
err += TTR("Unable to find Android SDK build-tools' apksigner command.");
|
err += TTR("Unable to find Android SDK build-tools' apksigner command.");
|
||||||
err += TTR("Please check in the Android SDK directory specified in Editor Settings.");
|
err += TTR("Please check in the Android SDK directory specified in Editor Settings.");
|
||||||
@@ -2389,9 +2462,16 @@ Error EditorExportPlatformAndroid::sign_apk(const Ref<EditorExportPreset> &p_pre
|
|||||||
String release_keystore = p_preset->get("keystore/release");
|
String release_keystore = p_preset->get("keystore/release");
|
||||||
String release_username = p_preset->get("keystore/release_user");
|
String release_username = p_preset->get("keystore/release_user");
|
||||||
String release_password = p_preset->get("keystore/release_password");
|
String release_password = p_preset->get("keystore/release_password");
|
||||||
|
String target_sdk_version = p_preset->get("custom_build/target_sdk");
|
||||||
String apksigner = get_apksigner_path();
|
if (!target_sdk_version.is_valid_int()) {
|
||||||
|
target_sdk_version = itos(DEFAULT_TARGET_SDK_VERSION);
|
||||||
|
}
|
||||||
|
String apksigner = get_apksigner_path(target_sdk_version.to_int(), true);
|
||||||
print_verbose("Starting signing of the " + export_label + " binary using " + apksigner);
|
print_verbose("Starting signing of the " + export_label + " binary using " + apksigner);
|
||||||
|
if (apksigner == "<FAILED>") {
|
||||||
|
add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), vformat(TTR("All 'apksigner' tools located in Android SDK 'build-tools' directory failed to execute. Please check that you have the correct version installed for your target sdk version. The resulting %s is unsigned."), export_label));
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
if (!FileAccess::exists(apksigner)) {
|
if (!FileAccess::exists(apksigner)) {
|
||||||
add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), vformat(TTR("'apksigner' could not be found. Please check that the command is available in the Android SDK build-tools directory. The resulting %s is unsigned."), export_label));
|
add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), vformat(TTR("'apksigner' could not be found. Please check that the command is available in the Android SDK build-tools directory. The resulting %s is unsigned."), export_label));
|
||||||
return OK;
|
return OK;
|
||||||
@@ -2441,20 +2521,27 @@ Error EditorExportPlatformAndroid::sign_apk(const Ref<EditorExportPreset> &p_pre
|
|||||||
args.push_back("--ks-key-alias");
|
args.push_back("--ks-key-alias");
|
||||||
args.push_back(user);
|
args.push_back(user);
|
||||||
args.push_back(export_path);
|
args.push_back(export_path);
|
||||||
if (p_debug) {
|
if (OS::get_singleton()->is_stdout_verbose() && p_debug) {
|
||||||
// We only print verbose logs for debug builds to avoid leaking release keystore credentials.
|
// We only print verbose logs with credentials for debug builds to avoid leaking release keystore credentials.
|
||||||
print_verbose("Signing debug binary using: " + String("\n") + apksigner + " " + join_list(args, String(" ")));
|
print_verbose("Signing debug binary using: " + String("\n") + apksigner + " " + join_list(args, String(" ")));
|
||||||
|
} else {
|
||||||
|
List<String> redacted_args = List<String>(args);
|
||||||
|
redacted_args.find(keystore)->set("<REDACTED>");
|
||||||
|
redacted_args.find("pass:" + password)->set("pass:<REDACTED>");
|
||||||
|
redacted_args.find(user)->set("<REDACTED>");
|
||||||
|
print_line("Signing binary using: " + String("\n") + apksigner + " " + join_list(redacted_args, String(" ")));
|
||||||
}
|
}
|
||||||
int retval;
|
int retval;
|
||||||
output.clear();
|
|
||||||
Error err = OS::get_singleton()->execute(apksigner, args, &output, &retval, true);
|
Error err = OS::get_singleton()->execute(apksigner, args, &output, &retval, true);
|
||||||
if (err != OK) {
|
if (err != OK) {
|
||||||
add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("Could not start apksigner executable."));
|
add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("Could not start apksigner executable."));
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
print_verbose(output);
|
// By design, apksigner does not output credentials in its output unless --verbose is used
|
||||||
|
print_line(output);
|
||||||
if (retval) {
|
if (retval) {
|
||||||
add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), vformat(TTR("'apksigner' returned with error #%d"), retval));
|
add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), vformat(TTR("'apksigner' returned with error #%d"), retval));
|
||||||
|
add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), vformat(TTR("output: \n%s"), output));
|
||||||
return ERR_CANT_CREATE;
|
return ERR_CANT_CREATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2479,6 +2566,7 @@ Error EditorExportPlatformAndroid::sign_apk(const Ref<EditorExportPreset> &p_pre
|
|||||||
print_verbose(output);
|
print_verbose(output);
|
||||||
if (retval) {
|
if (retval) {
|
||||||
add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), vformat(TTR("'apksigner' verification of %s failed."), export_label));
|
add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), vformat(TTR("'apksigner' verification of %s failed."), export_label));
|
||||||
|
add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), vformat(TTR("output: \n%s"), output));
|
||||||
return ERR_CANT_CREATE;
|
return ERR_CANT_CREATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -201,7 +201,7 @@ public:
|
|||||||
|
|
||||||
static String get_adb_path();
|
static String get_adb_path();
|
||||||
|
|
||||||
static String get_apksigner_path();
|
static String get_apksigner_path(int p_target_sdk = -1, bool p_check_executes = false);
|
||||||
|
|
||||||
virtual bool has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const override;
|
virtual bool has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const override;
|
||||||
virtual bool has_valid_project_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error) const override;
|
virtual bool has_valid_project_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error) const override;
|
||||||
|
|||||||
Reference in New Issue
Block a user