PAYATHON 2026

如何解决 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 项目手动引用。

移除后,依次检查以下设置:

  1. 确认活动构建平台仍是 Universal Windows Platform。
  2. 在 Player Settings 中选择已安装的 Windows SDK 版本。
  3. 将 Scripting Backend 保持为 IL2CPP。
  4. 面向 HoloLens 2 时选择 ARM64 架构。
  5. 重新生成 IDE 项目文件,必要时重新导入相关脚本。
  6. 在 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 无法覆盖的原始传感器,通常需要在原生层完成集成:

  1. 使用适用于 HoloLens 2 的 Research Mode 原生 API 或受支持的示例实现采集。
  2. 将采集代码封装为 ARM64 UWP 原生插件或 Windows Runtime Component。
  3. 向 Unity 暴露少量稳定接口,例如初始化、启动采集、停止采集和复制帧数据。
  4. 在 C# 层通过 P/Invoke 或 WinRT 组件接口调用。
  5. 管理好原生缓冲区的生命周期、线程切换和图像格式转换。

MRTK 和 OpenXR 主要用于交互、空间定位及 XR 生命周期管理。它们不会自动为 Unity 脚本添加 Windows.Media 引用,也不能替代 Research Mode 的传感器采集接口。

建议的排查顺序

可以按以下顺序排查,以便区分编译配置问题和传感器访问问题:

  1. 删除项目中手动添加的 Windows.winmd 和 System.Runtime.WindowsRuntime.dll。
  2. 使用 #if ENABLE_WINMD_SUPPORT 包住所有 WinRT 引用和实现。
  3. 检查 .asmdef 是否包含 UWP 平台。
  4. 确认 UWP、IL2CPP、ARM64 和 Windows SDK 设置。
  5. 生成 UWP 工程,并在 Visual Studio 中编译 ARM64 配置。
  6. 配置 WebCam、spatialPerception 或 Research Mode 所需能力,具体以实际调用的 API 为准。
  7. 在真机上检查帧源枚举结果。
  8. 如果媒体帧源中没有所需的 Research Mode 传感器,再改用原生 Research Mode 插件方案。

备注:内容仅供参考。