Plattformübergreifende Augmented Reality Apps mit .NET MAUI
Plattformübergreifende Entwicklung mobiler Anwendungen für iOS und Android
Die Entwicklung mobiler Anwendungen ist aufgrund der Unterschiede zwischen den einzelnen Plattformen meist mit großem Aufwand verbunden. Unter iOS werden Apps mit der Programmiersprache Swift entwickelt, während Android auf Java/Kotlin setzt und entsprechend über ein völlig anderes Ökosystem von Frameworks und Bibliotheken verfügt. Auch viele der grundlegenden Entwicklungskonzepte (bspw. Designprinzipien, UI-Erstellung, Lifecycle-Konzepte, Navigation, etc.) sind sehr unterschiedlich, sodass viele mobile Anwendungen mit vollständig separaten Codebasen für iOS und Android entwickelt werden.
Plattformübergreifende Frameworks, wie Flutter, React Native und .NET MAUI (das Nachfolge-Framework von Xamarin), bieten hier eine attraktive Lösung. Sie ermöglichen die Verwendung einer einzigen Codebasis für die Entwicklung von Apps, die nahtlos auf verschiedenen Plattformen funktionieren. Diese Herangehensweise reduziert nicht nur den Implementierungsaufwand und damit auch die Kosten und Time-to-Market erheblich, sondern ermöglicht auch eine konsistente UI/UX über Plattformen hinweg. Gleichzeitig gewährleisten die meisten Frameworks, dass Entwickler alle nativen Schnittstellen und Bibliotheken vollumfänglich nutzen können. Dadurch gibt es hinsichtlich der implementierbaren Funktionalität keine Einschränkungen. Die entwickelten Anwendungen werden, im Falle von .NET MAUI, in nativen Code übersetzt, sodass es auch keine Unterschiede hinsichtlich Performance, Look & Feel oder Ressourcenanforderungen gibt.
.NET MAUI ❤️ Augmented Reality?
Die Entwicklung von Augmented Reality (AR) Apps mit diesen Frameworks stellt jedoch noch immer eine große Herausforderung dar. AR-Experiences erfordern die Nutzung plattformspezifischer APIs (ARKit für iOS und ARCore
für Android) und nutzen separate Rendering Engines. Für Xamarin stellt Microsoft entsprechende Bindings für ARKit und ARCore
sowie Guides (bspw. Augmented Reality in Xamarin.Forms und Augmented Reality in Xamarin.Android with ARCore) zur Verfügung.
Für .NET MAUI, den offiziellen Nachfolger von Xamarin, das ab dem 01.05.2024 nicht mehr supported wird, gibt es weder aktuelle Bindings für ARCore
oder andere Higher-Level Bibliotheken (Bindings für ARKit sind verfügbar) noch OpenGL. Es fehlen auch Guides, Anleitungen oder Blog-Posts zur Entwicklung von AR-Anwendungen mit MAUI. Soweit wir das einschätzen können, gibt es nirgends im Internet eine funktionierende, aktuelle Anleitung zu diesem Thema.
All das wirft die Frage auf, ob es überhaupt noch (mit vertretbarem Aufwand) möglich ist, mit MAUI entsprechende Anwendungen zu entwickeln? Müssen bestehende AR-Xamarin-Anwendungen in einem anderen Framework neu entwickelt werden?
Unsere Lösung
Für unsere Negami-Anwendung war die Migration auf .NET MAUI aufgrund des baldigen EOL von Xamarin ohnehin geplant. Die Herausforderung bestand also darin, neben der eigentlichen Migration, eine Lösung zu finden, wie AR auf MAUI umgesetzt werden kann.
iOS
Für iOS war die Sache relativ einfach. Da Microsoft weiterhin aktuelle Bindings für ARKit zur Verfügung stellt, ist die Implementierung hier ohne großen Aufwand möglich. Wir entschieden uns dafür, die AR-Funktionalität in einem Custom Control zu kapseln und dieses Control über Custom Handlers dann auf iOS zu “übersetzen”.
Zuerst erstellen wir dafür eine Klasse, die von View
erbt und unser Custom Control darstellt:
public class AugmentedRealityView : View
{
public AugmentedRealityView()
{
}
}
Dann erstellen wir einen entsprechenden Handler, indem wir zunächst eine partielle, plattformübergreifende Klasse erstellen:
public partial class AugmentedRealityViewHandler<TView, THandler> where TView : AugmentedRealityView where THandler : AugmentedRealityViewHandler<TView, THandler>
{
public static IPropertyMapper<TView, THandler> PropertyMapper = new PropertyMapper<TView, THandler>(ViewMapper)
{
};
public static CommandMapper<TView, THandler> CommandMapper = new(ViewCommandMapper)
{
};
public AbstractAugmentedRealityViewHandler(IPropertyMapper<TView, THandler> propertyMapper, CommandMapper<TView, THandler> commandMapper) : base(propertyMapper, commandMapper)
{
}
}
Für die iOS-spezifische Implementierung dieses Handlers nutzen wir File-based Multi-targeting und erstellen eine entsprechende Datei AugmentedRealityViewHandler.iOS.cs
:
public partial class AugmentedRealityViewHandler<TView, THandler> : ViewHandler<TView, ARSCNView>
{
protected ARSCNView ARView => PlatformView;
protected override ARSCNView CreatePlatformView()
{
var view = new ARSCNView();
return view;
}
}
Jetzt fehlt nur noch die Registrierung des Handlers in der MauiProgram.cs
-Datei:
.ConfigureMauiHandlers(handlers =>
{
handlers.AddHandler(typeof(AugmentedRealityView), typeof(AugmentedRealityViewHandler));
})
Und damit haben wir eine funktionierende AR-Anwendung auf iOS! Wir können jetzt mittels ARKit entsprechende AR-Sessions starten und verwalten.
Android
Unter Android bestand die erste Herausforderung darin, .NET Bindings für eine aktuelle Version der ARCore
-Bibliothek zu erstellen. Diese Bindings konnten wir relativ schnell fertigstellen und auf GitHub und Nuget veröffentlichen. Zu Testzwecken haben wir die Hello AR
-Anwendung von Xamarin nach MAUI portiert und auch auf GitHub veröffentlicht.
An diesem Punkt haben wir also bereits eine funktionierende AR-Anwendung, die sowohl auf iOS als auch Android laufen kann. Für unsere Zwecke war die direkte Verwendung von ARCore
und OpenGL
jedoch viel zu aufwendig, wir suchten also nach einer Alternative, mit der wir - ähnlich wie bei ARKit
- mit Higher-level Abstraktionen arbeiten können und das Rendering nicht selbst übernehmen müssen. Fündig wurden wir in der Sceneview-Bibliothek, dem inoffiziellen Nachfolger von Sceneform, das ursprünglich von Google entwickelt wurde. Da es auch für diese Bibliothek keine aktuellen .NET Bindings gibt, mussten diese zunächst neu erstellt werden.
Die Bindings-Erstellung für Sceneview
stellte sich als außerordentlich aufwendig dar, da Sceneview
viele Abhängigkeiten besitzt, für die auch entsprechende Bindings erstellt werden müssen. Zudem sind Sceneview
selbst und viele der Abhängigkeiten in Kotlin geschrieben, was zu einer komplexen Java-API führt.
Wir entschieden uns, die Erstellung dieser Bindings extern in Auftrag zu geben. Sie sind mittlerweile auf GitHub veröffentlicht und in anderen Projekten einsetzbar.
Nachdem die Bindings für Sceneview
vorlagen, bestand der letzte Schritt für Android darin, einen entsprechenden Handler für die AugmentedRealityViewHandler
-Klasse von oben zu schreiben:
public partial class AugmentedRealityViewHandler<TView, THandler> : ViewHandler<TView, ARSceneView>
{
protected ARSceneView ARView => PlatformView;
protected override ARSceneView CreatePlatformView()
{
var view = new ARSceneView(Context);
return view;
}
}
Damit war auch die AR-Funktionalität für Android implementiert.
Sie möchten eine webbasierte oder mobile Anwendung entwickeln lassen?
Ein paar Worte zu MAUI
Mit dem beschriebenen Vorgehen konnten wir geschätzt 95% unserer Codebasis unter iOS und Android verwenden, nur ca. 5% des Codes (ausschließlich die AR-Funktionalität) musste für jede Plattform separat entwickelt werden. Dadurch können wir neue Funktionen deutlich schneller und oftmals mit weniger Fehlern entwickeln. Durch die Definition klarer, plattformspezifischer Schnittstellen für die AR-Teile der Anwendung entsteht zudem deutlich sauberer und besser verständlicher Code.
Gleichzeitig leidet MAUI jedoch noch immer unter den gleichen Problemen, die wir schon unter Xamarin beklagt haben. Besonders die Developer-Erfahrung bei der Entwicklung für iOS (mit Mac-Pairing) ist unterirdisch. App-Abstürze, Visual-Studio-Crashes, kryptische oder überhaupt nicht vorhandene Fehlermeldungen, fehlende Logs, lange Buildzeiten und Mac-Konnektivitätsprobleme waren eigentlich an der Tagesordnung. Auf Android sieht es deutlich besser aus, aber auch hier hatten wir immer wieder Probleme mit dem Debugging und Visual Studio allgemein.
Neben der Developer-Erfahrung hatten wir auch viel mit Problemen durch Linking/Trimming zu kämpfen, die besonders schwer zu identifizieren und debuggen sind, da sie typischerweise nur im Release-Modus auftreten (mit aktivierten Trimming).
Fazit
Die Entwicklung AR-basierter, plattformübergreifende mobiler Anwendungen, mit .NET MAUI stellt aufgrund des eingestellten Supports für ARCore
einige Herausforderungen dar. In diesem Blog-Post haben wir gezeigt, wie wir diese Herausforderungen bewältigt haben und welche Schritte notwendig waren, um eine funktionale Lösung zu finden. Alle hier besprochenen Bindings sind öffentlich verfügbar und können somit auch in anderen Projekten eingesetzt werden.