Unity开发Meta Quest 3 APK时TXT文件存储权限问题求助
Meta Quest 3 Unity开发:TXT文件存储权限问题排查
问题背景
我正在为研究目的用Unity开发Meta Quest 3的APK,需要将用户使用应用时输入的内容保存为TXT文件,怀疑遇到了Android权限问题。
存储代码
using System; using System.IO; using UnityEngine; using UnityEngine.SceneManagement; using UnityEngine.UI; public class LoggerQuest : MonoBehaviour { public GameObject textObject1; private DateTime startTime; private DateTime sceneStartTime; // Start is called before the first frame update void Start() { string fname = System.DateTime.Now.ToString("HH-mm-ss") + ".txt"; string path = $"/mnt/sdcard/This Headset/Oculus/{fname}"; startTime = DateTime.Now; sceneStartTime = DateTime.Now; SceneManager.sceneLoaded += OnSceneLoaded; if (textObject1 != null) { Text text1 = textObject1.GetComponent<Text>(); if (text1 != null) text1.RegisterDirtyVerticesCallback(() => SaveText(text1)); } void OnSceneLoaded(Scene scene, LoadSceneMode mode) { DateTime sceneEndTime = DateTime.Now; TimeSpan sceneElapsedTime = sceneEndTime - sceneStartTime; using (StreamWriter writer = new StreamWriter(path, true)) { writer.WriteLine("Scene Name: " + scene.name); writer.WriteLine("Scene Start Time: " + sceneStartTime.ToString("HH:mm:ss")); writer.WriteLine("Scene End Time: " + sceneEndTime.ToString("HH:mm:ss")); writer.WriteLine("Scene Elapsed Time: " + sceneElapsedTime.ToString()); writer.WriteLine("-------------------------------------"); } // Update the start time for the new scene sceneStartTime = DateTime.Now; } void OnApplicationQuit() { DateTime endTime = DateTime.Now; Debug.Log("Scene ended at: " + endTime.ToString("HH:mm:ss")); TimeSpan elapsedTime = endTime - startTime; TimeSpan sceneElapsedTime = endTime - sceneStartTime; using (StreamWriter writer = new StreamWriter(path, true)) { writer.WriteLine("Start Time: " + startTime.ToString("HH:mm:ss")); writer.WriteLine("End Time: " + endTime.ToString("HH:mm:ss")); writer.WriteLine("Elapsed Time: " + elapsedTime.ToString()); writer.WriteLine("Scene Elapsed Time: " + sceneElapsedTime.ToString()); writer.WriteLine("-------------------------------------"); } } void SaveText(Text textComponent) { DateTime inputTime = DateTime.Now; using (StreamWriter writer = new StreamWriter(path, true)) { writer.WriteLine("Text Object: " + textComponent.name); writer.WriteLine("Text: " + textComponent.text); writer.WriteLine("Text Change Time: " + inputTime.ToString("HH:mm:ss")); writer.WriteLine("-------------------------------------"); } } void LogInteraction(GameObject interactedObject) { DateTime interactionTime = DateTime.Now; using (StreamWriter writer = new StreamWriter(path, true)) { writer.WriteLine("Interaction with: " + interactedObject.name); writer.WriteLine("Interaction Time: " + interactionTime.ToString("HH:mm:ss")); writer.WriteLine("-------------------------------------"); } } } }
调试错误日志
07-19 16:42:37.876 19528 19601 E DeviceConfig: getProperties failed: Permission denial: reading from settings requires:android.permission.READ_DEVICE_CONFIG 07-19 16:42:40.018 744 744 E DeviceConfig: getProperties failed: 07-19 16:42:40.019 759 1048 E hw-IPCThreadState: Process seems to be sending too many oneway calls.
已添加的Android权限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
解决建议
1. 适配Android 13+权限规则
Meta Quest 3基于Android 13,原有的WRITE/READ_EXTERNAL_STORAGE权限已被弱化。针对TXT这类非媒体文件,需添加全存储访问权限:
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
该权限无法通过代码直接申请,需引导用户到系统设置手动开启。
2. 动态申请基础权限
在代码中主动申请所需权限,而非仅依赖Manifest声明:
#if UNITY_ANDROID && !UNITY_EDITOR void Start() { // 先申请基础存储权限 string[] basicPerms = new string[] { "android.permission.READ_EXTERNAL_STORAGE", "android.permission.WRITE_EXTERNAL_STORAGE" }; foreach (string perm in basicPerms) { if (!Permission.HasUserAuthorizedPermission(perm)) { Permission.RequestUserPermission(perm); } } // 检查全存储权限,未授权则跳转设置 if (!Permission.HasUserAuthorizedPermission("android.permission.MANAGE_EXTERNAL_STORAGE")) { OpenStorageSettings(); } // 原有Start方法逻辑... } void OpenStorageSettings() { AndroidJavaClass intentClass = new AndroidJavaClass("android.content.Intent"); AndroidJavaObject intentObject = new AndroidJavaObject("android.content.Intent"); AndroidJavaClass uriClass = new AndroidJavaClass("android.net.Uri"); AndroidJavaObject uriObject = uriClass.CallStatic<AndroidJavaObject>("parse", "package:" + Application.identifier); intentObject.Call<AndroidJavaObject>("setAction", "android.settings.MANAGE_APP_ALL_FILES_ACCESS_PERMISSION"); intentObject.Call<AndroidJavaObject>("setData", uriObject); AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer"); AndroidJavaObject currentActivity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity"); currentActivity.Call("startActivity", intentObject); } #endif
3. 更换推荐存储路径
避免使用硬编码的/mnt/sdcard路径,改用官方推荐路径:
- 应用专属存储(无需额外权限):卸载应用时数据会被删除,适合研究数据存储
string path = Path.Combine(Application.persistentDataPath, fname);
- 公共文档目录(需权限):数据可在设备文件管理器中查看
#if UNITY_ANDROID && !UNITY_EDITOR AndroidJavaClass environment = new AndroidJavaClass("android.os.Environment"); AndroidJavaObject publicDir = environment.CallStatic<AndroidJavaObject>("getExternalStoragePublicDirectory", environment.GetStatic<string>("DIRECTORY_DOCUMENTS")); string docsPath = publicDir.Call<string>("getAbsolutePath"); string path = Path.Combine(docsPath, "YourResearchApp", fname); Directory.CreateDirectory(Path.GetDirectoryName(path)); // 确保目录存在 #endif
4. 关于READ_DEVICE_CONFIG错误
该错误属于系统层面的内部调用问题,和你的文件存储逻辑无关,可暂时忽略,重点解决存储权限问题即可。
内容的提问来源于stack exchange,提问作者Anna
相关产品推荐
相关产品推荐

