Fehlende .NET-APIs in Unity und UWP
Beim Erstellen eines UWP-Spiels mit .NET stellen Sie möglicherweise fest, dass einige APIs, die Sie möglicherweise im Unity-Editor oder für ein eigenständiges PC-Spiel verwenden, für UWP nicht vorhanden sind. Das liegt daran, dass .NET für UWP-Apps eine Teilmenge der Typen enthält, die im vollständigen .NET Framework für jeden Namespace bereitgestellt werden.
Darüber hinaus verwenden einige Spielengines unterschiedliche Varianten von .NET, die nicht vollständig mit .NET für UWP kompatibel sind, z. B. Unitys Mono. Wenn Sie also Ihr Spiel schreiben, funktioniert alles möglicherweise im Editor einwandfrei, aber wenn Sie zum Erstellen für UWP wechseln, erhalten Sie möglicherweise Fehler wie folgt: Der Typ oder namespace "Formatters" ist im Namespace "System.Runtime.Serialization" nicht vorhanden (fehlen Sie einen Assemblyverweis?)
Glücklicherweise stellt Unity einige dieser fehlenden APIs als Erweiterungsmethoden und Ersetzungstypen bereit, die in Universelle Windows-Plattform beschrieben werden: Fehlende .NET-Typen auf .NET Scripting Back-End. Wenn die benötigten Funktionen jedoch hier nicht vorhanden sind, werden in .NET für Windows 8.x-Apps die Möglichkeiten erläutert, wie Sie Ihren Code konvertieren können, um WinRT oder .NET für Windows-Runtime-APIs zu verwenden. (Es wird Windows 8 erläutert, gilt aber auch für Windows 10 UWP-Apps.)
.NET Standard
Um zu verstehen, warum einige APIs möglicherweise nicht funktionieren, ist es wichtig, die verschiedenen .NET-Aromen zu verstehen und wie UWP .NET implementiert. Der .NET Standard ist eine formale Spezifikation von .NET-APIs, die plattformübergreifend sein sollen, und die verschiedenen .NET-Varianten zu vereinheitlichen. Jede Implementierung von .NET unterstützt eine bestimmte Version von .NET Standard. Eine Tabelle mit Standards und Implementierungen finden Sie unter .NET-Implementierungsunterstützung.
Jede Version des UWP SDK entspricht einer anderen Ebene von .NET Standard. Beispielsweise unterstützt das 16299 SDK (Fall Creators Update) .NET Standard 2.0.
Wenn Sie wissen möchten, ob eine bestimmte .NET-API in der UWP-Version unterstützt wird, auf die Sie abzielen, können Sie die .NET Standard-API-Referenz überprüfen und die Version von .NET Standard auswählen, die von dieser Version von UWP unterstützt wird.
Skripting-Back-End-Konfiguration
Das Erste, was Sie tun sollten, wenn Sie Probleme beim Erstellen von UWP haben, ist die Spielereinstellungen zu überprüfen (Dateibuildeinstellungen>, wählen Sie Universelle Windows-Plattform und dann Player-Einstellungen aus). Unter "Other Settings > Configuration" sind die ersten drei Dropdowns (Scripting Runtime Version, Scripting Back-End und API-Kompatibilitätsebene) alle wichtigen Einstellungen zu berücksichtigen.
Die Scripting-Runtime-Version verwendet das Unity-Skripting-Back-End, mit dem Sie die von Ihnen ausgewählte (ungefähr) entsprechende Version von .NET Framework-Unterstützung erhalten können. Beachten Sie jedoch, dass nicht alle APIs in dieser Version von .NET Framework unterstützt werden, nur diejenigen in der Version von .NET Standard, auf die Ihre UWP ausgerichtet ist.
Häufig werden mit neuen .NET-Versionen weitere APIs zu .NET Standard hinzugefügt, wodurch Sie denselben Code für eigenständige und UWP verwenden können. Der Namespace "System.Runtime.Serialization.Json" wurde beispielsweise in .NET Standard 2.0 eingeführt. Wenn Sie die Skripting-Runtime-Version auf .NET 3.5 Equivalent festlegen (die auf eine frühere Version von .NET Standard ausgerichtet ist), wird beim Versuch, die API zu verwenden, eine Fehlermeldung angezeigt. Wechseln Sie zu .NET 4.6 Equivalent (unterstützt .NET Standard 2.0), und die API funktioniert.
Das Scripting-Back-End kann .NET oder IL2CPP sein. Für dieses Thema wird davon ausgegangen, dass Sie .NET ausgewählt haben, da hier die hier erläuterten Probleme auftreten. Weitere Informationen finden Sie unter Scripting Back-Ends .
Schließlich sollten Sie die API-Kompatibilitätsstufe auf die Version von .NET festlegen, auf der Ihr Spiel ausgeführt werden soll. Dies sollte mit der Skripting-Runtime-Version übereinstimmen.
Im Allgemeinen sollten Sie für die Skripting-Runtime-Version und api-Kompatibilitätsstufe die neueste verfügbare Version auswählen, damit Sie mehr Kompatibilität mit .NET Framework haben und somit mehr .NET-APIs verwenden können.
Plattformabhängige Kompilierung
Wenn Sie Ihr Unity-Spiel für mehrere Plattformen erstellen, einschließlich UWP, sollten Sie die plattformabhängige Kompilierung verwenden, um sicherzustellen, dass der für UWP vorgesehene Code nur ausgeführt wird, wenn das Spiel als UWP erstellt wird. Auf diese Weise können Sie das vollständige .NET Framework für eigenständige Desktops und andere Plattformen und WinRT-APIs für UWP verwenden, ohne Buildfehler zu erhalten.
Verwenden Sie die folgenden Direktiven, um Code nur zu kompilieren, wenn sie als UWP-App ausgeführt werden:
#if NETFX_CORE
// Your UWP code here
#else
// Your standard code here
#endif
Hinweis
NETFX_CORE
ist nur gedacht, um zu überprüfen, ob Sie C#-Code für das .NET-Skripting-Back-End kompilieren. Wenn Sie ein anderes Skripting-Back-End wie IL2CPP verwenden, verwenden Sie stattdessen ENABLE_WINMD_SUPPORT .
Häufig auftretende Probleme und Problemumgehungen
In den folgenden Szenarien werden häufige Probleme beschrieben, die auftreten können, wenn .NET-APIs aus der UWP-Teilmenge fehlen, und Möglichkeiten, um sie zu umgehen.
Daten serialisierung mit BinaryFormatter
Es ist üblich, dass Spiele Daten serialisieren, damit Spieler sie nicht einfach bearbeiten können. BinaryFormatter, der ein Objekt in eine Binärdatei serialisiert, ist jedoch in früheren Versionen von .NET Standard (vor 2.0) nicht verfügbar. Erwägen Sie stattdessen die Verwendung von XmlSerializer oder 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();
}
E/A-Vorgänge
Einige Typen im System.IO-Namespace , z . B. FileStream, sind in früheren Versionen von .NET Standard nicht verfügbar. Unity stellt jedoch die Typen "Directory", "File" und "FileStream" bereit, damit Sie sie in Ihrem Spiel verwenden können.
Alternativ können Sie die Windows.Storage-APIs verwenden, die nur für UWP-Apps verfügbar sind. Diese APIs beschränken die App jedoch auf das Schreiben in ihren spezifischen Speicher und gewähren ihm keinen kostenlosen Zugriff auf das gesamte Dateisystem. Weitere Informationen finden Sie unter "Dateien", "Ordner" und "Bibliotheken ".
Ein wichtiger Hinweis ist, dass die Close-Methode nur in .NET Standard 2.0 und höher verfügbar ist (obwohl Unity eine Erweiterungsmethode bereitstellt). Verwenden Sie stattdessen Dispose .
Threading
Einige Typen in den System.Threading-Namespaces , z . B. ThreadPool, sind in früheren Versionen von .NET Standard nicht verfügbar. In diesen Fällen können Sie stattdessen den Windows.System.Threading-Namespace verwenden.
Hier erfahren Sie, wie Sie threading in einem Unity-Spiel mit plattformabhängiger Kompilierung behandeln können, um sowohl für UWP- als auch für Nicht-UWP-Plattformen vorzubereiten:
private void UsingThreads()
{
#if NETFX_CORE
Windows.System.Threading.ThreadPool.RunAsync(workItem => SomeMethod());
#else
System.Threading.ThreadPool.QueueUserWorkItem(workItem => SomeMethod());
#endif
}
Sicherheit
Einige der System.Security.* Namespaces, z . B. System.Security.Cryptography.X509Certificates, sind nicht verfügbar, wenn Sie ein Unity-Spiel für UWP erstellen. Verwenden Sie in diesen Fällen windows.Security .* APIs, die einen Großteil der gleichen Funktionalität abdecken.
Im folgenden Beispiel werden einfach die Zertifikate aus einem Zertifikatspeicher mit dem angegebenen Namen abgerufen:
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
}
Weitere Informationen zur Verwendung der WinRT-Sicherheits-APIs finden Sie unter "Sicherheit ".
Netzwerk
Einige der System.Net.* Namespaces wie System.Net.Mail sind auch beim Erstellen eines Unity-Spiels für UWP nicht verfügbar. Verwenden Sie für die meisten dieser APIs die entsprechenden Windows.Networking-Elemente.* und Windows.Web.* WinRT-APIs zum Abrufen ähnlicher Funktionen. Weitere Informationen finden Sie unter Networking und Webdienste .
Verwenden Sie im Fall von System.Net.Mail den Windows.ApplicationModel.Email Namespace. Weitere Informationen finden Sie unter "E-Mail senden" .