//Unity某些版本某些android机型,获取Application.persistentDataPath可能会返回空
//一些用Java获取外部路径的,也可能会在低端机上遇到UnauthorizedAccessException
//这个老外TheGering的方案比较完善,足以覆盖Android上所有的情况。
#region Android Java获取persistentDataPath以解决Unity获取路径为空的问题
private static string[] _persistentDataPaths;
public static bool IsDirectoryWritable(string path)
{
try
{
if (!Directory.Exists(path)) return false;
string file = Path.Combine(path, Path.GetRandomFileName());
using (FileStream fs = File.Create(file, 1)) { }
File.Delete(file);
return true;
}
catch
{
return false;
}
}
private static string GetPersistentDataPath(params string[] components)
{
try
{
string path = Path.DirectorySeparatorChar + string.Join("" + Path.DirectorySeparatorChar, components);
if (!Directory.GetParent(path).Exists) return null;
if (!Directory.Exists(path))
{
Debug.Log("creating directory: " + path);
Directory.CreateDirectory(path);
}
if (!IsDirectoryWritable(path))
{
Debug.LogWarning("persistent data path not writable: " + path);
return null;
}
return path;
}
catch (Exception ex)
{
Debug.LogException(ex);
return null;
}
}
public static string persistentDataPathInternal
{
#if UNITY_ANDROID
get
{
if (Application.isEditor || !Application.isPlaying) return Application.persistentDataPath;
string path = null;
if (string.IsNullOrEmpty(path)) path = GetPersistentDataPath("storage", "emulated", "0", "Android", "data", Application.bundleIdentifier, "files");
if (string.IsNullOrEmpty(path)) path = GetPersistentDataPath("data", "data", Application.bundleIdentifier, "files");
return path;
}
#else
get { return Application.persistentDataPath; }
#endif
}
public static string persistentDataPathExternal
{
#if UNITY_ANDROID
get
{
if (Application.isEditor || !Application.isPlaying) return null;
string path = null;
if (string.IsNullOrEmpty(path)) path = GetPersistentDataPath("storage", "sdcard0", "Android", "data", Application.bundleIdentifier, "files");
if (string.IsNullOrEmpty(path)) path = GetPersistentDataPath("storage", "sdcard1", "Android", "data", Application.bundleIdentifier, "files");
if (string.IsNullOrEmpty(path)) path = GetPersistentDataPath("mnt", "sdcard", "Android", "data", Application.bundleIdentifier, "files");
return path;
}
#else
get { return null; }
#endif
}
public static string[] persistentDataPaths
{
get
{
if (_persistentDataPaths == null)
{
List<string> paths = new List<string>();
if (!string.IsNullOrEmpty(persistentDataPathInternal)) paths.Add(persistentDataPathInternal);
if (!string.IsNullOrEmpty(persistentDataPathExternal)) paths.Add(persistentDataPathExternal);
if (!string.IsNullOrEmpty(Application.persistentDataPath) && !paths.Contains(Application.persistentDataPath)) paths.Add(Application.persistentDataPath);
_persistentDataPaths = paths.ToArray();
}
return _persistentDataPaths;
}
}
// returns best persistent data path
public static string persistentDataPath
{
get { return persistentDataPaths.Length > 0 ? persistentDataPaths[0] : null; }
}
public static string GetPersistentFile(string relativePath)
{
if (string.IsNullOrEmpty(relativePath)) return null;
foreach (string path in persistentDataPaths)
{
if (FileExists(path, relativePath)) return Path.Combine(path, relativePath);
}
return null;
}
public static bool SaveData(string relativePath, byte[] data)
{
string path = GetPersistentFile(relativePath);
if (string.IsNullOrEmpty(path))
{
return SaveData(relativePath, data, 0);
}
else
{
try
{
File.WriteAllBytes(path, data);
return true;
}
catch (Exception ex)
{
Debug.LogWarning("couldn't save data to: " + path);
Debug.LogException(ex);
// try to delete file again
if (File.Exists(path)) File.Delete(path);
return SaveData(relativePath, data, 0);
}
}
}
private static bool SaveData(string relativePath, byte[] data, int pathIndex)
{
if (pathIndex < persistentDataPaths.Length)
{
string path = Path.Combine(persistentDataPaths[pathIndex], relativePath);
try
{
string dir = Path.GetDirectoryName(path);
if (!Directory.Exists(dir))
{
Debug.Log("creating directory: " + dir);
Directory.CreateDirectory(dir);
}
File.WriteAllBytes(path, data);
return true;
}
catch (Exception ex)
{
Debug.LogWarning("couldn't save data to: " + path);
Debug.LogException(ex);
if (File.Exists(path)) File.Delete(path); // try to delete file again
return SaveData(relativePath, data, pathIndex + 1); // try next persistent path
}
}
else
{
Debug.LogWarning("couldn't save data to any persistent data path");
return false;
}
}
public static bool FileExists(string path, string relativePath)
{
return Directory.Exists(path) && File.Exists(Path.Combine(path, relativePath));
}
#endregion