1. 项目概述与核心痛点
最近在PICO 4 Ultra上折腾一个Unity项目,需要把运行时生成的一些日志和用户配置文件保存到设备的外部存储里,结果在Android API Level 32(也就是Android 12L)及以上版本上,直接卡在了文件读写权限这一步。相信不少从移动端或传统VR设备转向PICO 4 Ultra开发的同行都遇到过类似问题:明明在编辑器里跑得好好的, File.WriteAllText 也没报错,但一到真机上,文件要么写不进去,要么写进去了也找不到,或者直接给你抛个 UnauthorizedAccessException 。
这个问题的根源,在于Android系统的权限沙箱机制在不断收紧,尤其是从API Level 30(Android 11)引入作用域存储(Scoped Storage)开始,到API Level 33(Android 13)进一步加强管理,应用对外部存储的访问受到了极其严格的限制。PICO 4 Ultra出厂系统基于Android 12L,其默认的Target API Level往往要求设置到30甚至更高,以符合应用商店的合规要求。这就意味着,我们过去在低API Level下那些“简单粗暴”的读写外部存储的方法,比如直接使用 Environment.GetExternalStoragePublicDirectory ,已经彻底行不通了。
本指南将彻底拆解在Unity中,为适配PICO 4 Ultra等Android 12L+设备,正确配置外部文件读写权限的完整流程。这不仅仅是在Player Settings里勾选一个 WRITE_EXTERNAL_STORAGE 权限那么简单,而是一套从项目设置、清单文件(AndroidManifest)配置、运行时动态权限请求,到最终使用正确的API进行文件操作的组合拳。我会结合最近在PICO 4 Ultra上的实际踩坑经验,把每个步骤的原理、意图和避坑点都讲清楚,目标是让你配置一次,就能稳定地在高版本Android系统上实现可靠的文件读写。
2. 环境准备与项目基础配置
在开始处理权限这个“上层建筑”之前,我们必须先把“地基”打牢。这里的核心是确保Unity项目针对Android(尤其是PICO设备)的构建环境是正确的,并且设定了正确的目标API级别。
2.1 Unity版本与Android模块确认
首先,确保你使用的Unity版本与PICO SDK兼容。目前PICO官方推荐使用Unity 2021 LTS或2022 LTS版本进行开发。你可以在Unity Hub中检查或安装对应的Android Build Support模块,特别是 Android SDK & NDK Tools 和 OpenJDK 。一个常见的坑是只安装了Unity,但没有安装Android模块,导致构建时找不到SDK路径。
安装完成后,在Unity编辑器中,打开 Edit > Preferences > External Tools ,检查Android SDK、JDK和NDK的路径是否已自动配置。如果没有,你需要手动指向它们的安装目录。对于PICO开发,通常使用Unity内置的或PICO SDK包中推荐的NDK版本即可,避免使用过新或过旧的版本导致原生库编译问题。
2.2 关键配置:Player Settings中的Target API Level
这是整个流程中最关键的一步,它决定了你的应用将在哪种权限模型下运行。打开 File > Build Settings ,确保平台切换到了 Android ,然后点击 Player Settings... 按钮。
在打开的Project Settings窗口中,找到 Player > Other Settings 区域:
- Identification 部分:确保
Bundle Identifier符合反向域名格式(如com.YourCompany.YourApp)。 - Configuration 部分:找到
Target API Level这个下拉菜单。 这里的设置至关重要。
选项解析与选择策略:
- Automatic (highest installed) :不推荐。这会让Unity使用你本地安装的最高版本SDK进行构建,可能导致在低版本设备上出现意外行为。
- API Level XX :你需要手动指定一个具体的级别。
- 对于PICO 4 Ultra(Android 12L) :最低要求通常是
API Level 31 (Android 12)。但为了更好的兼容性和符合应用商店的未来要求, 我强烈建议直接设置为API Level 32 (Android 12L)或API Level 33 (Android 13)。这能确保你的应用在最新的权限模型下进行测试和开发。
- 对于PICO 4 Ultra(Android 12L) :最低要求通常是
为什么必须设置高Target API Level? 谷歌Play商店对于新应用和重大更新有强制性的Target API Level要求。即使PICO商店目前可能没有如此严格的规定,但使用高Target API Level进行开发,可以让你提前适配更严格的隐私和安全规范,避免未来被动。更重要的是,很多与存储相关的行为(尤其是作用域存储)在低Target API Level下会被兼容性框架“放行”,从而掩盖了真实问题,导致你在真机(高系统版本)上测试时才发现功能失效。因此,从项目初期就面向高API Level开发,是最高效的做法。
- 在同一个
Other Settings区域,向下滚动,找到Write Permission选项(在Install Location附近)。对于需要写入外部存储的应用,将其从默认的Internal改为External (SDCard)。 这个设置告诉系统,你的应用期望被允许写入外部共享存储。
2.3 导入PICO Unity Integration SDK
从PICO开发者平台下载并导入最新版本的PICO Unity Integration SDK(例如 PICO Unity Integration SDK v2.x.x.unitypackage )。导入后,通常会在 Window > PICO 菜单下找到相关的工具和设置面板。确保SDK初始化成功,并且项目中没有出现编译错误。这个SDK除了提供XR功能外,其自带的 AndroidManifest.xml 基础模板也包含了PICO设备所需的一些基本权限和特性声明,是我们进行后续权限定制的基础。
3. Android清单文件深度解析与权限声明
Android应用的权限和组件声明,全部依赖于 AndroidManifest.xml 文件。在Unity中,这个文件通常由Unity根据Player Settings和已导入的插件(如PICO SDK)自动生成和合并。但为了声明高级权限和配置,我们需要提供一个自定义的清单文件来覆盖或补充默认内容。
3.1 创建自定义的AndroidManifest.xml
- 在你的Unity项目Assets目录下,创建一个名为
Plugins的文件夹(如果不存在)。 - 在
Plugins文件夹内,再创建一个名为Android的文件夹。这是Unity约定俗成的路径,用于存放Android平台特有的资源。 - 在
Android文件夹内,创建一个新的XML文件,命名为AndroidManifest.xml。
你可以从一个简单的模板开始。一个最基础的、声明了外部存储写入权限的清单文件如下:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.YourCompany.YourApp"
android:installLocation="preferExternal">
<!-- 应用运行所需的基本权限 -->
<uses-permission android:name="android.permission.INTERNET" />
<!-- 关键:声明应用需要外部存储写入权限(Android 10及以下/传统模型) -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="29" />
<!-- 注意:从Android 11(API 30)开始,WRITE_EXTERNAL_STORAGE权限对于访问共享存储已失效。
但为了兼容targetSdkVersion < 30的应用,我们仍声明它,并用maxSdkVersion限制其只在低版本系统上生效。 -->
<!-- 关键:声明应用需要管理外部存储的权限(Android 11及以上/作用域存储模型) -->
<!-- 这个权限是访问MediaStore集合(如图片、视频、音频)和下载目录所必需的。 -->
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
<!-- 关键:声明应用请求所有文件访问的特殊权限(Android 11及以上) -->
<!-- 这个权限允许应用访问共享存储上的任何文件,但需要用户手动在系统设置中授权,且上架商店可能受限。 -->
<!-- 慎用!仅在绝对需要访问非媒体文件时使用,并做好被应用商店审核质询的准备。 -->
<!-- <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" /> -->
<!-- 实际上,MANAGE_EXTERNAL_STORAGE权限的声明就是上面那一行。这里再次注释是为了强调其特殊性。 -->
<!-- 为了请求MANAGE_EXTERNAL_STORAGE权限,必须在application标签内添加一个特定属性 -->
<application
android:requestLegacyExternalStorage="true"
android:allowBackup="true"
android:icon="@drawable/app_icon"
android:label="@string/app_name"
android:theme="@style/UnityThemeSelector">
<!-- 你的活动(Activity)和其他组件声明会由Unity和PICO SDK自动合并进来 -->
<activity android:


133

被折叠的 条评论
为什么被折叠?



