Unity 和 UWP 中缺少的 .NET API

使用 .NET 生成 UWP 游戏时,你可能会发现在 Unity 编辑器或独立电脑游戏中可能用于 UWP 的某些 API 不存在。 这是因为适用于 UWP 应用的 .NET 包含每个命名空间的完整 .NET Framework 中提供的类型的子集。

此外,某些游戏引擎使用不同版本的 .NET,这些版本与 UWP 的 .NET 并不完全兼容,例如 Unity 的 Mono。 因此,在编写游戏时,所有内容在编辑器中都可能正常工作,但当你为 UWP 进行构建时,你可能会收到如下错误:命名空间“System.Runtime.Serialization”中不存在类型或命名空间“Formatters”(是否缺少程序集的引用?)

幸运的是,Unity 在通用 Windows 平台:缺少的 .NET 类型在 .NET 脚本后端中,提供了一些缺失的 API 作为扩展方法和替换类型。 但是,如果您需要的功能不在此处,Windows 8.x 应用的 .NET 概述 将讨论如何将代码转换为使用 WinRT 或 .NET for Windows 运行时 API 的方法。 (它讨论了 Windows 8,但也适用于 Windows 10 UWP 应用。

.NET Standard

若要了解某些 API 可能不起作用的原因,请务必了解不同的 .NET 风格以及 UWP 如何实现 .NET。 .NET Standard 是 .NET API 的正式规范,旨在跨平台,并统一不同的 .NET 风格。 .NET 的每个实现都支持特定版本的 .NET Standard。 您可以在 .NET 实现支持中查看标准和实现的表格。

UWP SDK 的每个版本都符合不同级别的 .NET Standard。 例如,16299 SDK(Fall Creators Update)支持 .NET Standard 2.0。

如果想要知道目标 UWP 版本中是否支持特定 .NET API,可以检查 .NET Standard API 参考 ,并选择该版本的 UWP 支持的 .NET Standard 版本。

编写后端配置的脚本

如果你在构建 UWP 时遇到问题,首先检查 Player 设置文件 > 构建设置,选择 通用 Windows 平台,然后 Player 设置)。 在“其他设置配置”>下,前三个下拉列表(脚本运行时版本脚本后端API 兼容性级别)都是需要考虑的重要设置。

脚本运行时版本 是 Unity 脚本后端使用的版本,允许您获得所选 .NET Framework 支持的大致等效版本。 但是,请记住,并非所有 .NET Framework 版本中的 API 都受支持,只有那些位于您的 UWP 所面的 .NET Standard 版本中的 API 才会受到支持。

通常,随着新的 .NET 版本发布,更多的 API 会被添加到 .NET Standard 中,从而使您可以在独立应用程序和 UWP 中使用相同的代码。 例如, System.Runtime.Serialization.Json 命名空间是在 .NET Standard 2.0 中引入的。 如果将 脚本运行时版本 设置为 .NET 3.5 等效 版本(面向早期版本的 .NET Standard),则在尝试使用 API 时会收到错误;将其切换到 .NET 4.6 等效 项(支持 .NET Standard 2.0),API 将正常工作。

脚本后端 可以是 .NETIL2CPP。 对于本主题,我们假设你选择了 .NET,因为这是此处讨论的问题所在。 有关更多信息,请参阅脚本后端

最后,应将 Api 兼容性级别 设置为要运行游戏的 .NET 版本。 这应与 脚本运行时版本匹配。

通常,对于 脚本运行时版本API 兼容性级别,应选择可用的最新版本,以便与 .NET Framework 更兼容,从而允许使用更多 .NET API。

配置:编写运行时版本的脚本;编写后端脚本;API 兼容性级别

依赖于平台的编译

如果要为多个平台(包括 UWP)构建 Unity 游戏,则需要使用依赖于平台的编译来确保仅当游戏生成为 UWP 时,才运行适用于 UWP 的代码。 这样,您可以将 .NET Framework 的全部功能用于桌面和其他独立平台,并使用用于 UWP 的 WinRT API,而不会出现构建错误。

使用以下指令仅在作为 UWP 应用运行时编译代码:

#if NETFX_CORE
    // Your UWP code here
#else
    // Your standard code here
#endif

注释

NETFX_CORE 仅用于检查是否针对 .NET 脚本后端编译 C# 代码。 如果使用其他脚本后端(如 IL2CPP),请改用 ENABLE_WINMD_SUPPORT

常见问题和解决方法

以下方案描述了在 UWP 子集中缺少 .NET API 以及绕过 .NET API 的方法时可能出现的常见问题。

使用 BinaryFormatter 进行数据序列化

游戏通常会序列化保存数据,以防止玩家轻松篡改这些数据。 但是,将对象序列化为二进制的 BinaryFormatter 在早期版本的 .NET Standard 中不可用(低于 2.0)。 请考虑改用 XmlSerializerDataContractJsonSerializer

private void Save()
{
    SaveData data = new SaveData(); // User-defined object to serialize

    DataContractJsonSerializer serializer = 
      new DataContractJsonSerializer(typeof(SaveData));

    FileStream stream = 
      new FileStream(Application.persistentDataPath, FileMode.CreateNew);

    serializer.WriteObject(stream, data);
    stream.Dispose();
}

I/O 操作

System.IO 命名空间中的某些类型(如 FileStream)在早期版本的 .NET Standard 中不可用。 但是,Unity 确实提供 目录文件和FileStream 类型,以便你可以在游戏中使用它们。

或者,可以使用仅适用于 UWP 应用的 Windows.Storage API。 但是,这些 API 将应用限制为写入其特定存储,并且不授予应用对整个文件系统的免费访问权限。 有关详细信息 ,请参阅文件、文件夹和库

一个重要注意事项是 ,Close 方法仅在 .NET Standard 2.0 及更高版本中可用(尽管 Unity 提供了扩展方法)。 请改用 Dispose

线程

System.Threading 命名空间中的某些类型(如 ThreadPool)在早期版本的 .NET Standard 中不可用。 在这些情况下,可以改用 Windows.System.Threading 命名空间。

以下是如何在 Unity 游戏中处理线程的方法,使用平台相关的编译来为 UWP 和非 UWP 平台做好准备:

private void UsingThreads()
{
#if NETFX_CORE
    Windows.System.Threading.ThreadPool.RunAsync(workItem => SomeMethod());
#else
    System.Threading.ThreadPool.QueueUserWorkItem(workItem => SomeMethod());
#endif
}

安全

在 UWP 上构建 Unity 游戏时,一些 System.Security.* 命名空间(如 System.Security.Cryptography.X509Certificates)不可用。 在这些情况下,请使用 Windows.Security。* API,它们包含了许多相同的功能。

以下示例仅从具有给定名称的证书存储中获取证书:

private async void GetCertificatesAsync(string certStoreName)
    {
#if NETFX_CORE
        IReadOnlyList<Certificate> certs = await CertificateStores.FindAllAsync();
        IEnumerable<Certificate> myCerts = 
            certs.Where((certificate) => certificate.StoreName == certStoreName);
#else
        X509Store store = new X509Store(certStoreName, StoreLocation.CurrentUser);
        store.Open(OpenFlags.OpenExistingOnly);
        X509Certificate2Collection certs = store.Certificates;
#endif
    }

有关使用 WinRT 安全 API 的详细信息,请参阅 安全性

网络

一些 System.Net。* 命名空间(如 System.Net.Mail)在为 UWP 生成 Unity 游戏时也不可用。 对于这些 API 中的大多数,请使用相应的 Windows.Networking.* 和 Windows.Web.* WinRT API 来实现类似的功能。 有关详细信息,请参阅 网络和 Web 服务

如果涉及到 System.Net.Mail,请使用 Windows.ApplicationModel.Email 命名空间。 有关详细信息,请参阅 发送电子邮件

另请参阅