Unity 发布 Android 安卓端所有文件可读写

现在有个需求,读写安卓系统的根目录下的文档

路径为

/storage/emulated/0/Documents/

在Unity PlayerSetting里有一个设置访问非持久化路径的设置

但是实际打包后发现还是访问不了。

解决方法

申请与配置方法

先自动生成一下AndroidManifest.xml,然后添加授权

csharp 复制代码
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />

MANAGE_EXTERNAL_STORAGE 是 Android 10(API 级别 29)引入的系统权限,允许应用访问和管理设备外部存储上的所有文件,但需用户显式授权。‌

授权方法

csharp 复制代码
    /// <summary>
    /// 检查授权状态
    /// </summary>
    /// <returns></returns>
    private bool HasExternalStoragePermission()
    {
#if (!UNITY_EDITOR && UNITY_ANDROID)
        using (var version = new AndroidJavaClass("android.os.Build$VERSION"))
        {
            if (version.GetStatic<int>("SDK_INT") >= 30)
            {
                using (var environment = new AndroidJavaClass("android.os.Environment"))
                {
                    return environment.CallStatic<bool>("isExternalStorageManager");
                }
            }
        }
#endif
        return true;
    }
    /// <summary>
    /// 唤醒授权
    /// </summary>
    private void RequestExternalStoragePermission()
    {
#if (!UNITY_EDITOR && UNITY_ANDROID)
        using (var version = new AndroidJavaClass("android.os.Build$VERSION"))
        {
            if (version.GetStatic<int>("SDK_INT") >= 30)
            {
                using (var unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer"))
                {
                    using (var currentActivity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity"))
                    {
                        using (var intent = new AndroidJavaObject("android.content.Intent"))
                        {
                            intent.Call<AndroidJavaObject>("setAction", "android.settings.MANAGE_APP_ALL_FILES_ACCESS_PERMISSION");
                            using (var uriClass = new AndroidJavaClass("android.net.Uri"))
                            {
                                using (var uri = uriClass.CallStatic<AndroidJavaObject>("parse", "package:" + currentActivity.Call<string>("getPackageName")))
                                {
                                    intent.Call<AndroidJavaObject>("setData", uri);
                                }
                            }
                            currentActivity.Call("startActivity", intent);
                        }
                    }
                }
            }
        }
#endif
    }

完整的测试代码

功能是要在安卓根目录的文档中,必须存在test.txt,没有就写入,有就读取。

(比如实现写入某个唯一密钥文件,用于激活软件)

csharp 复制代码
public string path = "/storage/emulated/0/Documents/test.txt";
    public Text mt;

    void Start()
    {
        GetPermission();
        CheckFileAndProcess();
    }

    private void OnApplicationFocus(bool focus)
    {
        if (focus)
        {
            GetPermission();
        }
    }

    void GetPermission()
    {
        if (!HasExternalStoragePermission())
        {
            RequestExternalStoragePermission();
        }
        else
        {
            SceneManager.LoadSceneAsync(1);
        }
    }

    private bool HasExternalStoragePermission()
    {
#if (!UNITY_EDITOR && UNITY_ANDROID)
        using (var version = new AndroidJavaClass("android.os.Build$VERSION"))
        {
            if (version.GetStatic<int>("SDK_INT") >= 30)
            {
                using (var environment = new AndroidJavaClass("android.os.Environment"))
                {
                    return environment.CallStatic<bool>("isExternalStorageManager");
                }
            }
        }
#endif
        return true;
    }
    
    private void RequestExternalStoragePermission()
    {
#if (!UNITY_EDITOR && UNITY_ANDROID)
        using (var version = new AndroidJavaClass("android.os.Build$VERSION"))
        {
            if (version.GetStatic<int>("SDK_INT") >= 30)
            {
                using (var unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer"))
                {
                    using (var currentActivity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity"))
                    {
                        using (var intent = new AndroidJavaObject("android.content.Intent"))
                        {
                            intent.Call<AndroidJavaObject>("setAction", "android.settings.MANAGE_APP_ALL_FILES_ACCESS_PERMISSION");
                            using (var uriClass = new AndroidJavaClass("android.net.Uri"))
                            {
                                using (var uri = uriClass.CallStatic<AndroidJavaObject>("parse", "package:" + currentActivity.Call<string>("getPackageName")))
                                {
                                    intent.Call<AndroidJavaObject>("setData", uri);
                                }
                            }
                            currentActivity.Call("startActivity", intent);
                        }
                    }
                }
            }
        }
#endif
    }

    private void CheckFileAndProcess()
    {
        if (!HasExternalStoragePermission())
        {
            SetTextSafe("无文件访问权限,无法执行文件操作!");
            RequestExternalStoragePermission();
            return;
        }

        while (!File.Exists(path))
        {
            try
            {
                string directoryPath = Path.GetDirectoryName(path);
                if (!Directory.Exists(directoryPath))
                {
                    Directory.CreateDirectory(directoryPath);
                    Debug.Log("自动创建目录:" + directoryPath);
                }
                string writeContent = "HelloWorld";
                File.WriteAllText(path, writeContent, System.Text.Encoding.UTF8);
                Debug.Log("文件不存在,已自动写入:" + path + " 内容:" + writeContent);
            }
            catch (Exception ex)
            {
                SetTextSafe("文件写入失败,重试中:" + ex.Message);
            }
        }

        try
        {
            string fileContent = File.ReadAllText(path, System.Text.Encoding.UTF8);
            SetTextSafe("程序启动检测到文件,内容:\n" + fileContent);
        }
        catch (Exception ex)
        {
            SetTextSafe("文件存在但读取失败:" + ex.Message);
            Debug.LogError("文件读取异常:" + ex.ToString());
        }
    }

    public void ReadFileContentToText()
    {
        if (!HasExternalStoragePermission())
        {
            SetTextSafe("请先授予文件访问权限!");
            RequestExternalStoragePermission();
            return;
        }

        if (mt == null)
        {
            Debug.LogError("请在Inspector面板为mt赋值Text组件!");
            return;
        }

        try
        {
            if (!File.Exists(path))
            {
                SetTextSafe("文件不存在:" + path);
                return;
            }

            string fileContent = File.ReadAllText(path, System.Text.Encoding.UTF8);
            SetTextSafe("文件内容:\n" + fileContent);
            Debug.Log("文件读取成功:" + path);
        }
        catch (Exception ex)
        {
            SetTextSafe("读取失败:" + ex.Message);
            Debug.LogError("文件读取异常:" + ex.ToString());
        }
    }
    public void WriteHelloWorldToFile()
    {
        if (!HasExternalStoragePermission())
        {
            SetTextSafe("请先授予文件访问权限!");
            RequestExternalStoragePermission();
            return;
        }

        try
        {
            string directoryPath = Path.GetDirectoryName(path);
            if (!Directory.Exists(directoryPath))
            {
                Directory.CreateDirectory(directoryPath);
                Debug.Log("目录已创建:" + directoryPath);
            }

            string writeContent = "HelloWorld";
            File.WriteAllText(path, writeContent, System.Text.Encoding.UTF8);

            if (mt != null)
            {
                SetTextSafe("写入成功!\n路径:" + path + "\n内容:" + writeContent);
            }
            Debug.Log("文件写入成功:" + path);
        }
        catch (Exception ex)
        {
            if (mt != null)
            {
                SetTextSafe("写入失败:" + ex.Message);
            }
            Debug.LogError("文件写入异常:" + ex.ToString());
        }
    }


    private void SetTextSafe(string content)
    {
        if (mt != null && !string.IsNullOrEmpty(content))
        {
            mt.text = content;
        }
    }

验证

相关推荐
User_芊芊君子2 小时前
【LeetCode原地复写零】:双指针+逆向填充,O(n)时间O(1)空间最优解!
android·linux·leetcode
2501_944448004 小时前
Flutter for OpenHarmony衣橱管家App实战:支持我们功能实现
android·javascript·flutter
2601_9498333913 小时前
flutter_for_openharmony口腔护理app实战+预约管理实现
android·javascript·flutter
2603_9494621015 小时前
Flutter for OpenHarmony社团管理App实战:预算管理实现
android·javascript·flutter
王泰虎17 小时前
安卓开发日记,因为JCenter 关闭导致加载不了三方库应该怎么办
android
JIes__18 小时前
Unity(二)——核心系统
unity·游戏引擎
独处东汉18 小时前
freertos开发空气检测仪之按键输入事件管理系统设计与实现
人工智能·stm32·单片机·嵌入式硬件·unity
Howrun77719 小时前
虚幻引擎_C++_游戏开始菜单
游戏·游戏引擎·虚幻
速冻鱼Kiel19 小时前
虚幻状态树解析
ue5·游戏引擎·虚幻