APIs .NET ausentes no Unity e na UWP

Ao criar um jogo UWP usando o .NET, você pode descobrir que algumas APIs que você poderia usar no editor do Unity ou em um jogo de computador autônomo não estão presentes para UWP. Isso ocorre porque o .NET para aplicativos UWP inclui um subconjunto dos tipos fornecidos no .NET Framework completo para cada namespace.

Além disso, alguns mecanismos de jogos usam diferentes versões do .NET que não são totalmente compatíveis com o .NET para UWP, como o Mono do Unity. Por isso, quando você estiver escrevendo seu jogo, tudo poderá estar funcionando bem no editor, mas, quando você começar a realizar a compilação para UWP, erros como este poderão aparecer: O tipo ou namespace 'Formatters' não existe no namespace 'System.Runtime.Serialization' (há uma referência de assembly ausente?)

Felizmente, o Unity fornece algumas dessas APIs ausentes como métodos de extensão e tipos de substituição, que são descritas em Plataforma Universal do Windows: tipos .NET ausentes no back-end de script do .NET. No entanto, se a funcionalidade necessária não estiver aqui, a visão geral do .NET para aplicativos Windows 8.x discutirá maneiras de converter seu código para usar WinRT ou .NET para APIs Windows Runtime. (Ele aborda o Windows 8, mas também aplica-se aos aplicativos UWP do Windows 10.)

.NET Standard

Para compreender por que algumas APIs podem não estar funcionando, é importante entender os diferentes tipos .NET e como a UWP implementa o .NET. O .NET Standard é uma especificação formal de .NET APIs que deve funcionar como uma plataforma cruzada e unificar os diferentes tipos .NET. Cada implementação do .NET oferece suporte a uma determinada versão do .NET Standard. Você pode ver uma tabela de padrões e implementações em Suporte à implementação do .NET.

Cada versão do SDK da UWP está de acordo com um nível diferente do .NET Standard. Por exemplo, o SDK 16299 (o Fall Creators Update) oferece suporte ao .NET Standard 2.0.

Se você quiser saber se um determinado API .NET é compatível com a versão de UWP desejada, consulte a Referência de API do .NET Standard e selecione a versão do .NET Standard compatível com essa versão da UWP.

Configuração do back-end de script

A primeira coisa que você deve fazer se estiver tendo problemas para criar para UWP é marcar as Configurações do Player (Configurações de Build de Arquivo>, selecione Plataforma Universal do Windows e Configurações do Player). Em Outras Configurações > Configuração, as três primeiras listas suspensas (Versão do Runtime de Script, Back-end de Script e Nível de Compatibilidade da API) são todas configurações importantes a serem consideradas.

Scripting Runtime Version é o que o back-end de script do Unity usa para permitir que você obtenha a versão (aproximadamente) equivalente do suporte do .NET Framework desejado. No entanto, tenha em mente que nem todas as APIs nessa versão do .NET Framework será compatível, mas apenas as da versão do .NET Standard que a UWP tem como alvo.

Geralmente nas novas versões do .NET, mais APIs são adicionadas ao .NET Standard, o que pode permitir que você use o mesmo código entre uma plataforma autônoma e a UWP. Por exemplo, o namespace System.Runtime.Serialization.Json foi incorporado no .NET Standard 2.0. Se você definir Scripting Runtime Version para .NET 3.5 Equivalent (que direciona uma versão anterior do .NET Standard), receberá um erro ao tentar usar a API; alterne para .NET 4.6 Equivalent (que é compatível com o .NET Standard 2.0), e a API funcionará.

O Scripting Backend pode ser .NET ou IL2CPP. Neste tópico, assumimos que você escolheu .NET, já que foi nesse ponto que os problemas discutidos aqui surgiram. Consulte Back-ends de script para obter mais informações.

Por fim, você deve definir Api Compatibility Level para a versão do .NET na qual deseja que o jogo seja executado. Isso deve corresponder à Scripting Runtime Version.

Em geral, em Scripting Runtime Version e Api Compatibility Level, você deve selecionar a versão mais recente disponível para ter mais compatibilidade com o .NET Framework e, assim, permitir que você use mais .NET APIs.

Configuração: Scripting Runtime Version; Scripting Backend; Api Compatibility Level

Compilação dependente de plataforma

Se você estiver compilando o jogo do Unity para várias plataformas, incluindo a UWP, precisará usar a compilação dependente de plataforma para certificar-se de que código destinado à UWP seja executado apenas quando o jogo for compilado como uma UWP. Dessa forma, você pode usar o .NET Framework completo para área de trabalho autônoma e outras plataformas e APIs do WinRT para UWP, sem receber erros de compilação.

Use as seguintes diretivas para compilar o código somente quando ele estiver sendo executado como um aplicativo UWP:

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

Observação

NETFX_COREdestina-se apenas a marcar se você está compilando código C# no back-end de script do .NET. Se você estiver usando um back-end de script diferente, como IL2CPP, use ENABLE_WINMD_SUPPORT em vez disso.

Problemas comuns e soluções alternativas

Os cenários a seguir descrevem os problemas comuns que poderão surgir quando as .NET APIs estiverem ausentes no subconjunto da UWP e maneiras de contorná-los.

Serialização de dados usando BinaryFormatter

É comum os jogos serializarem os dados salvos para que os jogadores não consigam manipulá-los facilmente. No entanto, BinaryFormatter, que serializa um objeto em binário, não está disponível nas versões anteriores do .NET Standard (anteriores à 2.0). É recomendável o uso de XmlSerializer ou DataContractJsonSerializer.

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();
}

Operações de E/S

Alguns tipos no namespace System.IO, como FileStream, não estão disponíveis nas versões anteriores do .NET Standard. No entanto, o Unity fornece os tipos Directory, File e FileStream tipos para que você pode usá-los em seu jogo.

Como alternativa, você pode usar as APIS Windows.Storage , que só estão disponíveis para aplicativos UWP. No entanto, essas APIs restringem o app à gravação em seu armazenamento específico e não concede a ele acesso gratuito ao sistema de arquivos inteiro. Consulte Arquivos, pastas e bibliotecas para obter mais informações.

Uma observação importante é que o método Close só está disponível no .NET Standard 2.0 e posterior (embora o Unity forneça um método de extensão). Use Dispose em vez disso.

Threading

Alguns tipos no namespace System.Threading, como ThreadPool, não estão disponíveis nas versões anteriores do .NET Standard. Nesses casos, você pode usar o namespace Windows.System.Threading em vez disso.

Veja como tratar o threading em um jogo do Unity, usando a compilação dependente de plataforma para preparar o cenário para as plataformas UWP e não UWP:

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

Segurança

Alguns dos namespaces System.Security.*, como System.Security.Cryptography.X509Certificates, não estão disponíveis na criação de um jogo Unity para UWP. Nesses casos, use as APIs de Windows.Security.*, que abrangem praticamente a mesma funcionalidade.

O exemplo a seguir simplesmente obtém os certificados de um repositório de certificados com o nome fornecido:

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
    }

Consulte Segurança para obter mais informações sobre o uso das APIs de segurança do WinRT.

Rede

Alguns dos System.Net. * namespaces, como System.Net.Mail, também não estão disponíveis ao criar um jogo do Unity para UWP. Para a maioria dessas APIs, use as APIs do WinRT correspondentes Windows.Networking.* e Windows.Web.* para obter uma funcionalidade semelhante. Consulte Serviços de rede e Web para obter mais informações.

No caso de System.Net.Mail, use o namespace Windows.ApplicationModel.Email. Consulte Enviar email para obter mais informações.

Confira também