소스 검색

Add OS.get_external_data_dir() to get Android external directory

Marcel Admiraal 4 년 전
부모
커밋
b3a962945e

+ 5 - 0
core/core_bind.cpp

@@ -643,6 +643,10 @@ String _OS::get_user_data_dir() const {
 	return OS::get_singleton()->get_user_data_dir();
 }
 
+String _OS::get_external_data_dir() const {
+	return OS::get_singleton()->get_external_data_dir();
+}
+
 bool _OS::is_debug_build() const {
 #ifdef DEBUG_ENABLED
 	return true;
@@ -743,6 +747,7 @@ void _OS::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("get_static_memory_peak_usage"), &_OS::get_static_memory_peak_usage);
 
 	ClassDB::bind_method(D_METHOD("get_user_data_dir"), &_OS::get_user_data_dir);
+	ClassDB::bind_method(D_METHOD("get_external_data_dir"), &_OS::get_external_data_dir);
 	ClassDB::bind_method(D_METHOD("get_system_dir", "dir"), &_OS::get_system_dir);
 	ClassDB::bind_method(D_METHOD("get_unique_id"), &_OS::get_unique_id);
 

+ 1 - 0
core/core_bind.h

@@ -237,6 +237,7 @@ public:
 	String get_system_dir(SystemDir p_dir) const;
 
 	String get_user_data_dir() const;
+	String get_external_data_dir() const;
 
 	Error set_thread_name(const String &p_name);
 	Thread::ID get_thread_caller_id() const;

+ 5 - 0
core/os/os.cpp

@@ -310,6 +310,11 @@ String OS::get_user_data_dir() const {
 	return ".";
 }
 
+// Android OS path to app's external data storage
+String OS::get_external_data_dir() const {
+	return get_user_data_dir();
+};
+
 // Absolute path to res://
 String OS::get_resource_dir() const {
 	return ProjectSettings::get_singleton()->get_resource_path();

+ 1 - 0
core/os/os.h

@@ -252,6 +252,7 @@ public:
 	virtual String get_bundle_resource_dir() const;
 
 	virtual String get_user_data_dir() const;
+	virtual String get_external_data_dir() const;
 	virtual String get_resource_dir() const;
 
 	enum SystemDir {

+ 7 - 0
doc/classes/OS.xml

@@ -221,6 +221,13 @@
 				Returns the path to the current engine executable.
 			</description>
 		</method>
+		<method name="get_external_data_dir" qualifiers="const">
+			<return type="String">
+			</return>
+			<description>
+				On Android, returns the absolute directory path where user data can be written to external storage if available. On all other platforms, this will return the same location as [method get_user_data_dir].
+			</description>
+		</method>
 		<method name="get_granted_permissions" qualifiers="const">
 			<return type="PackedStringArray">
 			</return>

+ 4 - 0
platform/android/java/lib/src/org/godotengine/godot/GodotIO.java

@@ -452,6 +452,10 @@ public class GodotIO {
 		return activity.getFilesDir().getAbsolutePath();
 	}
 
+	public String getExternalDataDir() {
+		return activity.getExternalFilesDir(null).getAbsolutePath();
+	}
+
 	public String getLocale() {
 		return Locale.getDefault().toString();
 	}

+ 12 - 0
platform/android/java_godot_io_wrapper.cpp

@@ -49,6 +49,7 @@ GodotIOJavaWrapper::GodotIOJavaWrapper(JNIEnv *p_env, jobject p_godot_io_instanc
 
 		_open_URI = p_env->GetMethodID(cls, "openURI", "(Ljava/lang/String;)I");
 		_get_data_dir = p_env->GetMethodID(cls, "getDataDir", "()Ljava/lang/String;");
+		_get_external_data_dir = p_env->GetMethodID(cls, "getExternalDataDir", "()Ljava/lang/String;");
 		_get_locale = p_env->GetMethodID(cls, "getLocale", "()Ljava/lang/String;");
 		_get_model = p_env->GetMethodID(cls, "getModel", "()Ljava/lang/String;");
 		_get_screen_DPI = p_env->GetMethodID(cls, "getScreenDPI", "()I");
@@ -92,6 +93,17 @@ String GodotIOJavaWrapper::get_user_data_dir() {
 	}
 }
 
+String GodotIOJavaWrapper::get_external_data_dir() {
+	if (_get_external_data_dir) {
+		JNIEnv *env = get_jni_env();
+		ERR_FAIL_COND_V(env == nullptr, String());
+		jstring s = (jstring)env->CallObjectMethod(godot_io_instance, _get_external_data_dir);
+		return jstring_to_string(s, env);
+	} else {
+		return String();
+	}
+}
+
 String GodotIOJavaWrapper::get_locale() {
 	if (_get_locale) {
 		JNIEnv *env = get_jni_env();

+ 2 - 0
platform/android/java_godot_io_wrapper.h

@@ -47,6 +47,7 @@ private:
 
 	jmethodID _open_URI = 0;
 	jmethodID _get_data_dir = 0;
+	jmethodID _get_external_data_dir = 0;
 	jmethodID _get_locale = 0;
 	jmethodID _get_model = 0;
 	jmethodID _get_screen_DPI = 0;
@@ -66,6 +67,7 @@ public:
 
 	Error open_uri(const String &p_uri);
 	String get_user_data_dir();
+	String get_external_data_dir();
 	String get_locale();
 	String get_model();
 	int get_screen_dpi();

+ 26 - 17
platform/android/os_android.cpp

@@ -45,6 +45,23 @@
 #include "java_godot_io_wrapper.h"
 #include "java_godot_wrapper.h"
 
+String _remove_symlink(const String &dir) {
+	// Workaround for Android 6.0+ using a symlink.
+	// Save the current directory.
+	char current_dir_name[2048];
+	getcwd(current_dir_name, 2048);
+	// Change directory to the external data directory.
+	chdir(dir.utf8().get_data());
+	// Get the actual directory without the potential symlink.
+	char dir_name_wihout_symlink[2048];
+	getcwd(dir_name_wihout_symlink, 2048);
+	// Convert back to a String.
+	String dir_without_symlink(dir_name_wihout_symlink);
+	// Restore original current directory.
+	chdir(current_dir_name);
+	return dir_without_symlink;
+}
+
 class AndroidLogger : public Logger {
 public:
 	virtual void logv(const char *p_format, va_list p_list, bool p_err) {
@@ -199,26 +216,18 @@ String OS_Android::get_user_data_dir() const {
 
 	String data_dir = godot_io_java->get_user_data_dir();
 	if (data_dir != "") {
-		//store current dir
-		char real_current_dir_name[2048];
-		getcwd(real_current_dir_name, 2048);
-
-		//go to data dir
-		chdir(data_dir.utf8().get_data());
-
-		//get actual data dir, so we resolve potential symlink (Android 6.0+ seems to use symlink)
-		char data_current_dir_name[2048];
-		getcwd(data_current_dir_name, 2048);
-
-		//cache by parsing utf8
-		data_dir_cache.parse_utf8(data_current_dir_name);
-
-		//restore original dir so we don't mess things up
-		chdir(real_current_dir_name);
-
+		data_dir_cache = _remove_symlink(data_dir);
 		return data_dir_cache;
 	}
+	return ".";
+}
 
+String OS_Android::get_external_data_dir() const {
+	String data_dir = godot_io_java->get_external_data_dir();
+	if (data_dir != "") {
+		data_dir = _remove_symlink(data_dir);
+		return data_dir;
+	}
 	return ".";
 }
 

+ 1 - 0
platform/android/os_android.h

@@ -111,6 +111,7 @@ public:
 
 	virtual Error shell_open(String p_uri) override;
 	virtual String get_user_data_dir() const override;
+	virtual String get_external_data_dir() const override;
 	virtual String get_resource_dir() const override;
 	virtual String get_locale() const override;
 	virtual String get_model_name() const override;