Unity开发Meta Quest 2双APP文件读写权限异常求助
Meta Quest 2跨应用文件读取权限问题
我正在为Meta Quest 2开发两款应用:ADMIN和CLIENT。ADMIN应用可配置并保存数据,CLIENT应用需要加载这些数据,但当CLIENT尝试读取文件时,抛出如下错误:
UnauthorizedAccessException Access to path storage/emulated/0/Documents is denied
尽管已正确配置所有权限,问题依然存在。我的保存与加载代码如下:
using System; using System.IO; using System.Text; using UnityEngine; using UnityEngine.Android; using System.Security.AccessControl; using Microsoft.Win32.SafeHandles; /// <summary> /// Save System. /// Use these APIs to Save/Load game data. /// </summary> public static class SaveSystem { private static string selectedFilePath; private static ISaveSystemSerializer m_Serializer = new SaveSystemJsonSerializer(); private static Encoding m_Encoding = Encoding.UTF8; /// <summary> /// Gets or sets the serializer. /// </summary> /// <value>The serializer.</value> public static ISaveSystemSerializer Serializer { get => m_Serializer ??= new SaveSystemJsonSerializer(); set => m_Serializer = value; } /// <summary> /// Gets or sets the encoding. /// </summary> /// <value>The encoding.</value> public static Encoding DefaultEncoding { get => m_Encoding ??= Encoding.UTF8; set => m_Encoding = value; } /// <summary> /// Gets or sets a value indicating whether this <see cref="FG_Saving.SaveSystem"/> encrypt data by default. /// </summary> /// <value><c>true</c> if encode; otherwise, <c>false</c>.</value> public static bool Encode { get; set; } = false; public static string Path { get; set; } = "storage/emulated/0/Documents"; /// <summary> /// Gets or sets the encryption password. /// </summary> /// <value>The encryption password.</value> public static string EncodePassword { get; set; } = "dabkaksdksadkj"; /// <summary> /// Gets or sets a value indicating whether this <see cref="FG_Saving.SaveSystem"/> log error. /// </summary> /// <value><c>true</c> if log error; otherwise, <c>false</c>.</value> public static bool LogError { get; set; } = false; /// <summary> /// Saves data using the identifier. /// </summary> /// <param name="identifier">Identifier.</param> /// <param name="obj">Object to save.</param> /// <param name="saveFile"> Save File Number</param> /// <typeparam name="T">The 1st type parameter.</typeparam> public static void Save<T>(string identifier, T obj, int saveFile) { Save<T>(identifier, obj, saveFile, Encode, EncodePassword, Serializer, DefaultEncoding); } /// <summary> /// Saves data using the identifier. /// </summary> /// <param name="identifier">Identifier.</param> /// <param name="data">data to save.</param> /// <param name="saveFile"> Save File Number</param> /// <param name="encode">Encrypt the data?</param> /// <param name="password">Encryption Password.</param> /// <param name="serializer">Serializer.</param> /// <param name="encoding">Encoding.</param> /// <typeparam name="T">The 1st type parameter.</typeparam> public static void Save<T>(string identifier, T data, int saveFile, bool encode, string password, ISaveSystemSerializer serializer, Encoding encoding) { if (!Permission.HasUserAuthorizedPermission(Permission.ExternalStorageWrite) || Permission.HasUserAuthorizedPermission(Permission.ExternalStorageRead)) { Permission.RequestUserPermissions(new []{Permission.ExternalStorageRead, Permission.ExternalStorageWrite } ); Debug.Log("Permission Granted"); } if (string.IsNullOrEmpty(identifier)) throw new System.ArgumentNullException(nameof(identifier)); serializer ??= Serializer; encoding ??= DefaultEncoding; string filePath = ""; if (identifier == "Settings") { filePath = $"{Path}/{identifier + ".cfg"}"; } else { filePath = $"{Path}/{identifier}{saveFile:D3}.vrm"; } data ??= default(T); Stream stream = null; if (encode) { stream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None); } else { stream = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None); } serializer.Serialize(data, stream, encoding); stream.Dispose(); Debug.Log("saved" + filePath); } /// <summary> /// Loads data using identifier. /// </summary> /// <param name="identifier">Identifier.</param> /// <param name="saveSlot"> The save slot to load from</param> /// <typeparam name="T">The 1st type parameter.</typeparam> public static T Load<T>(string identifier, int saveSlot) { return Load<T>(identifier, saveSlot, default(T), Encode, EncodePassword, Serializer, DefaultEncoding); } /// <summary> /// Loads data using identifier. /// </summary> /// <param name="identifier">Identifier.</param> /// <param name="saveSlot"> the save slot to load from</param> /// <param name="defaultValue">Default Value.</param> /// <param name="encode">Load encrypted data? (set it to true if you have used encryption in save)</param> /// <param name="password">Encryption Password.</param> /// <param name="serializer">Serializer.</param> /// <param name="encoder">Encoder.</param> /// <param name="encoding">Encoding.</param> /// <param name="path">Path.</param> /// <typeparam name="T">The 1st type parameter.</typeparam> public static T Load<T>(string identifier, int saveSlot, T defaultValue, bool encode, string password, ISaveSystemSerializer serializer, Encoding encoding) { if (!Permission.HasUserAuthorizedPermission(Permission.ExternalStorageRead)) { Permission.RequestUserPermissions(new []{Permission.ExternalStorageRead, Permission.ExternalStorageWrite } ); Debug.Log("Permission Granted"); } if (string.IsNullOrEmpty(identifier)) throw new ArgumentNullException(nameof(identifier)); serializer ??= Serializer; encoding ??= DefaultEncoding; defaultValue ??= default(T); T result = defaultValue; string filePath = ""; if (identifier == "Settings") filePath = $"{Path}/{identifier + ".cfg"}"; else filePath = $"{Path}/{identifier}{saveSlot:D3}.vrm"; if (Exists(identifier, saveSlot)) { Stream stream = null; stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); result = serializer.Deserialize<T>(stream, encoding); stream.Dispose(); Debug.Log("loaded" + filePath); return result; } return default; } /// <summary> /// Checks whether the specified identifier exists or not. /// </summary> /// <param name="identifier">Identifier.</param> /// <param name="saveSlot"> The save slot to load from</param> public static bool Exists(string identifier, int saveSlot) => File.Exists($"{Path}/{identifier}{saveSlot:D3}.vrm"); /// <summary> /// Delete the specified identifier and path. /// </summary> /// <param name="identifier">Identifier.</param> /// <param name="saveSlot"> the save slot to load from </param> /// <param name="path">Path.</param> public static void Delete(string identifier, int saveSlot) { if (string.IsNullOrEmpty(identifier)) throw new System.ArgumentNullException(nameof(identifier)); string filePath = ""; if (identifier == "Settings") filePath = $"{Path}/{identifier + ".cfg"}"; else filePath = $"{Path}/{identifier}{saveSlot:D3}.vrm"; if (!Exists(filePath, saveSlot)) return; File.Delete(filePath); } }
我尝试过使用Unity的AndroidJavaClass加载文件,但因不熟悉Java,最终未成功解决问题。
内容的提问来源于stack exchange,提问作者Janda
相关产品推荐
相关产品推荐

