Xamarin.Android und die Android API Levels

16. Juni 2015

Bei der Konfiguration von Xamarin.Android-Projekten kann eingestellt werden, welche Android API Levels angewendet werden. So kann man festlegen, gegen welches Level kompiliert wird, welches Level auf dem Zielgerät mindestens vorausgesetzt wird und für welches Level die Anwendung eigentlich geschrieben wird. Dieser Artikel beleuchtet die Anwendung der Android API Levels im Kontext von Xamarin for Visual Studio. Da eine fehlerhafte Kombination von API Levels zum Crash der App führen kann, ist ein gutes Verständnis dafür sehr empfehlenswert.

Seitdem mit Xamarin bzw. Mono die Möglichkeit besteht, mit den Standard-Windows Entwicklerwerkzeugen (Visual Studio, C#) Anwendungen für Android zu erstellen, kommen auch .NET-Entwickler in den Genuss der Entwicklung von Android Apps. Um den Einstieg in die Thematik der Android API Levels zu erleichtern, beschreibt dieser Artikel den grundsätzlichen Umgang damit.

Ein API Level ist zunächst einmal nur eine Ganzzahl. Angefangen bei Level 1 ist zum Zeitpunkt der Entstehung dieses Artikels das aktuellste API Level 22. Jede neue Android-Version (aktuell v5.1 “Lollipop MR1”) bringt i. d. R. eine neue Revision der Android Framework API mit, welche durch das API Level gekennzeichnet wird. Die Framework API wird von Android Apps genutzt, um mit der Android Platform zu interagieren. Immer dann, wenn eine neue Android-Version Updates an der mitgelieferten API vornimmt, wird die Nummer des API Levels erhöht.

Updates an der Framework API sind abwärtskompatibel, so dass ältere Anwendungen weiterhin lauffähig bleiben. Updates sind additiv, d. h. wenn alte Bestandteile der API aktualisiert werden, so werden diese nicht entfernt, sondern nur als veraltet gekennzeichnet. Nur in wenigen Fällen, z. B. im Rahmen von Security Updates), kann es sein, dass API-Teile tatsächlich geändert oder sogar entfernt werden.

Jede Version der Android Platform unterstützt genau ein API Level, wobei aber immer frühere Levels implizit unterstützt werden. Die Android Developer Website enthält eine gute Übersicht über Android-Versionen und deren unterstütze API Levels.

Über die Verteilung der verschiedenen Android-Versionen und API Levels über den Android-Gerätemarkt liefern die Android Dashboards eine gute Übersicht. Gegenwärtig machen die Android-Versionen 4.1 bis 4.4 (JellyBean und Kitkat zu ähnlichen Anteilen) ca. 80% des Marktes aus (vgl. Android Dashboards). Lollipop (API Level 21 & 22) ist mit ca. 10% im Kommen. Damit sind die API Levels 16 bis 19 am stärksten im Markt vertreten, wobei 19 (Android 4.4 “Kitkat”) für sich genommen den Löwenanteil ausmacht. Wenn man also Apps für Android erstellt. Sollte man mindestens API Level 16 unterstützen, um den allergrößten Anteil der Geräte im Markt zu abzudecken.

Doch nun zum praktischen Teil.

Eingestellt werden die API Levels in einem Xamarin.Android App Visual Studio Project in den Projekteigenschaften im Bereich Application.

ProjectProperties

  • Bei "Compile using Android version" handelt es sich um das Target Framework, gegen das die App kompiliert wird.
  • "Minimum Android to target" meint die Minimum Android Version, also die kleinste Android-Version, die die App mindestens auf dem Zielgerät voraussetzt.
  • Die "Target Android Version" meint das API Level, für das die App primär programmiert wird.

Welche API Levels jeweils zur Auswahl stehen hängt davon ab, welche auf dem Entwicklungsrechner installiert sind. Die Installation erfolgt mit dem Android SDK Manager.

Die drei Einstellungen im Visual Studio Project werden im Folgenden näher erläutert.

Target Framework

Das Target Framework bezeichnet das API Level zur Entwicklungs-/Kompilierzeit und somit das API Level, gegen das die App vorweg geprüft und übersetzt wird. Das hier eingestellte Level bewirkt, dass die Anwendung zur Laufzeit davon ausgeht, dass dieses Level und dessen Funktionsumfang zur Verfügung stehen. Es sagt jedoch nichts darüber aus, welches Level zur Laufzeit tatsächlich verfügbar ist.

Aus dem eingestellten Target Framework ergeben sich die APIs, die zur Entwicklungszeit zur Verfügung stehen. Wird eine API-Funktion aufgerufen, die erst in einem höheren API Level als das eingestellte zur Verfügung steht, wird bereits vom Compiler ein Fehler gemeldet.

Target Android Version

Die Target Android Version bezeichnet das API Level, von dem die Anwendung ausgeht, dass es zur Laufzeit verfügbar ist. Dies ist somit die Android-Version, für die die App gedacht ist und primär entwickelt wird. Die App kann sich darauf verlassen, dass alle Funktionen dieser Version auf dem Zielgerät vollständig vorhanden sind und kann diese auch vollständig nutzen. Beim Deployment wird geprüft, ob die eingestellte Version auf dem Zielgerät vorhanden ist. Falls sie nicht vorhanden ist, wird sie beim Deployment bzw. der Installation aus dem Store mit eingeschlossen.

Normalerweise wird die Target Android Version dem Target Framework entsprechen. Es gibt allerdings Ausnahmen. So könnte eine verwendete Android Library eine höhere Target Android Version voraussetzen. In diesem Fall müsste für die App die Target Android Version höher eingestellt werden als das Target Framework.

Die Target Android Version signalisiert der Android Runtime, dass die App gegen dieses API Level erfolgreich getestet wurde. Das bedeutet für Android, dass keine besondere Kompatibilitätslogik ausgeführt werden muss, um die App auf einem Gerät mit diesem API Level auszuführen. Im anderen Fall, wenn das API Level auf dem Zielgerät höher ist als die Target Android Version der App, würde Android durch spezielles Verhalten für die Aufwärtskompatibilität der App sorgen.

Minimum Android Version

Dies ist die auf dem Zielgerät mindestens vorausgesetzte Android-Version. Wird diese niedriger eingestellt als das Target Framework, signalisiert dies die Abwärtskompatibilität der App.

Falls die App APIs aufruft, die in der Minimum Android Version noch nicht existieren, crasht die App zur Laufzeit. Es ist daher notwendig, dass im Code entsprechende Runtime Checks eingebaut werden, die eine bestimmte API nur dann aufrufen lassen, wenn diese auch vorhanden ist. Mono.Android enthält dafür entsprechende Hilfsklassen.

Runtime Checks

Setzt man die Minimum Android Version auf einen niedrigeren Wert als das Target Framework, könnten einige der im Code aufgerufenen APIs zur Laufzeit nicht verfügbar sein. Trotzdem könnte die App auf einem älteren Gerät laufen, dann allerdings ohne Verfügbarkeit bestimmter Features. Der Code der App muss in diesem Fall dafür Sorge tragen, dass nur die APIs aufgerufen werden, die auch verfügbar sind. Wie macht er das?

Die Assembly Mono.Android enthält dafür das abzufragende Property Android.OS.Build.Version.SdkInt, welches den BuildVersionCode zurückgibt. Ein konkreter Runtime Check, der z. B. prüft, ob mindestens Android 4.4 (Kitkat) vorliegt, sieht dann wie folgt aus:

   1: if (Android.OS.Build.Version.SdkInt >= Android.OS.BuildVersionCodes.Kitkat) 

   2: {

   3:

   4: }

Im Falle die erstellte App läuft in einer veralteten Umgebung, könnte die App z. B. den Benutzer informieren, dass ein bestimmtes Feature nicht zur Verfügung steht. Oder das bestimmte Feature wird stillschweigend nicht angeboten. Oder die App enthält eine Alternativimplementierung. Oder… Hier ist sicher die Kreativität des Entwicklers gefragt unter Berücksichtigung der User Experience. 😉

API Level-Kombinationen

Bei der Wahl der API Levels sind Regeln zu beachten. So macht es beispielsweise keinen Sinn, gegen ein niedrigeres Target Framework zu kompilieren, als auf dem Zielgerät mindestens vorausgesetzt wird (Minimum Android Version). Oder auch gegen ein höheres Target Framework zu kompilieren, als Android durch die Target Android Version tatsächlich sicherstellt, ist nicht zulässig.

 

Target Framework (TF) =

Minimum Android Version (Min) = Target Android Version (TAV)

Normalfall.

Ein Xamarin.Android-Projekt enthält diese Kombination standardmäßig bei der Erstellung durch das Projekt-Template. Hier besteht keine Abwärtskompatibilität.

TF < Min

Nicht zulässig, da dies zu Inkompatibilität führt.

TF > Min

Abwärtskompatibilität der App, um ältere Android-Versionen zu unterstützen. Erfordert Runtime Checks im Code, um nicht unterstützte API-Aufrufe auf der jeweiligen Zielplattform zu verhindern.

TF < TAV

Empfohlen, wenn verwendete Bibliotheken ein höheres API Level voraussetzen (entspricht dem Target Framework der Bibliotheken).

TF > TAV

Nicht zulässig, da dies zu Inkompatibilität führt.

Min < TAV

Ist dann der Fall, wenn TF >= TAV ist und Abwärtskompatibilität entsprechend TF > Min gewährleistet werden soll.

Min > TAV

Nicht zulässig, da dies expliziter Aufwärtskompatibilität entsprechen würde und somit im Widerspruch zum umgesetzten Ansatz der Kompatibilitätssicherung stünde.

Bei unzulässigen Kombinationen warnt Visual Studio.

Warnungen

Android Libraries

Ein Xamarin.Android Class Library Project enthält im Gegensatz zu App Projects keine Möglichkeit zur expliziten Auswahl von Minimum und Target Android Version.

Library

Der Grund dafür ist, dass die Library in beliebigen Apps verwendet werden könnte, die für beliebige API Levels erstellt werden. Minimum und Target Android Version werden also von der App bestimmt, die die Library verwendet. Bei der Verwendung oder Erstellung von Android Libraries sollte demnach Folgendes beachtet werden.

  • Wenn eine Library konsumiert wird, sollte die Target Android Version mindestens so hoch sein, wie das Target Framework Level der Library. Das gilt im Übrigen auch für die Minimum Android Version, da man nicht wissen kann, dass die Library ein niedrigeres Level unterstützt als das, wogegen sie kompiliert worden ist.
  • Wenn eine Library erstellt wird, sollte deren Target Framework Level nicht höher als nötig eingestellt werden. Es ist gilt als Best Practice, dass man sich bei der Entwicklung einer Library auf die Verwendung möglichst weniger API Calls beschränkt, um die Library auf möglichst vielen API Levels schlussendlich verwenden zu können.

Fazit

Ein gutes Verständnis der Android API Levels ist notwendig. Es vermeidet Fehler, die erst zur Laufzeit auffallen und im schlimmsten Fall bis zum Endanwender durchschlagen sowie nur durch ein erneutes Deployment in den Store behoben werden können. Abschließend und zusammenfassend seien folgende Tipps gegeben.

  • Verwende für Target Framework, Target Android Version und Minimum Android Version standardmäßig das gleiche API Level. Weiche davon nur ab, wenn es gute Gründe dafür gibt, wie z. B. Abwärtskompatibilität zu gewährleisten.
  • Setze das Target Framework Level nur so hoch, wie für Deine App notwendig, wenn so viele Geräte wie möglich unterstützt werden sollen.
  • Beachte die Besonderheiten bei der Erstellung und dem Konsum von Android Libraries.

Siehe auch

Understanding Android API Levels (Xamarin Developer Portal)http://developer.xamarin.com/guides/android/application_fundamentals/understanding_android_api_levels

<uses-sdk> | Android Developers

http://developer.android.com/guide/topics/manifest/uses-sdk-element.html