You've already forked godot
mirror of
https://github.com/godotengine/godot.git
synced 2025-12-02 16:48:55 +00:00
Enable Gradle builds on the Android editor via a dedicated build app
Co-authored-by: Logan Lang <devloglogan@gmail.com>
This commit is contained in:
@@ -8528,8 +8528,8 @@ EditorNode::EditorNode() {
|
|||||||
project_menu->add_separator();
|
project_menu->add_separator();
|
||||||
project_menu->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/export", TTRC("Export..."), Key::NONE, TTRC("Export")), PROJECT_EXPORT);
|
project_menu->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/export", TTRC("Export..."), Key::NONE, TTRC("Export")), PROJECT_EXPORT);
|
||||||
project_menu->add_item(TTRC("Pack Project as ZIP..."), PROJECT_PACK_AS_ZIP);
|
project_menu->add_item(TTRC("Pack Project as ZIP..."), PROJECT_PACK_AS_ZIP);
|
||||||
#ifndef ANDROID_ENABLED
|
|
||||||
project_menu->add_item(TTRC("Install Android Build Template..."), PROJECT_INSTALL_ANDROID_SOURCE);
|
project_menu->add_item(TTRC("Install Android Build Template..."), PROJECT_INSTALL_ANDROID_SOURCE);
|
||||||
|
#ifndef ANDROID_ENABLED
|
||||||
project_menu->add_item(TTRC("Open User Data Folder"), PROJECT_OPEN_USER_DATA_FOLDER);
|
project_menu->add_item(TTRC("Open User Data Folder"), PROJECT_OPEN_USER_DATA_FOLDER);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
192
platform/android/export/android_editor_gradle_runner.cpp
Normal file
192
platform/android/export/android_editor_gradle_runner.cpp
Normal file
@@ -0,0 +1,192 @@
|
|||||||
|
/**************************************************************************/
|
||||||
|
/* android_editor_gradle_runner.cpp */
|
||||||
|
/**************************************************************************/
|
||||||
|
/* This file is part of: */
|
||||||
|
/* GODOT ENGINE */
|
||||||
|
/* https://godotengine.org */
|
||||||
|
/**************************************************************************/
|
||||||
|
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||||
|
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||||
|
/* */
|
||||||
|
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||||
|
/* a copy of this software and associated documentation files (the */
|
||||||
|
/* "Software"), to deal in the Software without restriction, including */
|
||||||
|
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||||
|
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||||
|
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||||
|
/* the following conditions: */
|
||||||
|
/* */
|
||||||
|
/* The above copyright notice and this permission notice shall be */
|
||||||
|
/* included in all copies or substantial portions of the Software. */
|
||||||
|
/* */
|
||||||
|
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||||
|
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||||
|
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||||
|
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||||
|
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||||
|
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||||
|
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
|
/**************************************************************************/
|
||||||
|
|
||||||
|
#ifdef ANDROID_ENABLED
|
||||||
|
#include "android_editor_gradle_runner.h"
|
||||||
|
|
||||||
|
#include "editor/editor_interface.h"
|
||||||
|
#include "scene/gui/dialogs.h"
|
||||||
|
#include "scene/gui/rich_text_label.h"
|
||||||
|
|
||||||
|
#include "../java_godot_wrapper.h"
|
||||||
|
#include "../os_android.h"
|
||||||
|
|
||||||
|
void AndroidEditorGradleRunner::run_gradle(const String &p_project_path, const String &p_build_path, const List<String> &p_gradle_build_args, const List<String> &p_gradle_copy_args) {
|
||||||
|
project_path = p_project_path;
|
||||||
|
build_path = p_build_path;
|
||||||
|
gradle_build_args = p_gradle_build_args;
|
||||||
|
gradle_copy_args = p_gradle_copy_args;
|
||||||
|
|
||||||
|
if (output_dialog == nullptr) {
|
||||||
|
output_label = memnew(RichTextLabel);
|
||||||
|
output_label->set_selection_enabled(true);
|
||||||
|
output_label->set_context_menu_enabled(true);
|
||||||
|
output_label->set_scroll_follow(true);
|
||||||
|
|
||||||
|
output_dialog = memnew(ConfirmationDialog);
|
||||||
|
output_dialog->set_unparent_when_invisible(true);
|
||||||
|
output_dialog->set_title(TTR("Building Android Project (gradle)"));
|
||||||
|
output_dialog->add_child(output_label);
|
||||||
|
|
||||||
|
output_dialog->connect("canceled", callable_mp(this, &AndroidEditorGradleRunner::_android_gradle_build_cancel));
|
||||||
|
}
|
||||||
|
|
||||||
|
output_label->clear();
|
||||||
|
output_dialog->get_ok_button()->set_disabled(true);
|
||||||
|
|
||||||
|
EditorInterface::get_singleton()->popup_dialog_centered_ratio(output_dialog);
|
||||||
|
|
||||||
|
state = STATE_BUILDING;
|
||||||
|
_android_gradle_build_connect();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AndroidEditorGradleRunner::_android_gradle_build_connect() {
|
||||||
|
_android_gradle_build_output(0, TTR("> Connecting to Gradle Build Environment..."));
|
||||||
|
|
||||||
|
GodotJavaWrapper *godot_java = OS_Android::get_singleton()->get_godot_java();
|
||||||
|
if (!godot_java->build_env_connect(callable_mp(this, &AndroidEditorGradleRunner::_android_gradle_build_build))) {
|
||||||
|
_android_gradle_build_failed(TTR("Unable to connect to Gradle Build Environment service"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AndroidEditorGradleRunner::_android_gradle_build_disconnect() {
|
||||||
|
GodotJavaWrapper *godot_java = OS_Android::get_singleton()->get_godot_java();
|
||||||
|
godot_java->build_env_disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AndroidEditorGradleRunner::_android_gradle_build_output(int p_type, const String &p_line) {
|
||||||
|
if (p_type == 0) {
|
||||||
|
print_line(p_line);
|
||||||
|
output_label->append_text("[color=green]" + p_line + "[/color]\n");
|
||||||
|
} else if (p_type == 1) {
|
||||||
|
print_line(p_line);
|
||||||
|
output_label->add_text(p_line + "\n");
|
||||||
|
} else {
|
||||||
|
print_error(p_line);
|
||||||
|
output_label->append_text("[color=red]" + p_line + "[/color]\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AndroidEditorGradleRunner::_android_gradle_build_build() {
|
||||||
|
_android_gradle_build_output(0, TTR("> Starting Gradle build..."));
|
||||||
|
|
||||||
|
GodotJavaWrapper *godot_java = OS_Android::get_singleton()->get_godot_java();
|
||||||
|
job_id = godot_java->build_env_execute(
|
||||||
|
"gradle",
|
||||||
|
gradle_build_args,
|
||||||
|
project_path,
|
||||||
|
build_path,
|
||||||
|
callable_mp(this, &AndroidEditorGradleRunner::_android_gradle_build_output),
|
||||||
|
callable_mp(this, &AndroidEditorGradleRunner::_android_gradle_build_build_callback));
|
||||||
|
if (job_id < 0) {
|
||||||
|
_android_gradle_build_failed(TTR("Failed to execute Gradle command"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AndroidEditorGradleRunner::_android_gradle_build_build_callback(int p_exit_code) {
|
||||||
|
job_id = -1;
|
||||||
|
if (p_exit_code != 0) {
|
||||||
|
_android_gradle_build_failed();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_android_gradle_build_copy();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AndroidEditorGradleRunner::_android_gradle_build_copy() {
|
||||||
|
_android_gradle_build_output(0, TTR("> Copying Gradle artifacts..."));
|
||||||
|
|
||||||
|
GodotJavaWrapper *godot_java = OS_Android::get_singleton()->get_godot_java();
|
||||||
|
job_id = godot_java->build_env_execute(
|
||||||
|
"gradle",
|
||||||
|
gradle_copy_args,
|
||||||
|
project_path,
|
||||||
|
build_path,
|
||||||
|
callable_mp(this, &AndroidEditorGradleRunner::_android_gradle_build_output),
|
||||||
|
callable_mp(this, &AndroidEditorGradleRunner::_android_gradle_build_copy_callback));
|
||||||
|
if (job_id < 0) {
|
||||||
|
_android_gradle_build_failed(TTR("Failed to execute Gradle command"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AndroidEditorGradleRunner::_android_gradle_build_copy_callback(int p_exit_code) {
|
||||||
|
job_id = -1;
|
||||||
|
if (p_exit_code != 0) {
|
||||||
|
_android_gradle_build_failed();
|
||||||
|
} else {
|
||||||
|
_android_gradle_build_clean_project(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AndroidEditorGradleRunner::_android_gradle_build_clean_project(bool p_was_successful) {
|
||||||
|
if (state != STATE_CLEANING) {
|
||||||
|
state = STATE_CLEANING;
|
||||||
|
|
||||||
|
if (p_was_successful) {
|
||||||
|
output_dialog->hide();
|
||||||
|
} else {
|
||||||
|
output_dialog->get_ok_button()->set_disabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
GodotJavaWrapper *godot_java = OS_Android::get_singleton()->get_godot_java();
|
||||||
|
godot_java->build_env_clean_project(
|
||||||
|
project_path,
|
||||||
|
build_path,
|
||||||
|
callable_mp(this, &AndroidEditorGradleRunner::_android_gradle_build_clean_project_callback));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AndroidEditorGradleRunner::_android_gradle_build_clean_project_callback() {
|
||||||
|
// Ensure we haven't switched back to STATE_BUILDING in the meantime.
|
||||||
|
if (state == STATE_CLEANING) {
|
||||||
|
_android_gradle_build_disconnect();
|
||||||
|
state = STATE_IDLE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AndroidEditorGradleRunner::_android_gradle_build_failed(const String &p_msg) {
|
||||||
|
job_id = -1;
|
||||||
|
|
||||||
|
if (p_msg != "") {
|
||||||
|
_android_gradle_build_output(1, p_msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
_android_gradle_build_clean_project(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AndroidEditorGradleRunner::_android_gradle_build_cancel() {
|
||||||
|
if (job_id > 0) {
|
||||||
|
GodotJavaWrapper *godot_java = OS_Android::get_singleton()->get_godot_java();
|
||||||
|
godot_java->build_env_cancel(job_id);
|
||||||
|
_android_gradle_build_clean_project(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // ANDROID_ENABLED
|
||||||
76
platform/android/export/android_editor_gradle_runner.h
Normal file
76
platform/android/export/android_editor_gradle_runner.h
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
/**************************************************************************/
|
||||||
|
/* android_editor_gradle_runner.h */
|
||||||
|
/**************************************************************************/
|
||||||
|
/* This file is part of: */
|
||||||
|
/* GODOT ENGINE */
|
||||||
|
/* https://godotengine.org */
|
||||||
|
/**************************************************************************/
|
||||||
|
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||||
|
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||||
|
/* */
|
||||||
|
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||||
|
/* a copy of this software and associated documentation files (the */
|
||||||
|
/* "Software"), to deal in the Software without restriction, including */
|
||||||
|
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||||
|
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||||
|
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||||
|
/* the following conditions: */
|
||||||
|
/* */
|
||||||
|
/* The above copyright notice and this permission notice shall be */
|
||||||
|
/* included in all copies or substantial portions of the Software. */
|
||||||
|
/* */
|
||||||
|
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||||
|
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||||
|
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||||
|
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||||
|
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||||
|
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||||
|
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
|
/**************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef ANDROID_ENABLED
|
||||||
|
|
||||||
|
#include "core/object/object.h"
|
||||||
|
|
||||||
|
class ConfirmationDialog;
|
||||||
|
class RichTextLabel;
|
||||||
|
|
||||||
|
class AndroidEditorGradleRunner : public Object {
|
||||||
|
GDCLASS(AndroidEditorGradleRunner, Object);
|
||||||
|
|
||||||
|
RichTextLabel *output_label = nullptr;
|
||||||
|
ConfirmationDialog *output_dialog = nullptr;
|
||||||
|
|
||||||
|
enum State {
|
||||||
|
STATE_IDLE,
|
||||||
|
STATE_BUILDING,
|
||||||
|
STATE_CLEANING,
|
||||||
|
};
|
||||||
|
State state = STATE_IDLE;
|
||||||
|
|
||||||
|
String project_path;
|
||||||
|
String build_path;
|
||||||
|
List<String> gradle_build_args;
|
||||||
|
List<String> gradle_copy_args;
|
||||||
|
int64_t job_id;
|
||||||
|
|
||||||
|
void _android_gradle_build_connect();
|
||||||
|
void _android_gradle_build_disconnect();
|
||||||
|
void _android_gradle_build_output(int p_type, const String &p_line);
|
||||||
|
void _android_gradle_build_build();
|
||||||
|
void _android_gradle_build_build_callback(int p_exit_code);
|
||||||
|
void _android_gradle_build_copy();
|
||||||
|
void _android_gradle_build_copy_callback(int p_exit_code);
|
||||||
|
void _android_gradle_build_clean_project(bool p_was_successful);
|
||||||
|
void _android_gradle_build_clean_project_callback();
|
||||||
|
|
||||||
|
void _android_gradle_build_failed(const String &p_msg = String());
|
||||||
|
void _android_gradle_build_cancel();
|
||||||
|
|
||||||
|
public:
|
||||||
|
void run_gradle(const String &p_project_path, const String &p_build_path, const List<String> &p_gradle_build_args, const List<String> &p_gradle_copy_args);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // ANDROID_ENABLED
|
||||||
@@ -60,7 +60,9 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef ANDROID_ENABLED
|
#ifdef ANDROID_ENABLED
|
||||||
|
#include "../java_godot_wrapper.h"
|
||||||
#include "../os_android.h"
|
#include "../os_android.h"
|
||||||
|
#include "android_editor_gradle_runner.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static const char *ANDROID_PERMS[] = {
|
static const char *ANDROID_PERMS[] = {
|
||||||
@@ -2015,6 +2017,11 @@ String EditorExportPlatformAndroid::get_export_option_warning(const EditorExport
|
|||||||
if (!enabled_deprecated_plugins_names.is_empty() && !gradle_build_enabled) {
|
if (!enabled_deprecated_plugins_names.is_empty() && !gradle_build_enabled) {
|
||||||
return TTR("\"Use Gradle Build\" must be enabled to use the plugins.");
|
return TTR("\"Use Gradle Build\" must be enabled to use the plugins.");
|
||||||
}
|
}
|
||||||
|
#ifdef ANDROID_ENABLED
|
||||||
|
if (gradle_build_enabled) {
|
||||||
|
return TTR("Support for \"Use Gradle Build\" on Android is currently experimental.");
|
||||||
|
}
|
||||||
|
#endif // ANDROID_ENABLED
|
||||||
} else if (p_name == "gradle_build/compress_native_libraries") {
|
} else if (p_name == "gradle_build/compress_native_libraries") {
|
||||||
bool gradle_build_enabled = p_preset->get("gradle_build/use_gradle_build");
|
bool gradle_build_enabled = p_preset->get("gradle_build/use_gradle_build");
|
||||||
if (bool(p_preset->get("gradle_build/compress_native_libraries")) && !gradle_build_enabled) {
|
if (bool(p_preset->get("gradle_build/compress_native_libraries")) && !gradle_build_enabled) {
|
||||||
@@ -2100,7 +2107,7 @@ void EditorExportPlatformAndroid::get_export_options(List<ExportOption> *r_optio
|
|||||||
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/debug", PROPERTY_HINT_GLOBAL_FILE, "*.apk"), ""));
|
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/debug", PROPERTY_HINT_GLOBAL_FILE, "*.apk"), ""));
|
||||||
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/release", PROPERTY_HINT_GLOBAL_FILE, "*.apk"), ""));
|
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/release", PROPERTY_HINT_GLOBAL_FILE, "*.apk"), ""));
|
||||||
|
|
||||||
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "gradle_build/use_gradle_build"), false, true, true));
|
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "gradle_build/use_gradle_build"), false, true, false));
|
||||||
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "gradle_build/gradle_build_directory", PROPERTY_HINT_PLACEHOLDER_TEXT, "res://android"), "", false, false));
|
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "gradle_build/gradle_build_directory", PROPERTY_HINT_PLACEHOLDER_TEXT, "res://android"), "", false, false));
|
||||||
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "gradle_build/android_source_template", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), ""));
|
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "gradle_build/android_source_template", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), ""));
|
||||||
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "gradle_build/compress_native_libraries"), false, false, true));
|
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "gradle_build/compress_native_libraries"), false, false, true));
|
||||||
@@ -2889,10 +2896,6 @@ bool EditorExportPlatformAndroid::has_valid_export_configuration(const Ref<Edito
|
|||||||
err += template_err;
|
err += template_err;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
#ifdef ANDROID_ENABLED
|
|
||||||
err += TTR("Gradle build is not supported for the Android editor.") + "\n";
|
|
||||||
valid = false;
|
|
||||||
#else
|
|
||||||
// Validate the custom gradle android source template.
|
// Validate the custom gradle android source template.
|
||||||
bool android_source_template_valid = false;
|
bool android_source_template_valid = false;
|
||||||
const String android_source_template = p_preset->get("gradle_build/android_source_template");
|
const String android_source_template = p_preset->get("gradle_build/android_source_template");
|
||||||
@@ -2915,7 +2918,6 @@ bool EditorExportPlatformAndroid::has_valid_export_configuration(const Ref<Edito
|
|||||||
}
|
}
|
||||||
|
|
||||||
valid = installed_android_build_template && !r_missing_templates;
|
valid = installed_android_build_template && !r_missing_templates;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate the rest of the export configuration.
|
// Validate the rest of the export configuration.
|
||||||
@@ -3665,6 +3667,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
const String assets_directory = get_assets_directory(p_preset, export_format);
|
const String assets_directory = get_assets_directory(p_preset, export_format);
|
||||||
|
#ifndef ANDROID_ENABLED
|
||||||
String java_sdk_path = EDITOR_GET("export/android/java_sdk_path");
|
String java_sdk_path = EDITOR_GET("export/android/java_sdk_path");
|
||||||
if (java_sdk_path.is_empty()) {
|
if (java_sdk_path.is_empty()) {
|
||||||
add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), TTR("Java SDK path must be configured in Editor Settings at 'export/android/java_sdk_path'."));
|
add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), TTR("Java SDK path must be configured in Editor Settings at 'export/android/java_sdk_path'."));
|
||||||
@@ -3678,6 +3681,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
|
|||||||
return ERR_UNCONFIGURED;
|
return ERR_UNCONFIGURED;
|
||||||
}
|
}
|
||||||
print_verbose("Android sdk path: " + sdk_path);
|
print_verbose("Android sdk path: " + sdk_path);
|
||||||
|
#endif
|
||||||
|
|
||||||
// TODO: should we use "package/name" or "application/config/name"?
|
// TODO: should we use "package/name" or "application/config/name"?
|
||||||
String project_name = get_project_name(p_preset, p_preset->get("package/name"));
|
String project_name = get_project_name(p_preset, p_preset->get("package/name"));
|
||||||
@@ -3738,14 +3742,17 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
print_verbose("Storing command line flags...");
|
print_verbose("Storing command line flags...");
|
||||||
store_file_at_path(assets_directory + "/_cl_", command_line_flags);
|
store_file_at_path(assets_directory + "/_cl_", command_line_flags);
|
||||||
|
|
||||||
|
#ifndef ANDROID_ENABLED
|
||||||
print_verbose("Updating JAVA_HOME environment to " + java_sdk_path);
|
print_verbose("Updating JAVA_HOME environment to " + java_sdk_path);
|
||||||
OS::get_singleton()->set_environment("JAVA_HOME", java_sdk_path);
|
OS::get_singleton()->set_environment("JAVA_HOME", java_sdk_path);
|
||||||
|
|
||||||
print_verbose("Updating ANDROID_HOME environment to " + sdk_path);
|
print_verbose("Updating ANDROID_HOME environment to " + sdk_path);
|
||||||
OS::get_singleton()->set_environment("ANDROID_HOME", sdk_path);
|
OS::get_singleton()->set_environment("ANDROID_HOME", sdk_path);
|
||||||
|
#endif
|
||||||
String build_command;
|
String build_command;
|
||||||
|
|
||||||
#ifdef WINDOWS_ENABLED
|
#ifdef WINDOWS_ENABLED
|
||||||
@@ -3832,8 +3839,10 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
|
|||||||
|
|
||||||
String addons_directory = ProjectSettings::get_singleton()->globalize_path("res://addons");
|
String addons_directory = ProjectSettings::get_singleton()->globalize_path("res://addons");
|
||||||
|
|
||||||
|
#ifndef ANDROID_ENABLED
|
||||||
cmdline.push_back("-p"); // argument to specify the start directory.
|
cmdline.push_back("-p"); // argument to specify the start directory.
|
||||||
cmdline.push_back(build_path); // start directory.
|
cmdline.push_back(build_path); // start directory.
|
||||||
|
#endif
|
||||||
cmdline.push_back("-Paddons_directory=" + addons_directory); // path to the addon directory as it may contain jar or aar dependencies
|
cmdline.push_back("-Paddons_directory=" + addons_directory); // path to the addon directory as it may contain jar or aar dependencies
|
||||||
cmdline.push_back("-Pexport_package_name=" + package_name); // argument to specify the package name.
|
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_code=" + version_code); // argument to specify the version code.
|
||||||
@@ -3872,6 +3881,25 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
|
|||||||
add_message(EXPORT_MESSAGE_ERROR, TTR("Code Signing"), TTR("Could not find debug keystore, unable to export."));
|
add_message(EXPORT_MESSAGE_ERROR, TTR("Code Signing"), TTR("Could not find debug keystore, unable to export."));
|
||||||
return ERR_FILE_CANT_OPEN;
|
return ERR_FILE_CANT_OPEN;
|
||||||
}
|
}
|
||||||
|
#ifdef ANDROID_ENABLED
|
||||||
|
if (debug_keystore.begins_with("assets://")) {
|
||||||
|
// The Gradle build environment app can't access the Godot
|
||||||
|
// editor's assets, so we need to copy this to temp file.
|
||||||
|
Error err;
|
||||||
|
PackedByteArray keystore_data = FileAccess::get_file_as_bytes(debug_keystore, &err);
|
||||||
|
if (err == OK) {
|
||||||
|
String temp_dir = build_path + "/.android";
|
||||||
|
String temp_filename = temp_dir + "/debug.keystore";
|
||||||
|
|
||||||
|
DirAccess::make_dir_recursive_absolute(temp_dir);
|
||||||
|
Ref<FileAccess> temp_file = FileAccess::open(temp_filename, FileAccess::WRITE);
|
||||||
|
if (temp_file.is_valid()) {
|
||||||
|
temp_file->store_buffer(keystore_data);
|
||||||
|
debug_keystore = temp_filename;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
cmdline.push_back("-Pdebug_keystore_file=" + debug_keystore); // argument to specify the debug keystore file.
|
cmdline.push_back("-Pdebug_keystore_file=" + debug_keystore); // argument to specify the debug keystore file.
|
||||||
cmdline.push_back("-Pdebug_keystore_alias=" + debug_user); // argument to specify the debug keystore alias.
|
cmdline.push_back("-Pdebug_keystore_alias=" + debug_user); // argument to specify the debug keystore alias.
|
||||||
@@ -3895,21 +3923,14 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String build_project_output;
|
|
||||||
int result = EditorNode::get_singleton()->execute_and_show_output(TTR("Building Android Project (gradle)"), build_command, cmdline, true, false, &build_project_output);
|
|
||||||
if (result != 0) {
|
|
||||||
add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), TTR("Building of Android project failed, check output for the error:") + "\n\n" + build_project_output);
|
|
||||||
return ERR_CANT_CREATE;
|
|
||||||
} else {
|
|
||||||
print_verbose(build_project_output);
|
|
||||||
}
|
|
||||||
|
|
||||||
List<String> copy_args;
|
List<String> copy_args;
|
||||||
String copy_command = "copyAndRenameBinary";
|
String copy_command = "copyAndRenameBinary";
|
||||||
copy_args.push_back(copy_command);
|
copy_args.push_back(copy_command);
|
||||||
|
|
||||||
|
#ifndef ANDROID_ENABLED
|
||||||
copy_args.push_back("-p"); // argument to specify the start directory.
|
copy_args.push_back("-p"); // argument to specify the start directory.
|
||||||
copy_args.push_back(build_path); // start directory.
|
copy_args.push_back(build_path); // start directory.
|
||||||
|
#endif
|
||||||
|
|
||||||
copy_args.push_back("-Pexport_edition=" + edition.to_lower());
|
copy_args.push_back("-Pexport_edition=" + edition.to_lower());
|
||||||
|
|
||||||
@@ -3928,6 +3949,23 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
|
|||||||
copy_args.push_back("-Pexport_path=file:" + export_path);
|
copy_args.push_back("-Pexport_path=file:" + export_path);
|
||||||
copy_args.push_back("-Pexport_filename=" + export_filename);
|
copy_args.push_back("-Pexport_filename=" + export_filename);
|
||||||
|
|
||||||
|
#ifdef ANDROID_ENABLED
|
||||||
|
String project_path = ProjectSettings::get_singleton()->globalize_path("res://");
|
||||||
|
android_editor_gradle_runner->run_gradle(
|
||||||
|
project_path,
|
||||||
|
build_path.substr(project_path.length()),
|
||||||
|
cmdline,
|
||||||
|
copy_args);
|
||||||
|
#else
|
||||||
|
String build_project_output;
|
||||||
|
int result = EditorNode::get_singleton()->execute_and_show_output(TTR("Building Android Project (gradle)"), build_command, cmdline, true, false, &build_project_output);
|
||||||
|
if (result != 0) {
|
||||||
|
add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), TTR("Building of Android project failed, check output for the error:") + "\n\n" + build_project_output);
|
||||||
|
return ERR_CANT_CREATE;
|
||||||
|
} else {
|
||||||
|
print_verbose(build_project_output);
|
||||||
|
}
|
||||||
|
|
||||||
print_verbose("Copying Android binary using gradle command: " + String("\n") + build_command + " " + join_list(copy_args, String(" ")));
|
print_verbose("Copying Android binary using gradle command: " + String("\n") + build_command + " " + join_list(copy_args, String(" ")));
|
||||||
String copy_binary_output;
|
String copy_binary_output;
|
||||||
int copy_result = EditorNode::get_singleton()->execute_and_show_output(TTR("Moving output"), build_command, copy_args, true, false, ©_binary_output);
|
int copy_result = EditorNode::get_singleton()->execute_and_show_output(TTR("Moving output"), build_command, copy_args, true, false, ©_binary_output);
|
||||||
@@ -3939,6 +3977,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
|
|||||||
}
|
}
|
||||||
|
|
||||||
print_verbose("Successfully completed Android gradle build.");
|
print_verbose("Successfully completed Android gradle build.");
|
||||||
|
#endif
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
// This is the start of the Legacy build system
|
// This is the start of the Legacy build system
|
||||||
@@ -4338,6 +4377,8 @@ void EditorExportPlatformAndroid::initialize() {
|
|||||||
_create_editor_debug_keystore_if_needed();
|
_create_editor_debug_keystore_if_needed();
|
||||||
_update_preset_status();
|
_update_preset_status();
|
||||||
check_for_changes_thread.start(_check_for_changes_poll_thread, this);
|
check_for_changes_thread.start(_check_for_changes_poll_thread, this);
|
||||||
|
#else
|
||||||
|
android_editor_gradle_runner = memnew(AndroidEditorGradleRunner);
|
||||||
#endif
|
#endif
|
||||||
use_scrcpy = EditorSettings::get_singleton()->get_project_metadata("android", "use_scrcpy", false);
|
use_scrcpy = EditorSettings::get_singleton()->get_project_metadata("android", "use_scrcpy", false);
|
||||||
}
|
}
|
||||||
@@ -4349,5 +4390,9 @@ EditorExportPlatformAndroid::~EditorExportPlatformAndroid() {
|
|||||||
if (check_for_changes_thread.is_started()) {
|
if (check_for_changes_thread.is_started()) {
|
||||||
check_for_changes_thread.wait_to_finish();
|
check_for_changes_thread.wait_to_finish();
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
if (android_editor_gradle_runner) {
|
||||||
|
memdelete(android_editor_gradle_runner);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,6 +60,8 @@ struct LauncherIcon {
|
|||||||
int dimensions = 0;
|
int dimensions = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class AndroidEditorGradleRunner;
|
||||||
|
|
||||||
class EditorExportPlatformAndroid : public EditorExportPlatform {
|
class EditorExportPlatformAndroid : public EditorExportPlatform {
|
||||||
GDCLASS(EditorExportPlatformAndroid, EditorExportPlatform);
|
GDCLASS(EditorExportPlatformAndroid, EditorExportPlatform);
|
||||||
|
|
||||||
@@ -106,6 +108,8 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
|
|||||||
|
|
||||||
static void _check_for_changes_poll_thread(void *ud);
|
static void _check_for_changes_poll_thread(void *ud);
|
||||||
void _update_preset_status();
|
void _update_preset_status();
|
||||||
|
#else
|
||||||
|
AndroidEditorGradleRunner *android_editor_gradle_runner = nullptr;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
String get_project_name(const Ref<EditorExportPreset> &p_preset, const String &p_name) const;
|
String get_project_name(const Ref<EditorExportPreset> &p_preset, const String &p_name) const;
|
||||||
|
|||||||
@@ -3,6 +3,10 @@
|
|||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:installLocation="auto">
|
android:installLocation="auto">
|
||||||
|
|
||||||
|
<queries>
|
||||||
|
<package android:name="org.godotengine.godot_gradle_build_environment" />
|
||||||
|
</queries>
|
||||||
|
|
||||||
<supports-screens
|
<supports-screens
|
||||||
android:largeScreens="true"
|
android:largeScreens="true"
|
||||||
android:normalScreens="true"
|
android:normalScreens="true"
|
||||||
|
|||||||
@@ -53,11 +53,12 @@ import androidx.core.content.edit
|
|||||||
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
|
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.window.layout.WindowMetricsCalculator
|
import androidx.window.layout.WindowMetricsCalculator
|
||||||
|
import org.godotengine.editor.buildprovider.GradleBuildProvider
|
||||||
import org.godotengine.editor.embed.EmbeddedGodotGame
|
import org.godotengine.editor.embed.EmbeddedGodotGame
|
||||||
import org.godotengine.editor.embed.GameMenuFragment
|
import org.godotengine.editor.embed.GameMenuFragment
|
||||||
import org.godotengine.editor.utils.signApk
|
import org.godotengine.editor.utils.signApk
|
||||||
import org.godotengine.editor.utils.verifyApk
|
import org.godotengine.editor.utils.verifyApk
|
||||||
import org.godotengine.godot.BuildConfig
|
import org.godotengine.godot.BuildProvider
|
||||||
import org.godotengine.godot.Godot
|
import org.godotengine.godot.Godot
|
||||||
import org.godotengine.godot.GodotActivity
|
import org.godotengine.godot.GodotActivity
|
||||||
import org.godotengine.godot.GodotLib
|
import org.godotengine.godot.GodotLib
|
||||||
@@ -171,6 +172,7 @@ abstract class BaseGodotEditor : GodotActivity(), GameMenuFragment.GameMenuListe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal val gradleBuildProvider: GradleBuildProvider = GradleBuildProvider(this, this)
|
||||||
internal val editorMessageDispatcher = EditorMessageDispatcher(this)
|
internal val editorMessageDispatcher = EditorMessageDispatcher(this)
|
||||||
private val editorLoadingIndicator: View? by lazy { findViewById(R.id.editor_loading_indicator) }
|
private val editorLoadingIndicator: View? by lazy { findViewById(R.id.editor_loading_indicator) }
|
||||||
|
|
||||||
@@ -262,6 +264,11 @@ abstract class BaseGodotEditor : GodotActivity(), GameMenuFragment.GameMenuListe
|
|||||||
setupGameMenuBar()
|
setupGameMenuBar()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
gradleBuildProvider.buildEnvDisconnect()
|
||||||
|
super.onDestroy()
|
||||||
|
}
|
||||||
|
|
||||||
override fun onNewIntent(newIntent: Intent) {
|
override fun onNewIntent(newIntent: Intent) {
|
||||||
if (newIntent.hasCategory(HYBRID_APP_PANEL_CATEGORY) || newIntent.hasCategory(HYBRID_APP_IMMERSIVE_CATEGORY)) {
|
if (newIntent.hasCategory(HYBRID_APP_PANEL_CATEGORY) || newIntent.hasCategory(HYBRID_APP_IMMERSIVE_CATEGORY)) {
|
||||||
val params = retrieveCommandLineParamsFromLaunchIntent(newIntent)
|
val params = retrieveCommandLineParamsFromLaunchIntent(newIntent)
|
||||||
@@ -968,4 +975,8 @@ abstract class BaseGodotEditor : GodotActivity(), GameMenuFragment.GameMenuListe
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun isGameEmbeddingSupported() = !isNativeXRDevice(applicationContext)
|
override fun isGameEmbeddingSupported() = !isNativeXRDevice(applicationContext)
|
||||||
|
|
||||||
|
override fun getBuildProvider(): BuildProvider? {
|
||||||
|
return gradleBuildProvider
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,225 @@
|
|||||||
|
/**************************************************************************/
|
||||||
|
/* GradleBuildEnvironmentClient.kt */
|
||||||
|
/**************************************************************************/
|
||||||
|
/* This file is part of: */
|
||||||
|
/* GODOT ENGINE */
|
||||||
|
/* https://godotengine.org */
|
||||||
|
/**************************************************************************/
|
||||||
|
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||||
|
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||||
|
/* */
|
||||||
|
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||||
|
/* a copy of this software and associated documentation files (the */
|
||||||
|
/* "Software"), to deal in the Software without restriction, including */
|
||||||
|
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||||
|
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||||
|
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||||
|
/* the following conditions: */
|
||||||
|
/* */
|
||||||
|
/* The above copyright notice and this permission notice shall be */
|
||||||
|
/* included in all copies or substantial portions of the Software. */
|
||||||
|
/* */
|
||||||
|
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||||
|
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||||
|
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||||
|
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||||
|
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||||
|
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||||
|
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
|
/**************************************************************************/
|
||||||
|
|
||||||
|
package org.godotengine.editor.buildprovider
|
||||||
|
|
||||||
|
import android.content.ComponentName
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.content.ServiceConnection
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.os.Handler
|
||||||
|
import android.os.IBinder
|
||||||
|
import android.os.Message
|
||||||
|
import android.os.Messenger
|
||||||
|
import android.os.RemoteException
|
||||||
|
import android.util.Log
|
||||||
|
import kotlin.collections.set
|
||||||
|
|
||||||
|
private const val MSG_EXECUTE_GRADLE = 1
|
||||||
|
private const val MSG_COMMAND_RESULT = 2
|
||||||
|
private const val MSG_COMMAND_OUTPUT = 3
|
||||||
|
private const val MSG_CANCEL_COMMAND = 4
|
||||||
|
private const val MSG_CLEAN_PROJECT = 5
|
||||||
|
|
||||||
|
internal class GradleBuildEnvironmentClient(private val context: Context) {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val TAG = GradleBuildEnvironmentClient::class.java.simpleName
|
||||||
|
}
|
||||||
|
|
||||||
|
private var bound: Boolean = false
|
||||||
|
private var outgoingMessenger: Messenger? = null
|
||||||
|
private val connection = object : ServiceConnection {
|
||||||
|
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
|
||||||
|
outgoingMessenger = Messenger(service)
|
||||||
|
bound = true
|
||||||
|
|
||||||
|
Log.i(TAG, "Service connected")
|
||||||
|
for (callable in connectionCallbacks) {
|
||||||
|
callable()
|
||||||
|
}
|
||||||
|
connectionCallbacks.clear()
|
||||||
|
connecting = false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onServiceDisconnected(name: ComponentName?) {
|
||||||
|
outgoingMessenger = null
|
||||||
|
bound = false
|
||||||
|
Log.i(TAG, "Service disconnected")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private inner class IncomingHandler: Handler() {
|
||||||
|
override fun handleMessage(msg: Message) {
|
||||||
|
when (msg.what) {
|
||||||
|
MSG_COMMAND_RESULT -> {
|
||||||
|
this@GradleBuildEnvironmentClient.receiveCommandResult(msg)
|
||||||
|
}
|
||||||
|
MSG_COMMAND_OUTPUT -> {
|
||||||
|
this@GradleBuildEnvironmentClient.receiveCommandOutput(msg)
|
||||||
|
}
|
||||||
|
else -> super.handleMessage(msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private val incomingMessenger = Messenger(IncomingHandler())
|
||||||
|
|
||||||
|
private val connectionCallbacks = mutableListOf<() -> Unit>()
|
||||||
|
private var connecting = false
|
||||||
|
private var executionId = 1000
|
||||||
|
|
||||||
|
private class ExecutionInfo(val outputCallback: (Int, String) -> Unit, val resultCallback: (Int) -> Unit)
|
||||||
|
private val executionMap = HashMap<Int, ExecutionInfo>()
|
||||||
|
|
||||||
|
fun connect(callback: () -> Unit): Boolean {
|
||||||
|
if (bound) {
|
||||||
|
callback()
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
connectionCallbacks.add(callback)
|
||||||
|
if (connecting) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
connecting = true;
|
||||||
|
|
||||||
|
val intent = Intent("org.godotengine.action.BUILD_PROVIDER").apply {
|
||||||
|
setPackage("org.godotengine.godot_gradle_build_environment")
|
||||||
|
}
|
||||||
|
val info = context.packageManager.resolveService(intent, 0)
|
||||||
|
if (info == null) {
|
||||||
|
connecting = false;
|
||||||
|
Log.e(TAG, "Unable to resolve service")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
val result = context.bindService(intent, connection, Context.BIND_AUTO_CREATE)
|
||||||
|
if (!result) {
|
||||||
|
Log.e(TAG, "Unable to bind to service")
|
||||||
|
connecting = false;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
fun disconnect() {
|
||||||
|
if (bound) {
|
||||||
|
context.unbindService(connection)
|
||||||
|
bound = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getNextExecutionId(outputCallback: (Int, String) -> Unit, resultCallback: (Int) -> Unit): Int {
|
||||||
|
val id = executionId++
|
||||||
|
executionMap[id] = ExecutionInfo(outputCallback, resultCallback)
|
||||||
|
return id
|
||||||
|
}
|
||||||
|
|
||||||
|
fun execute(arguments: Array<String>, projectPath: String, gradleBuildDir: String, outputCallback: (Int, String) -> Unit, resultCallback: (Int) -> Unit): Int {
|
||||||
|
if (outgoingMessenger == null) {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
val msg: Message = Message.obtain(null, MSG_EXECUTE_GRADLE, getNextExecutionId(outputCallback, resultCallback),0)
|
||||||
|
msg.replyTo = incomingMessenger
|
||||||
|
|
||||||
|
val data = Bundle()
|
||||||
|
data.putStringArrayList("arguments", ArrayList(arguments.toList()))
|
||||||
|
data.putString("project_path", projectPath)
|
||||||
|
data.putString("gradle_build_directory", gradleBuildDir)
|
||||||
|
msg.data = data
|
||||||
|
|
||||||
|
try {
|
||||||
|
outgoingMessenger?.send(msg)
|
||||||
|
} catch (e: RemoteException) {
|
||||||
|
Log.e(TAG, "Unable to execute Gradle command: gradlew ${arguments.joinToString(" ")}", e)
|
||||||
|
e.printStackTrace()
|
||||||
|
executionMap.remove(msg.arg1)
|
||||||
|
resultCallback(255)
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
return msg.arg1
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun receiveCommandResult(msg: Message) {
|
||||||
|
val executionInfo = executionMap.remove(msg.arg1)
|
||||||
|
executionInfo?.resultCallback?.invoke(msg.arg2)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun receiveCommandOutput(msg: Message) {
|
||||||
|
val data = msg.data
|
||||||
|
val line = data.getString("line")
|
||||||
|
|
||||||
|
if (line != null) {
|
||||||
|
val executionInfo = executionMap.get(msg.arg1)
|
||||||
|
executionInfo?.outputCallback?.invoke(msg.arg2, line)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun cancel(jobId: Int) {
|
||||||
|
if (outgoingMessenger == null) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val msg: Message = Message.obtain(null, MSG_CANCEL_COMMAND, jobId, 0)
|
||||||
|
try {
|
||||||
|
outgoingMessenger?.send(msg)
|
||||||
|
} catch (e: RemoteException) {
|
||||||
|
Log.e(TAG, "Unable to cancel Gradle command: ${jobId}", e)
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun cleanProject(projectPath: String, gradleBuildDir: String, resultCallback: (Int) -> Unit) {
|
||||||
|
if (outgoingMessenger == null) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val emptyOutputCallback: (Int, String) -> Unit = { outputType, line -> }
|
||||||
|
|
||||||
|
val msg: Message = Message.obtain(null, MSG_CLEAN_PROJECT, getNextExecutionId(emptyOutputCallback, resultCallback), 0)
|
||||||
|
msg.replyTo = incomingMessenger
|
||||||
|
|
||||||
|
val data = Bundle()
|
||||||
|
data.putString("project_path", projectPath)
|
||||||
|
data.putString("gradle_build_directory", gradleBuildDir)
|
||||||
|
msg.data = data
|
||||||
|
|
||||||
|
try {
|
||||||
|
outgoingMessenger?.send(msg)
|
||||||
|
} catch (e: RemoteException) {
|
||||||
|
Log.e(TAG, "Unable to clean Gradle project", e)
|
||||||
|
executionMap.remove(msg.arg1)
|
||||||
|
resultCallback(0)
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
/**************************************************************************/
|
||||||
|
/* GradleBuildProvider.kt */
|
||||||
|
/**************************************************************************/
|
||||||
|
/* This file is part of: */
|
||||||
|
/* GODOT ENGINE */
|
||||||
|
/* https://godotengine.org */
|
||||||
|
/**************************************************************************/
|
||||||
|
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||||
|
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||||
|
/* */
|
||||||
|
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||||
|
/* a copy of this software and associated documentation files (the */
|
||||||
|
/* "Software"), to deal in the Software without restriction, including */
|
||||||
|
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||||
|
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||||
|
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||||
|
/* the following conditions: */
|
||||||
|
/* */
|
||||||
|
/* The above copyright notice and this permission notice shall be */
|
||||||
|
/* included in all copies or substantial portions of the Software. */
|
||||||
|
/* */
|
||||||
|
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||||
|
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||||
|
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||||
|
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||||
|
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||||
|
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||||
|
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
|
/**************************************************************************/
|
||||||
|
|
||||||
|
package org.godotengine.editor.buildprovider
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import org.godotengine.godot.BuildProvider
|
||||||
|
import org.godotengine.godot.GodotHost
|
||||||
|
import org.godotengine.godot.variant.Callable
|
||||||
|
|
||||||
|
internal class GradleBuildProvider(
|
||||||
|
val context: Context,
|
||||||
|
val host: GodotHost,
|
||||||
|
) : BuildProvider {
|
||||||
|
|
||||||
|
val gradleBuildEnvironmentClient = GradleBuildEnvironmentClient(context)
|
||||||
|
|
||||||
|
val godot get() = host.godot
|
||||||
|
|
||||||
|
override fun buildEnvConnect(callback: Callable): Boolean {
|
||||||
|
return gradleBuildEnvironmentClient.connect {
|
||||||
|
godot?.runOnRenderThread {
|
||||||
|
callback.call()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun buildEnvDisconnect() {
|
||||||
|
gradleBuildEnvironmentClient.disconnect()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun buildEnvExecute(
|
||||||
|
buildTool: String,
|
||||||
|
arguments: Array<String>,
|
||||||
|
projectPath: String,
|
||||||
|
buildDir: String,
|
||||||
|
outputCallback: Callable,
|
||||||
|
resultCallback: Callable
|
||||||
|
): Int {
|
||||||
|
if (buildTool != "gradle") {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
val outputCb: (Int, String) -> Unit = { outputType, line ->
|
||||||
|
godot?.runOnRenderThread {
|
||||||
|
outputCallback.call(outputType, line)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val resultCb: (Int) -> Unit = { exitCode ->
|
||||||
|
godot?.runOnRenderThread {
|
||||||
|
resultCallback.call(exitCode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return gradleBuildEnvironmentClient.execute(arguments, projectPath, buildDir, outputCb, resultCb)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun buildEnvCancel(jobId: Int) {
|
||||||
|
gradleBuildEnvironmentClient.cancel(jobId)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun buildEnvCleanProject(projectPath: String, buildDir: String, callback: Callable) {
|
||||||
|
val cb: (Int) -> Unit = { exitCode ->
|
||||||
|
godot?.runOnRenderThread {
|
||||||
|
callback.call()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gradleBuildEnvironmentClient.cleanProject(projectPath, buildDir, cb)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
/**************************************************************************/
|
||||||
|
/* BuildProvider.java */
|
||||||
|
/**************************************************************************/
|
||||||
|
/* This file is part of: */
|
||||||
|
/* GODOT ENGINE */
|
||||||
|
/* https://godotengine.org */
|
||||||
|
/**************************************************************************/
|
||||||
|
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||||
|
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||||
|
/* */
|
||||||
|
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||||
|
/* a copy of this software and associated documentation files (the */
|
||||||
|
/* "Software"), to deal in the Software without restriction, including */
|
||||||
|
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||||
|
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||||
|
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||||
|
/* the following conditions: */
|
||||||
|
/* */
|
||||||
|
/* The above copyright notice and this permission notice shall be */
|
||||||
|
/* included in all copies or substantial portions of the Software. */
|
||||||
|
/* */
|
||||||
|
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||||
|
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||||
|
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||||
|
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||||
|
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||||
|
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||||
|
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
|
/**************************************************************************/
|
||||||
|
|
||||||
|
package org.godotengine.godot;
|
||||||
|
|
||||||
|
import org.godotengine.godot.variant.Callable;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides an environment for executing build commands.
|
||||||
|
*/
|
||||||
|
public interface BuildProvider {
|
||||||
|
/**
|
||||||
|
* Connects to the build environment.
|
||||||
|
*
|
||||||
|
* @param callback The callback to call when connected
|
||||||
|
* @return Whether or not connecting is possible
|
||||||
|
*/
|
||||||
|
boolean buildEnvConnect(@NonNull Callable callback);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disconnects from the build environment.
|
||||||
|
*/
|
||||||
|
void buildEnvDisconnect();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes a command via the build environment.
|
||||||
|
*
|
||||||
|
* @param buildTool The build tool to execute (for example, "gradle")
|
||||||
|
* @param arguments The argument for the command
|
||||||
|
* @param projectPath The working directory to use when executing the command
|
||||||
|
* @param buildDir The build directory within the project
|
||||||
|
* @param outputCallback The callback to call for each line of output from the command
|
||||||
|
* @param resultCallback The callback to call when the command is finished running
|
||||||
|
* @return A positive job id, if successful; otherwise, a negative number
|
||||||
|
*/
|
||||||
|
int buildEnvExecute(String buildTool, @NonNull String[] arguments, @NonNull String projectPath, @NonNull String buildDir, @NonNull Callable outputCallback, @NonNull Callable resultCallback);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancels a command executed via the build environment.
|
||||||
|
*
|
||||||
|
* @param jobId The job id returned from buildEnvExecute()
|
||||||
|
*/
|
||||||
|
void buildEnvCancel(int jobId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Requests that a project be cleaned up via the build environment.
|
||||||
|
*
|
||||||
|
* @param projectPath The working directory to use when executing the command
|
||||||
|
* @param buildDir The build directory within the project
|
||||||
|
*/
|
||||||
|
void buildEnvCleanProject(@NonNull String projectPath, @NonNull String buildDir, @NonNull Callable callback);
|
||||||
|
}
|
||||||
@@ -75,6 +75,7 @@ import org.godotengine.godot.utils.benchmarkFile
|
|||||||
import org.godotengine.godot.utils.dumpBenchmark
|
import org.godotengine.godot.utils.dumpBenchmark
|
||||||
import org.godotengine.godot.utils.endBenchmarkMeasure
|
import org.godotengine.godot.utils.endBenchmarkMeasure
|
||||||
import org.godotengine.godot.utils.useBenchmark
|
import org.godotengine.godot.utils.useBenchmark
|
||||||
|
import org.godotengine.godot.variant.Callable as GodotCallable
|
||||||
import org.godotengine.godot.xr.XRMode
|
import org.godotengine.godot.xr.XRMode
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.FileInputStream
|
import java.io.FileInputStream
|
||||||
@@ -1304,4 +1305,64 @@ class Godot private constructor(val context: Context) {
|
|||||||
private fun nativeOnEditorWorkspaceSelected(workspace: String) {
|
private fun nativeOnEditorWorkspaceSelected(workspace: String) {
|
||||||
primaryHost?.onEditorWorkspaceSelected(workspace)
|
primaryHost?.onEditorWorkspaceSelected(workspace)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Keep
|
||||||
|
private fun nativeBuildEnvConnect(callback: GodotCallable): Boolean {
|
||||||
|
try {
|
||||||
|
val buildProvider = primaryHost?.getBuildProvider()
|
||||||
|
return buildProvider?.buildEnvConnect(callback) ?: false
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e(TAG, "Unable to connect to build environment", e)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Keep
|
||||||
|
private fun nativeBuildEnvDisconnect() {
|
||||||
|
try {
|
||||||
|
val buildProvider = primaryHost?.getBuildProvider()
|
||||||
|
buildProvider?.buildEnvDisconnect()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e(TAG, "Unable to disconnect from build environment", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Keep
|
||||||
|
private fun nativeBuildEnvExecute(buildTool: String, arguments: Array<String>, projectPath: String, buildDir: String, outputCallback: GodotCallable, resultCallback: GodotCallable): Int {
|
||||||
|
try {
|
||||||
|
val buildProvider = primaryHost?.getBuildProvider()
|
||||||
|
return buildProvider?.buildEnvExecute(
|
||||||
|
buildTool,
|
||||||
|
arguments,
|
||||||
|
projectPath,
|
||||||
|
buildDir,
|
||||||
|
outputCallback,
|
||||||
|
resultCallback
|
||||||
|
) ?: -1
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e(TAG, "Unable to execute Gradle command in build environment", e);
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Keep
|
||||||
|
private fun nativeBuildEnvCancel(jobId: Int) {
|
||||||
|
try {
|
||||||
|
val buildProvider = primaryHost?.getBuildProvider()
|
||||||
|
buildProvider?.buildEnvCancel(jobId)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e(TAG, "Unable to cancel command in build environment", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Keep
|
||||||
|
private fun nativeBuildEnvCleanProject(projectPath: String, buildDir: String, callback: GodotCallable) {
|
||||||
|
try {
|
||||||
|
val buildProvider = primaryHost?.getBuildProvider()
|
||||||
|
buildProvider?.buildEnvCleanProject(projectPath, buildDir, callback)
|
||||||
|
} catch(e: Exception) {
|
||||||
|
Log.e(TAG, "Unable to clean project in build environment", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,7 +40,6 @@ import android.content.Context;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
import android.os.Build;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Messenger;
|
import android.os.Messenger;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
@@ -496,4 +495,12 @@ public class GodotFragment extends Fragment implements IDownloaderClient, GodotH
|
|||||||
parentHost.onEditorWorkspaceSelected(workspace);
|
parentHost.onEditorWorkspaceSelected(workspace);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BuildProvider getBuildProvider() {
|
||||||
|
if (parentHost != null) {
|
||||||
|
return parentHost.getBuildProvider();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -166,4 +166,13 @@ public interface GodotHost {
|
|||||||
activity.runOnUiThread(action);
|
activity.runOnUiThread(action);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the build provider, if available.
|
||||||
|
*
|
||||||
|
* @return the build provider, if available; otherwise, null.
|
||||||
|
*/
|
||||||
|
default @Nullable BuildProvider getBuildProvider() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ class Callable private constructor(private val nativeCallablePointer: Long) {
|
|||||||
/**
|
/**
|
||||||
* Calls the method represented by this [Callable]. Arguments can be passed and should match the method's signature.
|
* Calls the method represented by this [Callable]. Arguments can be passed and should match the method's signature.
|
||||||
*/
|
*/
|
||||||
internal fun call(vararg params: Any): Any? {
|
fun call(vararg params: Any): Any? {
|
||||||
if (nativeCallablePointer == 0L) {
|
if (nativeCallablePointer == 0L) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,8 @@
|
|||||||
|
|
||||||
#include "java_godot_wrapper.h"
|
#include "java_godot_wrapper.h"
|
||||||
|
|
||||||
|
#include "jni_utils.h"
|
||||||
|
|
||||||
// JNIEnv is only valid within the thread it belongs to, in a multi threading environment
|
// JNIEnv is only valid within the thread it belongs to, in a multi threading environment
|
||||||
// we can't cache it.
|
// we can't cache it.
|
||||||
// For Godot we call most access methods from our thread and we thus get a valid JNIEnv
|
// For Godot we call most access methods from our thread and we thus get a valid JNIEnv
|
||||||
@@ -88,6 +90,11 @@ GodotJavaWrapper::GodotJavaWrapper(JNIEnv *p_env, jobject p_godot_instance) {
|
|||||||
_set_window_color = p_env->GetMethodID(godot_class, "setWindowColor", "(Ljava/lang/String;)V");
|
_set_window_color = p_env->GetMethodID(godot_class, "setWindowColor", "(Ljava/lang/String;)V");
|
||||||
_on_editor_workspace_selected = p_env->GetMethodID(godot_class, "nativeOnEditorWorkspaceSelected", "(Ljava/lang/String;)V");
|
_on_editor_workspace_selected = p_env->GetMethodID(godot_class, "nativeOnEditorWorkspaceSelected", "(Ljava/lang/String;)V");
|
||||||
_get_activity = p_env->GetMethodID(godot_class, "getActivity", "()Landroid/app/Activity;");
|
_get_activity = p_env->GetMethodID(godot_class, "getActivity", "()Landroid/app/Activity;");
|
||||||
|
_build_env_connect = p_env->GetMethodID(godot_class, "nativeBuildEnvConnect", "(Lorg/godotengine/godot/variant/Callable;)Z");
|
||||||
|
_build_env_disconnect = p_env->GetMethodID(godot_class, "nativeBuildEnvDisconnect", "()V");
|
||||||
|
_build_env_execute = p_env->GetMethodID(godot_class, "nativeBuildEnvExecute", "(Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lorg/godotengine/godot/variant/Callable;Lorg/godotengine/godot/variant/Callable;)I");
|
||||||
|
_build_env_cancel = p_env->GetMethodID(godot_class, "nativeBuildEnvCancel", "(I)V");
|
||||||
|
_build_env_clean_project = p_env->GetMethodID(godot_class, "nativeBuildEnvCleanProject", "(Ljava/lang/String;Ljava/lang/String;Lorg/godotengine/godot/variant/Callable;)V");
|
||||||
}
|
}
|
||||||
|
|
||||||
GodotJavaWrapper::~GodotJavaWrapper() {
|
GodotJavaWrapper::~GodotJavaWrapper() {
|
||||||
@@ -607,3 +614,84 @@ void GodotJavaWrapper::on_editor_workspace_selected(const String &p_workspace) {
|
|||||||
env->CallVoidMethod(godot_instance, _on_editor_workspace_selected, j_workspace);
|
env->CallVoidMethod(godot_instance, _on_editor_workspace_selected, j_workspace);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool GodotJavaWrapper::build_env_connect(const Callable &p_callback) {
|
||||||
|
if (_build_env_connect) {
|
||||||
|
JNIEnv *env = get_jni_env();
|
||||||
|
ERR_FAIL_NULL_V(env, false);
|
||||||
|
|
||||||
|
jobject j_callback = callable_to_jcallable(env, p_callback);
|
||||||
|
jboolean result = env->CallBooleanMethod(godot_instance, _build_env_connect, j_callback);
|
||||||
|
env->DeleteLocalRef(j_callback);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GodotJavaWrapper::build_env_disconnect() {
|
||||||
|
if (_build_env_disconnect) {
|
||||||
|
JNIEnv *env = get_jni_env();
|
||||||
|
ERR_FAIL_NULL(env);
|
||||||
|
|
||||||
|
env->CallVoidMethod(godot_instance, _build_env_disconnect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int GodotJavaWrapper::build_env_execute(const String &p_build_tool, const List<String> &p_arguments, const String &p_project_path, const String &p_gradle_build_directory, const Callable &p_output_callback, const Callable &p_result_callback) {
|
||||||
|
if (_build_env_execute) {
|
||||||
|
JNIEnv *env = get_jni_env();
|
||||||
|
ERR_FAIL_NULL_V(env, -1);
|
||||||
|
|
||||||
|
jstring j_build_tool = env->NewStringUTF(p_build_tool.utf8().get_data());
|
||||||
|
jobjectArray j_args = env->NewObjectArray(p_arguments.size(), env->FindClass("java/lang/String"), nullptr);
|
||||||
|
for (int i = 0; i < p_arguments.size(); i++) {
|
||||||
|
jstring j_arg = env->NewStringUTF(p_arguments.get(i).utf8().get_data());
|
||||||
|
env->SetObjectArrayElement(j_args, i, j_arg);
|
||||||
|
env->DeleteLocalRef(j_arg);
|
||||||
|
}
|
||||||
|
jstring j_project_path = env->NewStringUTF(p_project_path.utf8().get_data());
|
||||||
|
jstring j_gradle_build_directory = env->NewStringUTF(p_gradle_build_directory.utf8().get_data());
|
||||||
|
jobject j_output_callback = callable_to_jcallable(env, p_output_callback);
|
||||||
|
jobject j_result_callback = callable_to_jcallable(env, p_result_callback);
|
||||||
|
|
||||||
|
jint result = env->CallIntMethod(godot_instance, _build_env_execute, j_build_tool, j_args, j_project_path, j_gradle_build_directory, j_output_callback, j_result_callback);
|
||||||
|
|
||||||
|
env->DeleteLocalRef(j_build_tool);
|
||||||
|
env->DeleteLocalRef(j_args);
|
||||||
|
env->DeleteLocalRef(j_project_path);
|
||||||
|
env->DeleteLocalRef(j_gradle_build_directory);
|
||||||
|
env->DeleteLocalRef(j_output_callback);
|
||||||
|
env->DeleteLocalRef(j_result_callback);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GodotJavaWrapper::build_env_cancel(int p_job_id) {
|
||||||
|
if (_build_env_cancel) {
|
||||||
|
JNIEnv *env = get_jni_env();
|
||||||
|
ERR_FAIL_NULL(env);
|
||||||
|
env->CallVoidMethod(godot_instance, _build_env_cancel, p_job_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GodotJavaWrapper::build_env_clean_project(const String &p_project_path, const String &p_gradle_build_directory, const Callable &p_callback) {
|
||||||
|
if (_build_env_clean_project) {
|
||||||
|
JNIEnv *env = get_jni_env();
|
||||||
|
ERR_FAIL_NULL(env);
|
||||||
|
|
||||||
|
jstring j_project_path = env->NewStringUTF(p_project_path.utf8().get_data());
|
||||||
|
jstring j_gradle_build_directory = env->NewStringUTF(p_gradle_build_directory.utf8().get_data());
|
||||||
|
jobject j_callback = callable_to_jcallable(env, p_callback);
|
||||||
|
|
||||||
|
env->CallVoidMethod(godot_instance, _build_env_clean_project, j_project_path, j_gradle_build_directory, j_callback);
|
||||||
|
|
||||||
|
env->DeleteLocalRef(j_project_path);
|
||||||
|
env->DeleteLocalRef(j_gradle_build_directory);
|
||||||
|
env->DeleteLocalRef(j_callback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -84,6 +84,11 @@ private:
|
|||||||
jmethodID _set_window_color = nullptr;
|
jmethodID _set_window_color = nullptr;
|
||||||
jmethodID _on_editor_workspace_selected = nullptr;
|
jmethodID _on_editor_workspace_selected = nullptr;
|
||||||
jmethodID _get_activity = nullptr;
|
jmethodID _get_activity = nullptr;
|
||||||
|
jmethodID _build_env_connect = nullptr;
|
||||||
|
jmethodID _build_env_disconnect = nullptr;
|
||||||
|
jmethodID _build_env_execute = nullptr;
|
||||||
|
jmethodID _build_env_cancel = nullptr;
|
||||||
|
jmethodID _build_env_clean_project = nullptr;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
GodotJavaWrapper(JNIEnv *p_env, jobject p_godot_instance);
|
GodotJavaWrapper(JNIEnv *p_env, jobject p_godot_instance);
|
||||||
@@ -141,4 +146,10 @@ public:
|
|||||||
void set_window_color(const Color &p_color);
|
void set_window_color(const Color &p_color);
|
||||||
|
|
||||||
void on_editor_workspace_selected(const String &p_workspace);
|
void on_editor_workspace_selected(const String &p_workspace);
|
||||||
|
|
||||||
|
bool build_env_connect(const Callable &p_callback);
|
||||||
|
void build_env_disconnect();
|
||||||
|
int build_env_execute(const String &p_build_tool, const List<String> &p_arguments, const String &p_project_path, const String &p_gradle_build_directory, const Callable &p_output_callback, const Callable &p_result_callback);
|
||||||
|
void build_env_cancel(int p_job_id);
|
||||||
|
void build_env_clean_project(const String &p_project_path, const String &p_gradle_build_directory, const Callable &p_callback);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user