如何解决 Unity UWP/HoloLens 找不到 Windows 命名空间的问题?
结论
Unity 编辑器默认不提供 UWP 的 WinRT 类型。直接写 using Windows.Media... 时,通常会出现找不到 Windows 命名空间的错误。可以用 ENABLE_WINMD_SUPPORT 对 WinRT 引用及相关代码进行条件编译,使其只在构建 UWP Player 时参与编译。
不要把系统自带的 Windows.winmd 和 System.Runtime.WindowsRuntime.dll 复制到 Unity 项目中。构建 UWP Player 时,Unity 会根据所选的 Windows SDK 自动引用系统 WinMD。手动添加这些文件可能导致类型重复、程序集版本不匹配或 IL2CPP 构建错误。
HoloLens 2 Research Mode 的原始传感器数据也未必能通过通用的 Windows.Media API 采集。应根据实际目标选择方案,例如普通摄像头帧可以尝试媒体 API,而 Research Mode 提供的深度、灰度等原始传感器流可能需要其他接口。
使用条件编译隔离 WinRT 代码
可以按下面的方式处理:
using UnityEngine;
#if ENABLE_WINMD_SUPPORT
using Windows.Media.Capture;
using Windows.Media.Capture.Frames;
#endif
public class UwpMediaProbe : MonoBehaviour
{
private async void Start()
{
#if ENABLE_WINMD_SUPPORT
var groups = await MediaFrameSourceGroup.FindAllAsync();
Debug.Log($"Found {groups.Count} media frame source groups.");
#else
Debug.Log("Windows Runtime APIs are unavailable in the Unity Editor.");
#endif
}
}
ENABLE_WINMD_SUPPORT 表示当前编译环境支持 Windows Runtime 元数据。相比只判断 UNITY_WSA,它更符合这里的需求。活动平台切换为 UWP 后,Unity 编辑器仍可能定义 UNITY_WSA,但编辑器本身无法执行这些 WinRT API。
如果还要明确限制平台,可以这样写:
#if UNITY_WSA && ENABLE_WINMD_SUPPORT
using Windows.Media.Capture;
using Windows.Media.Capture.Frames;
#endif
条件编译不能只包住 using。所有使用 WinRT 类型的字段、参数、返回值和方法实现都要放进相同的条件编译区域,否则编辑器仍会解析这些类型。
public class CameraService
{
#if ENABLE_WINMD_SUPPORT
private MediaCapture mediaCapture;
public async System.Threading.Tasks.Task InitializeAsync()
{
mediaCapture = new MediaCapture();
await mediaCapture.InitializeAsync();
}
#else
public System.Threading.Tasks.Task InitializeAsync()
{
throw new System.PlatformNotSupportedException(
"MediaCapture is only available in a UWP build."
);
}
#endif
}
项目规模较大时,可以把平台相关代码集中到一个 UWP 实现类中,再通过接口供普通 Unity 脚本调用。这样能减少 WinRT 类型对编辑器代码、测试代码和其他程序集的影响。
移除手动添加的系统程序集
如果已将以下文件复制到 Assets 或某个插件目录,请从项目中移除:
Windows.winmd
System.Runtime.WindowsRuntime.dll
Windows SDK 安装目录中的 Windows.winmd 是平台元数据,不适合作为普通 Unity 插件复制到项目里。.NETPortable\v4.6 下的 System.Runtime.WindowsRuntime.dll 通常也不需要由 Unity 2022.3 IL2CPP 项目手动引用。
移除后,依次检查以下设置:
- 确认活动构建平台仍是 Universal Windows Platform。
- 在 Player Settings 中选择已安装的 Windows SDK 版本。
- 将 Scripting Backend 保持为 IL2CPP。
- 面向 HoloLens 2 时选择 ARM64 架构。
- 重新生成 IDE 项目文件,必要时重新导入相关脚本。
- 在 Unity 中执行一次 UWP Build,再用生成的 Visual Studio 解决方案进行编译和部署。
Visual Studio 的 UWP workload 只能保证生成的 UWP 工程具备相应的编译环境,无法让 Unity 编辑器识别 Windows.* 命名空间。因此,只安装 workload 解决不了编辑器中的无条件引用问题。
检查程序集定义文件
如果脚本位于包含 .asmdef 的目录,还要检查该程序集的 Include Platforms 或 Exclude Platforms 配置。
程序集必须允许 Windows Store Apps/UWP 平台参与编译。如果它仅限于 Editor、Android 或其他平台,即使条件编译写法正确,UWP 构建也不会包含该程序集。
程序集之间的引用关系也需要检查。通用程序集不应公开返回 MediaCapture、MediaFrameSourceGroup 等 WinRT 类型,否则引用它的编辑器程序集仍可能遇到类型解析错误。更稳妥的做法是让通用接口只使用普通 C# 类型,并将 WinRT 对象保留在 UWP 实现内部。
API Compatibility Level 通常不是原因
.NET Standard 2.1 设置通常不会引发这类错误。Windows.Media 属于 Windows Runtime API,不是 .NET Standard API。Unity 能否识别它,取决于以下条件:
- 当前是否在编译 UWP Player;
- 是否启用了 WinMD 支持;
- 代码是否采用了正确的条件编译;
- 是否安装了 Windows SDK,以及生成的 UWP 工程是否选中了该 SDK;
.asmdef是否允许 UWP 平台;- 项目中是否存在手动添加且发生冲突的程序集。
因此,不必为解决这个错误而随意切换 API Compatibility Level。
配置应用能力
编译错误解决后,还需要配置运行时权限。具体能力由实际设备和调用的 API 决定。例如,访问普通摄像头通常要在 UWP Package Manifest 中启用 WebCam,需要音频时再启用 Microphone。
使用 Research Mode 时,还可能需要:
- 在 HoloLens 2 设备上启用 Research Mode;
- 在应用清单中声明对应的受限能力;
- 确认设备系统版本和目标 SDK 满足所用 API 的要求;
- 处理首次访问设备资源时的授权失败。
常见的 Research Mode 受限能力名称是:
<rescap:Capability Name="perceptionSensorsExperimental" />
使用该能力时,清单还要正确声明 rescap XML 命名空间。Unity 生成项目后,可以手工修改 Package.appxmanifest 进行验证,但重新生成工程时,这些改动可能会被覆盖。正式项目更适合通过自定义清单处理或构建后处理脚本完成配置。受限能力能否用于应用分发,还要根据实际发布渠道和当前平台政策确认。
编译期找不到 Windows 命名空间和设备端权限不足是两个不同的问题。即使编译错误已经解决,清单能力或设备设置不完整时,应用仍可能在初始化传感器时抛出 UnauthorizedAccessException,也可能找不到帧源或无法打开设备。
Research Mode 的集成方式
如果只需访问普通彩色摄像头或系统公开的媒体帧源,可以先尝试以下 API:
Windows.Media.Capture.MediaCapture
Windows.Media.Capture.Frames.MediaFrameSourceGroup
Windows.Media.Capture.Frames.MediaFrameReader
如果要读取 HoloLens 2 Research Mode 提供的深度、灰度或其他原始传感器数据,应先确认目标传感器是否通过所选的 Windows.Media.Capture.Frames 接口公开。能够引用 Windows.Media,并不代表应用已经具备 Research Mode 数据的访问能力。
对于通用媒体 API 无法覆盖的原始传感器,通常需要在原生层完成集成:
- 使用适用于 HoloLens 2 的 Research Mode 原生 API 或受支持的示例实现采集。
- 将采集代码封装为 ARM64 UWP 原生插件或 Windows Runtime Component。
- 向 Unity 暴露少量稳定接口,例如初始化、启动采集、停止采集和复制帧数据。
- 在 C# 层通过 P/Invoke 或 WinRT 组件接口调用。
- 管理好原生缓冲区的生命周期、线程切换和图像格式转换。
MRTK 和 OpenXR 主要用于交互、空间定位及 XR 生命周期管理。它们不会自动为 Unity 脚本添加 Windows.Media 引用,也不能替代 Research Mode 的传感器采集接口。
建议的排查顺序
可以按以下顺序排查,以便区分编译配置问题和传感器访问问题:
- 删除项目中手动添加的
Windows.winmd和System.Runtime.WindowsRuntime.dll。 - 使用
#if ENABLE_WINMD_SUPPORT包住所有 WinRT 引用和实现。 - 检查
.asmdef是否包含 UWP 平台。 - 确认 UWP、IL2CPP、ARM64 和 Windows SDK 设置。
- 生成 UWP 工程,并在 Visual Studio 中编译 ARM64 配置。
- 配置
WebCam、spatialPerception或 Research Mode 所需能力,具体以实际调用的 API 为准。 - 在真机上检查帧源枚举结果。
- 如果媒体帧源中没有所需的 Research Mode 传感器,再改用原生 Research Mode 插件方案。
备注:内容仅供参考。
