You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Unity安卓端无法保存TXT文件至内部存储,求解决方案

嘿,我来帮你搞定Unity安卓上保存TXT文件的问题~

你的代码在电脑上能跑,但到安卓就失效,核心问题出在硬编码路径不可靠安卓新系统的存储权限限制上,我给你一步步拆解解决方案:

问题根源

  1. 硬编码路径不通用/sdcard/Download/这种路径在不同安卓设备、不同系统版本里可能不一样,而且Android 10+引入了「分区存储(Scoped Storage)」,直接读写公共目录会被系统限制。
  2. 权限缺失或无效:即使你申请了存储权限,新系统也不允许直接访问公共目录的路径,必须用官方API来操作。

解决方案1:用Unity官方安全路径(推荐)

Unity提供了跨平台的持久化存储路径Application.persistentDataPath,这个路径是每个应用专属的安全目录,安卓上对应Android/data/[你的应用包名]/files/,不需要额外权限,也不会被系统随意清理。

修改后的代码如下:

using UnityEngine;
using System.IO;
using UnityEngine.UI;

public class Click2 : MonoBehaviour
{
    public void OnClick()
    {
        // 用Unity官方的跨平台持久化路径,自动适配安卓/Windows/iOS
        string saveLocation = Application.persistentDataPath;
        
        // 确保目录存在(虽然persistentDataPath默认会创建,但好习惯还是加上)
        if (!Directory.Exists(saveLocation))
        {
            Directory.CreateDirectory(saveLocation);
        }
        
        // 用Path.Combine自动处理路径分隔符,避免跨平台格式错误
        string filePath = Path.Combine(saveLocation, "1.txt");
        
        // using语句会自动释放文件资源,不用手动Close(),更安全
        using (StreamWriter file = new StreamWriter(filePath, true))
        {
            file.Write("a");
        }
    }
}

解决方案2:保存到公共Download目录(Android 10+)

如果你一定要把文件存到系统的Download公共目录,就得用安卓原生的MediaStoreAPI来绕过分区存储限制,下面是Unity调用安卓原生代码的示例:

using UnityEngine;
using System.IO;

public class SaveToPublicDownload : MonoBehaviour
{
    public void SaveToDownload()
    {
        string content = "a";
        string fileName = "1.txt";
        
        #if UNITY_ANDROID && !UNITY_EDITOR
        // 调用安卓原生的MediaStore API
        AndroidJavaClass mediaStore = new AndroidJavaClass("android.provider.MediaStore");
        AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
        AndroidJavaObject currentActivity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity");
        
        AndroidJavaObject contentResolver = currentActivity.Call<AndroidJavaObject>("getContentResolver");
        AndroidJavaObject contentValues = new AndroidJavaObject("android.content.ContentValues");
        
        // 设置文件名称和类型
        contentValues.Call<AndroidJavaObject>("put", mediaStore.GetStatic<string>("MediaColumns.DISPLAY_NAME"), fileName);
        contentValues.Call<AndroidJavaObject>("put", mediaStore.GetStatic<string>("MediaColumns.MIME_TYPE"), "text/plain");
        // 指定保存到Download目录
        contentValues.Call<AndroidJavaObject>("put", mediaStore.GetStatic<string>("MediaColumns.RELATIVE_PATH"), "Download");
        
        // 插入文件并获取Uri
        AndroidJavaObject uri = contentResolver.Call<AndroidJavaObject>("insert", mediaStore.GetStatic<AndroidJavaObject>("Downloads.EXTERNAL_CONTENT_URI"), contentValues);
        
        if (uri != null)
        {
            AndroidJavaObject outputStream = contentResolver.Call<AndroidJavaObject>("openOutputStream", uri);
            if (outputStream != null)
            {
                // 将字符串转为字节数组写入文件
                byte[] bytes = System.Text.Encoding.UTF8.GetBytes(content);
                outputStream.Call("write", bytes);
                outputStream.Call("close");
                Debug.Log("文件已成功保存到Download目录!");
            }
        }
        #else
        // 编辑器或其他平台用持久化路径替代
        string savePath = Path.Combine(Application.persistentDataPath, fileName);
        using (StreamWriter sw = new StreamWriter(savePath, true))
        {
            sw.Write(content);
        }
        Debug.Log($"编辑器模式下保存路径:{savePath}");
        #endif
    }
}

权限补充说明

  • Android 9及以下:需要在Unity的PlayerSettings > Android > Publishing Settings里启用自定义Manifest,添加权限:
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    
  • Android 10+:用上面的MediaStore方式不需要申请存储权限,系统会自动允许写入公共目录。

内容的提问来源于stack exchange,提问作者Muhammad Hussain

火山引擎 最新活动