Browse Source

Add GDNative libraries to Android custom Gradle builds

Marcel Admiraal 4 years ago
parent
commit
7b63f0a22d
2 changed files with 66 additions and 9 deletions
  1. 66 1
      platform/android/export/export.cpp
  2. 0 8
      platform/android/export/gradle_export_util.h

+ 66 - 1
platform/android/export/export.cpp

@@ -34,6 +34,7 @@
 #include "core/io/dir_access.h"
 #include "core/io/dir_access.h"
 #include "core/io/file_access.h"
 #include "core/io/file_access.h"
 #include "core/io/image_loader.h"
 #include "core/io/image_loader.h"
+#include "core/io/json.h"
 #include "core/io/marshalls.h"
 #include "core/io/marshalls.h"
 #include "core/io/zip_io.h"
 #include "core/io/zip_io.h"
 #include "core/os/os.h"
 #include "core/os/os.h"
@@ -206,6 +207,7 @@ static const char *LEGACY_BUILD_SPLASH_IMAGE_EXPORT_PATH = "res/drawable-nodpi-v
 static const char *SPLASH_BG_COLOR_PATH = "res/drawable-nodpi/splash_bg_color.png";
 static const char *SPLASH_BG_COLOR_PATH = "res/drawable-nodpi/splash_bg_color.png";
 static const char *LEGACY_BUILD_SPLASH_BG_COLOR_PATH = "res/drawable-nodpi-v4/splash_bg_color.png";
 static const char *LEGACY_BUILD_SPLASH_BG_COLOR_PATH = "res/drawable-nodpi-v4/splash_bg_color.png";
 static const char *SPLASH_CONFIG_PATH = "res://android/build/res/drawable/splash_drawable.xml";
 static const char *SPLASH_CONFIG_PATH = "res://android/build/res/drawable/splash_drawable.xml";
+static const char *GDNATIVE_LIBS_PATH = "res://android/build/libs/gdnativelibs.json";
 
 
 const String SPLASH_CONFIG_XML_CONTENT = R"SPLASH(<?xml version="1.0" encoding="utf-8"?>
 const String SPLASH_CONFIG_XML_CONTENT = R"SPLASH(<?xml version="1.0" encoding="utf-8"?>
 <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
 <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
@@ -277,6 +279,11 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
 		EditorProgress *ep = nullptr;
 		EditorProgress *ep = nullptr;
 	};
 	};
 
 
+	struct CustomExportData {
+		bool debug;
+		Vector<String> libs;
+	};
+
 	Vector<PluginConfigAndroid> plugins;
 	Vector<PluginConfigAndroid> plugins;
 	String last_plugin_names;
 	String last_plugin_names;
 	uint64_t last_custom_build_time = 0;
 	uint64_t last_custom_build_time = 0;
@@ -757,6 +764,33 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
 		return OK;
 		return OK;
 	}
 	}
 
 
+	static Error copy_gradle_so(void *p_userdata, const SharedObject &p_so) {
+		ERR_FAIL_COND_V_MSG(!p_so.path.get_file().begins_with("lib"), FAILED,
+				"Android .so file names must start with \"lib\", but got: " + p_so.path);
+		Vector<String> abis = get_abis();
+		CustomExportData *export_data = (CustomExportData *)p_userdata;
+		bool exported = false;
+		for (int i = 0; i < p_so.tags.size(); ++i) {
+			int abi_index = abis.find(p_so.tags[i]);
+			if (abi_index != -1) {
+				exported = true;
+				String base = "res://android/build/libs";
+				String type = export_data->debug ? "debug" : "release";
+				String abi = abis[abi_index];
+				String filename = p_so.path.get_file();
+				String dst_path = base.plus_file(type).plus_file(abi).plus_file(filename);
+				Vector<uint8_t> data = FileAccess::get_file_as_array(p_so.path);
+				print_verbose("Copying .so file from " + p_so.path + " to " + dst_path);
+				Error err = store_file_at_path(dst_path, data);
+				ERR_FAIL_COND_V_MSG(err, err, "Failed to copy .so file from " + p_so.path + " to " + dst_path);
+				export_data->libs.push_back(dst_path);
+			}
+		}
+		ERR_FAIL_COND_V_MSG(!exported, FAILED,
+				"Cannot determine ABI for library \"" + p_so.path + "\". One of the supported ABIs must be used as a tag: " + String(" ").join(abis));
+		return OK;
+	}
+
 	void _get_permissions(const Ref<EditorExportPreset> &p_preset, bool p_give_internet, Vector<String> &r_permissions) {
 	void _get_permissions(const Ref<EditorExportPreset> &p_preset, bool p_give_internet, Vector<String> &r_permissions) {
 		const char **aperms = android_perms;
 		const char **aperms = android_perms;
 		while (*aperms) {
 		while (*aperms) {
@@ -2380,6 +2414,28 @@ public:
 		}
 		}
 	}
 	}
 
 
+	void _remove_copied_libs() {
+		print_verbose("Removing previously installed libraries...");
+		Error error;
+		String libs_json = FileAccess::get_file_as_string(GDNATIVE_LIBS_PATH, &error);
+		if (error || libs_json.is_empty()) {
+			print_verbose("No previously installed libraries found");
+			return;
+		}
+
+		JSON json;
+		error = json.parse(libs_json);
+		ERR_FAIL_COND_MSG(error, "Error parsing \"" + libs_json + "\" on line " + itos(json.get_error_line()) + ": " + json.get_error_message());
+
+		Vector<String> libs = json.get_data();
+		DirAccessRef da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
+		for (int i = 0; i < libs.size(); i++) {
+			print_verbose("Removing previously installed library " + libs[i]);
+			da->remove(libs[i]);
+		}
+		da->remove(GDNATIVE_LIBS_PATH);
+	}
+
 	String join_list(List<String> parts, const String &separator) const {
 	String join_list(List<String> parts, const String &separator) const {
 		String ret;
 		String ret;
 		for (int i = 0; i < parts.size(); ++i) {
 		for (int i = 0; i < parts.size(); ++i) {
@@ -2491,13 +2547,22 @@ public:
 
 
 			//stores all the project files inside the Gradle project directory. Also includes all ABIs
 			//stores all the project files inside the Gradle project directory. Also includes all ABIs
 			_clear_assets_directory();
 			_clear_assets_directory();
+			_remove_copied_libs();
 			if (!apk_expansion) {
 			if (!apk_expansion) {
 				print_verbose("Exporting project files..");
 				print_verbose("Exporting project files..");
-				err = export_project_files(p_preset, rename_and_store_file_in_gradle_project, nullptr, ignore_so_file);
+				CustomExportData user_data;
+				user_data.debug = p_debug;
+				err = export_project_files(p_preset, rename_and_store_file_in_gradle_project, &user_data, copy_gradle_so);
 				if (err != OK) {
 				if (err != OK) {
 					EditorNode::add_io_error("Could not export project files to gradle project\n");
 					EditorNode::add_io_error("Could not export project files to gradle project\n");
 					return err;
 					return err;
 				}
 				}
+				if (user_data.libs.size() > 0) {
+					FileAccessRef fa = FileAccess::open(GDNATIVE_LIBS_PATH, FileAccess::WRITE);
+					JSON json;
+					fa->store_string(json.stringify(user_data.libs, "\t"));
+					fa->close();
+				}
 			} else {
 			} else {
 				print_verbose("Saving apk expansion file..");
 				print_verbose("Saving apk expansion file..");
 				err = save_apk_expansion_file(p_preset, p_path);
 				err = save_apk_expansion_file(p_preset, p_path);

+ 0 - 8
platform/android/export/gradle_export_util.h

@@ -96,14 +96,6 @@ Error create_directory(const String &p_dir) {
 	return OK;
 	return OK;
 }
 }
 
 
-// Implementation of EditorExportSaveSharedObject.
-// This method will only be called as an input to export_project_files.
-// This method lets the .so files for all ABIs to be copied
-// into the gradle project from the .AAR file
-Error ignore_so_file(void *p_userdata, const SharedObject &p_so) {
-	return OK;
-}
-
 // Writes p_data into a file at p_path, creating directories if necessary.
 // Writes p_data into a file at p_path, creating directories if necessary.
 // Note: this will overwrite the file at p_path if it already exists.
 // Note: this will overwrite the file at p_path if it already exists.
 Error store_file_at_path(const String &p_path, const Vector<uint8_t> &p_data) {
 Error store_file_at_path(const String &p_path, const Vector<uint8_t> &p_data) {