在 UnityEngine 中的 Meta Quest 2 上保存/加载文件

问题描述 投票:0回答:1

我正在开发 Meta Quest 2 的应用程序。我基本上有两个应用程序。一个称为“ADMIN”,另一个称为“CLIENT”。您可以在“管理员”应用程序中配置和保存一些数据,然后应在“客户端”应用程序中加载它们。 问题是,当我尝试读取“CLIENT”应用程序中的文件时,它会抛出一个错误:“UnauthorizedAccessException 访问路径存储/模拟/0/文档被拒绝”,即使我已正确设置所有权限。

我的保存代码是:

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 :) 尽管我想出了一些办法,但根本不起作用。

c# file unity-game-engine save oculusquest
1个回答
0
投票

我不使用 Unity,但我认为,对于多个游戏引擎,对于 Meta Quest 2,这个问题是相同的。

我做了什么来使文件访问与 System.IO C# 类一起工作,因为它已经设置为可以与远程调试一起使用:

  • 在导出设置中设置“读取外部存储”和“写入外部存储”权限。
  • 在眼镜上远程调试/启动应用程序后,进入 Meta Quest 2 设置,在“应用程序 > 权限 > 存储”中,然后输入应用程序名称以允许应用程序访问文件。
  • 使用
    /storage/emulated/0/Android/data/<javaPackageName>/files/…
    作为文件路径。显然,其他文件无法修改。
  • 如果仍然不起作用,请将眼镜连接到计算机,并将文件明确复制到 Meta Quest 2 的
    internal storage…/Android/data/<javaPackageName>/files
    中。实际上,游戏编辑器应该在远程调试游戏时就已经这样做了,但这是一个不丢失文件的安全测试方法。

来源:

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.