diff --git a/editor/editor_paths.cpp b/editor/editor_paths.cpp index 801c81efa848..be511452a68a 100644 --- a/editor/editor_paths.cpp +++ b/editor/editor_paths.cpp @@ -70,6 +70,10 @@ String EditorPaths::get_export_templates_dir() const { return get_data_dir().path_join(export_templates_folder); } +String EditorPaths::get_debug_keystore_path() const { + return get_data_dir().path_join("keystores/debug.keystore"); +} + String EditorPaths::get_project_settings_dir() const { return get_project_data_dir().path_join("editor"); } diff --git a/editor/editor_paths.h b/editor/editor_paths.h index 547b93ad7e8a..a396c433018a 100644 --- a/editor/editor_paths.h +++ b/editor/editor_paths.h @@ -63,6 +63,7 @@ public: String get_cache_dir() const; String get_project_data_dir() const; String get_export_templates_dir() const; + String get_debug_keystore_path() const; String get_project_settings_dir() const; String get_text_editor_themes_dir() const; String get_script_templates_dir() const; diff --git a/editor/export/editor_export.cpp b/editor/export/editor_export.cpp index 0f02ab5a7a48..9a0f2f18fac5 100644 --- a/editor/export/editor_export.cpp +++ b/editor/export/editor_export.cpp @@ -32,6 +32,7 @@ #include "core/config/project_settings.h" #include "core/io/config_file.h" +#include "editor/editor_settings.h" EditorExport *EditorExport::singleton = nullptr; @@ -191,6 +192,12 @@ void EditorExport::_notification(int p_what) { export_platforms.write[i]->cleanup(); } } break; + + case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: { + for (int i = 0; i < export_platforms.size(); i++) { + export_platforms.write[i]->notification(p_what); + } + } break; } } diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp index 138714634f9a..6a6d7149ff89 100644 --- a/platform/android/export/export.cpp +++ b/platform/android/export/export.cpp @@ -33,6 +33,7 @@ #include "export_plugin.h" #include "core/os/os.h" +#include "editor/editor_paths.h" #include "editor/editor_settings.h" #include "editor/export/editor_export.h" @@ -46,10 +47,10 @@ void register_android_exporter() { EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/android/java_sdk_path", PROPERTY_HINT_GLOBAL_DIR)); EDITOR_DEF("export/android/android_sdk_path", OS::get_singleton()->get_environment("ANDROID_HOME")); EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/android/android_sdk_path", PROPERTY_HINT_GLOBAL_DIR)); - EDITOR_DEF("export/android/debug_keystore", ""); + EDITOR_DEF("export/android/debug_keystore", EditorPaths::get_singleton()->get_debug_keystore_path()); EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/android/debug_keystore", PROPERTY_HINT_GLOBAL_FILE, "*.keystore,*.jks")); - EDITOR_DEF("export/android/debug_keystore_user", "androiddebugkey"); - EDITOR_DEF("export/android/debug_keystore_pass", "android"); + EDITOR_DEF("export/android/debug_keystore_user", DEFAULT_ANDROID_KEYSTORE_DEBUG_USER); + EDITOR_DEF("export/android/debug_keystore_pass", DEFAULT_ANDROID_KEYSTORE_DEBUG_PASSWORD); EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/android/debug_keystore_pass", PROPERTY_HINT_PASSWORD)); EDITOR_DEF("export/android/force_system_user", false); diff --git a/platform/android/export/export_plugin.cpp b/platform/android/export/export_plugin.cpp index 7cab5e8d9092..3b1a534daf28 100644 --- a/platform/android/export/export_plugin.cpp +++ b/platform/android/export/export_plugin.cpp @@ -831,14 +831,82 @@ bool EditorExportPlatformAndroid::_uses_vulkan() { void EditorExportPlatformAndroid::_notification(int p_what) { #ifndef ANDROID_ENABLED - if (p_what == NOTIFICATION_POSTINITIALIZE) { - if (EditorExport::get_singleton()) { - EditorExport::get_singleton()->connect_presets_runnable_updated(callable_mp(this, &EditorExportPlatformAndroid::_update_preset_status)); - } + switch (p_what) { + case NOTIFICATION_POSTINITIALIZE: { + if (EditorExport::get_singleton()) { + EditorExport::get_singleton()->connect_presets_runnable_updated(callable_mp(this, &EditorExportPlatformAndroid::_update_preset_status)); + } + } break; + + case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: { + if (EditorSettings::get_singleton()->check_changed_settings_in_group("export/android")) { + _create_editor_debug_keystore_if_needed(); + } + } break; } #endif } +void EditorExportPlatformAndroid::_create_editor_debug_keystore_if_needed() { + // Check if we have a valid keytool path. + String keytool_path = get_keytool_path(); + if (!FileAccess::exists(keytool_path)) { + return; + } + + // Check if the current editor debug keystore exists. + String editor_debug_keystore = EDITOR_GET("export/android/debug_keystore"); + if (FileAccess::exists(editor_debug_keystore)) { + return; + } + + // Generate the debug keystore. + String keystore_path = EditorPaths::get_singleton()->get_debug_keystore_path(); + String keystores_dir = keystore_path.get_base_dir(); + if (!DirAccess::exists(keystores_dir)) { + Ref dir_access = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + Error err = dir_access->make_dir_recursive(keystores_dir); + if (err != OK) { + WARN_PRINT(TTR("Error creating keystores directory:") + "\n" + keystores_dir); + return; + } + } + + if (!FileAccess::exists(keystore_path)) { + String output; + List args; + args.push_back("-genkey"); + args.push_back("-keystore"); + args.push_back(keystore_path); + args.push_back("-storepass"); + args.push_back("android"); + args.push_back("-alias"); + args.push_back(DEFAULT_ANDROID_KEYSTORE_DEBUG_USER); + args.push_back("-keypass"); + args.push_back(DEFAULT_ANDROID_KEYSTORE_DEBUG_PASSWORD); + args.push_back("-keyalg"); + args.push_back("RSA"); + args.push_back("-keysize"); + args.push_back("2048"); + args.push_back("-validity"); + args.push_back("10000"); + args.push_back("-dname"); + args.push_back("cn=Godot, ou=Godot Engine, o=Stichting Godot, c=NL"); + Error error = OS::get_singleton()->execute(keytool_path, args, &output, nullptr, true); + print_verbose(output); + if (error != OK) { + WARN_PRINT("Error: Unable to create debug keystore"); + return; + } + } + + // Update the editor settings. + EditorSettings::get_singleton()->set("export/android/debug_keystore", keystore_path); + EditorSettings::get_singleton()->set("export/android/debug_keystore_user", DEFAULT_ANDROID_KEYSTORE_DEBUG_USER); + EditorSettings::get_singleton()->set("export/android/debug_keystore_pass", DEFAULT_ANDROID_KEYSTORE_DEBUG_PASSWORD); + print_verbose("Updated editor debug keystore to " + keystore_path); +} + void EditorExportPlatformAndroid::_get_permissions(const Ref &p_preset, bool p_give_internet, Vector &r_permissions) { const char **aperms = android_perms; while (*aperms) { @@ -2210,6 +2278,15 @@ String EditorExportPlatformAndroid::get_java_path() { return java_sdk_path.path_join("bin/java" + exe_ext); } +String EditorExportPlatformAndroid::get_keytool_path() { + String exe_ext; + if (OS::get_singleton()->get_name() == "Windows") { + exe_ext = ".exe"; + } + String java_sdk_path = EDITOR_GET("export/android/java_sdk_path"); + return java_sdk_path.path_join("bin/keytool" + exe_ext); +} + String EditorExportPlatformAndroid::get_adb_path() { String exe_ext; if (OS::get_singleton()->get_name() == "Windows") { @@ -3655,6 +3732,7 @@ EditorExportPlatformAndroid::EditorExportPlatformAndroid() { android_plugins_changed.set(); #endif // DISABLE_DEPRECATED #ifndef ANDROID_ENABLED + _create_editor_debug_keystore_if_needed(); _update_preset_status(); check_for_changes_thread.start(_check_for_changes_poll_thread, this); #endif diff --git a/platform/android/export/export_plugin.h b/platform/android/export/export_plugin.h index 7bc7bbf9e9c7..679afdc50f73 100644 --- a/platform/android/export/export_plugin.h +++ b/platform/android/export/export_plugin.h @@ -60,6 +60,9 @@ const String ENV_ANDROID_KEYSTORE_RELEASE_PATH = "GODOT_ANDROID_KEYSTORE_RELEASE const String ENV_ANDROID_KEYSTORE_RELEASE_USER = "GODOT_ANDROID_KEYSTORE_RELEASE_USER"; const String ENV_ANDROID_KEYSTORE_RELEASE_PASS = "GODOT_ANDROID_KEYSTORE_RELEASE_PASSWORD"; +const String DEFAULT_ANDROID_KEYSTORE_DEBUG_USER = "androiddebugkey"; +const String DEFAULT_ANDROID_KEYSTORE_DEBUG_PASSWORD = "android"; + struct LauncherIcon { const char *export_path; int dimensions = 0; @@ -188,6 +191,8 @@ class EditorExportPlatformAndroid : public EditorExportPlatform { const Ref &foreground, const Ref &background); + static void _create_editor_debug_keystore_if_needed(); + static Vector get_enabled_abis(const Ref &p_preset); static bool _uses_vulkan(); @@ -236,6 +241,8 @@ public: static String get_java_path(); + static String get_keytool_path(); + virtual bool has_valid_export_configuration(const Ref &p_preset, String &r_error, bool &r_missing_templates, bool p_debug = false) const override; virtual bool has_valid_project_configuration(const Ref &p_preset, String &r_error) const override; static bool has_valid_username_and_password(const Ref &p_preset, String &r_error);