Windows Universal Apps und Extension SDKs
Windows Universal Apps sind dafür ausgelegt auf allen Geräteklassen zu laufen – wenn man es als Entwickler nicht explizit ausschließt. Zur Erinnerung: Wir sprechen bei Universal Windows Apps von Applikationen, die auf Windows 10 Desktops, Windows 10 Tablets, Windows 10 Phones, Xbox One, Raspberry PI2, HoloLens und Surface Hub laufen können sollen. Und mit Blick auf die Zukunft kommen eventuell noch mehr Gerätekategorien, wer kann das heute schon sagen?
Wie soll das funktionieren?
Als Entwickler stellt man sich sofort zwei Fragen: Wie soll das funktionieren, wenn meine App mit so vielen unterschiedlichen Bildschirmgrößen funktionieren soll? Und: Wie soll das funktionieren, wenn ich Eigenschaften einer bestimmten Geräteklasse ansprechen will, die es vielleicht gar nicht auf allen Geräteklassen gibt.
Um letztere Herausforderung dreht sich dieser Blogpost.
Es liegt die Vermutung nahe, dass Universal Windows Apps immer nur den kleinsten gemeinsamen Nenner der auf unterschiedlichen Geräteklassen verfügbaren Fähigkeiten adressieren können. Diese Annahme ist falsch!
Dennoch ist sie nicht aus der Luft gegriffen, denn wenn man sich überlegt, wie in der Vergangenheit der Mechanismus der Portable Class Libraries funktioniert hat, dann war das genau dieses Prinzip: Über die Portable Class Libraries konnte ich .NET Code schreiben und damit eine .dll erzeugen, die sowohl auf Windows Phone als auch auf Windows als auch auf Xbox 360 funktioniert hat. Dabei habe ich mit jeder Zielplattform die Anzahl der in der Portable Class Library verfügbaren Namespaces eingeschränkt, da die letztlich verfügbaren Namespaces sich in der Schnittmenge der jeweiligen .NET Profile befinden. In der Praxis hat das bedeutet, dass ich Portable Class Libraries nur eingeschränkt benutzen konnte und in vielen Fällen primär für Klassen, die eben keine besonders "speziellen" Namespaces benötigt haben, was wiederum in der Konsequenz die Wiederverwendung von Code über mehrere Plattformen hinweg deutlich reduziert hat.
Es geht bei Windows Universal Apps nicht um den kleinsten gemeinsamen Nenner!
Ich kann es nicht deutlich genug sagen: Es geht bei Windows Universal Apps nicht um den kleinsten gemeinsamen Nenner! Es geht darum, jede Plattform optimal nutzen zu können und trotzdem dafür zu sorgen, dass die App auf allen Plattformen läuft. Was wie Magie klingt funktioniert mit Hilfe der Extension SDKs.
Die Extension SDKs kann mal wie Referenzen in Visual Studio zum Universal App Projekt hinzufügen. Dadurch werden uns während der Entwicklung einer Universal App zusätzliche Namespaces angeboten.
Die Extension SDKs erweitern also das Angebot der zur Verfügung stehenden Namespaces um Namespaces, die sich nicht in der Menge der Universal Windows Runtime APIs befinden. Umgekehrt habe ich als Entwickler die Garantie, dass Universal Windows Runtime APIs auf allen Geräten zur Verfügung stehen.
Wenn ich Beispielsweise die StatusBar auf Windows Phone anprogrammieren möchte, dann muss ich dafür das Microsoft Mobile Extension SDK einbinden, anderenfalls wird die Klasse StatusBar nicht gefunden.
Nach dem Einbinden steht mir die Klasse zur Verfügung und ich kann die StatusBar ein- und ausblenden und im Quellcode entsprechende Aufrufe machen.
Vorsicht: TypeLoadException
Wenn ich die Software jetzt kompiliere und aufs Telefon installiere, dann wird alles funktionieren wie geplant. Das spannende ist aber, dass ich die App auch auf alle anderen Windows 10 Geräteklassen installieren kann. Auch auf welchen, die gar keine StatusBar haben! Die App läuft da auch völlig problemlos, bis zu dem Zeitpunkt wo ich versuche die StatusBar API im Code anzusprechen: Dann gibt es eine TypeLoadException!
Dieser Punkt ist ungeheuer wichtig für mich als Entwicker. Ich muss also sicherstellen, dass zur Laufzeit die APIs aus den Extension SDKs auch tatsächlich vorhanden sind. Hier liegt ein Paradigmenwechsel für mich als Programmierer vor: Während ich in der Vergangenheit dediziert für eine bestimmte Gerätekategorie entwickelt habe und dadurch darauf schließen konnte, welche APIs vorhanden sind, programmieren wir hier so, dass wir einfach alle Features nutzen, die auf der jeweiligen Plattform vorhanden sind. Welche das sind, finden wir erst zur Laufzeit heraus!
Das ganze ist unter dem Begriff "Feature Detection" auch bei Webentwicklern als Best Practice etabliert, die beim Entwickeln für unterschiedliche Browser vor der gleichen Herausforderung stehen.
Um herauszufinden, ob ein Feature vorhanden ist, gibt es die Klasse Windows.Foundation.Metadata.ApiInformation . Diese stellt uns beispielsweise die IsTypePresent() Methode zur Verfügung.
So kann ich also – bevor ich meinen Aufruf auf die StatusBar tätige – abfragen, ob die StatusBar tatsächlich vorhanden ist. IsTypePresent() erwartet einen String als Parameter. Damit ich hier nicht an Tippfehlern verzweifle bietet es sich an mit typeof zu arbeiten:
Das sorgt dafür, dass uns zur Laufzeit nichts um die Ohren fliegt. Wer sich jetzt fragt, wie es funktioniert, dass typeof(StatusBar) ausgewertet werden kann, obwohl es StatusBar doch gar nicht zur Laufzeit gibt, der hat gut aufgepasst! Schönerweise wird typeof aber schon zum Zeitpunkt der Kompilierung ausgewertet, so dass zur Laufzeit hier mit einem String gearbeitet werden kann.
Fazit
Auf den ersten Blick mag das Arbeiten mit Extension SDKs kompliziert wirken, wir bekommen aber im Gegenzug die Möglichkeit unsere Apps wirklich überall laufen zu lassen, wo die Windows Universal Platform vorhanden ist – also auf jedem Windows 10 Gerät. Durch das Erweitern des Funktionsumfangs mit hilfe der Extension SDKs schränken wir die Menge der unterstützen Gerätetypen nicht ein – lediglich gerätespezifische Funktionen sind eben nur auf bestimmten Gerätenklassen verfügbar. Meines Erachtens: Großes Kino!