Xamarin.Android App mit Azure DevOps bauen

Ich verwende Azure DevOps zum Organisieren meiner Projekte. Ich habe also den gesamten benötigten Code im Repository und nutze die Boards, um die notwendigen Aufgaben im Überblick zu haben. In diesem Beitrag möchte ich euch jetzt zeigen, wie ihr mit wenig Aufwand eine Pipeline in Azure DevOps erstellen könnt, welche es euch ermöglicht eure Android-Version zu bauen.

Der Beitrag ist auch schon in englischer Sprache auf Medium veröffentlicht worden.

Erstellen der Keystore-Datei

Bevor wir uns den Prozess zum Einrichten der Pipeline ansehen können, benötigen wir eine Keystore-Datei. Diese Datei wird zum Signieren der App benötigt. Zunächst öffnen wir unser Xamarin-Projekt in Visual Studio. Jetzt öffnen wir ein Terminal unter View > Terminal und in diesem Terminal verwenden wir das Keytool-Tool, um die Keystore-Datei zu generieren.

keytool -genkey 
        -v
        -keystore MyAwesomeXamarinApp.keystore
        -alias MyAwesomeXamarinApp
        -keyalg RSA
        -keysize 2048
        -validity 20000

Wir müssen uns den Alias-Wert merken, da wir diesen Wert später in unserer Pipeline angeben müssen. Die Gültigkeit des Parameters ist in Tagen angegeben, also ist 20000 eine ziemlich große Zahl, aber wir müssen sicherstellen, dass der Schlüssel nicht abläuft, da wir sonst unsere Android-Anwendung im Google Play Store nicht mehr aktualisieren können.

Der folgende Screenshot zeigt den Befehl in Aktion. Zunächst müssen wir ein Passwort festlegen, das wir uns auch merken sollten, da es in der Pipeline benötigt wird. Dies ist wichtig, denn wenn die Keystore-Datei gestohlen wird und der Dieb das Kennwort kennt, kann er Ihre vorhandene Xamarin.Android-App im Google Play Store aktualisieren. Wir müssen also sicherstellen, dass wir diese Informationen sicher aufbewahren. Danach müssen wir einige Fragen wie den Namen oder die Organisation beantworten. Wir müssen nur eine Frage beantworten, also beantworte ich die Frage nach dem aus zwei Buchstaben bestehenden Ländercode. Danach haben wir die Möglichkeit, alle unsere Daten zu validieren und mit Ja zu bestätigen. Es ist möglich, diese Datei für eine höhere Sicherheit mit einem anderen Passwort zu sichern, aber es ist auch legitim, dasselbe Passwort zu verwenden, indem Sie einfach die Eingabetaste drücken, und die Datei wird erstellt.

Keystore-Datei hochladen

Wie ich im vorherigen Absatz erwähnt habe, benötigen wir diese Keystore-Datei in unserer Pipeline. Wir öffnen Azure DevOps, navigieren zu unserem Projekt und dann zu Library, die Teil der Registerkarte Pipelines ist. Wir wechseln zu Secure Files und klicken auf + Secure file. Jetzt können wir die erstellte Keystore-Datei hochladen.

Nach dem Upload-Vorgang können wir einen Namen der Keystore-Datei angeben, da wir diesen Namen in unserer Pipeline benötigen.

Jetzt können wir auf die Registerkarte Variable groups wechseln und eine neue Gruppe namens variables erstellen. Diese Gruppe enthält drei Variablen: KeyStore-Alias, KeyStore-FileName und KeyStore-Password. Die Variable KeyStore-Password sollte als sichere Variable angelegt werden, damit niemand das Passwort sehen kann. KeyStore-Alias und KeyStore-Password werden mit den Werten aus dem Keystore-Erstellungsprozess gefüllt und KeyStore-FileName ist der Name der hochgeladenen Datei.

Pipeline erstellen

Jetzt ist es an der Zeit, die Pipeline zu erstellen. Wir wählen die Registerkarte Pipelines im linken Menü. Um eine neue Pipeline zu erstellen, verwenden wir die blaue Schaltfläche (mit der Bezeichnung New pipeline). Im ersten Schritt müssen wir den Ort von unserem Code angeben. In meinem Fall speichere ich den Code im Azure Repos Git, aber man kann den Code auch von GitHub, BitBucket oder jeder anderen Git- oder Subversion-Quelle verwenden.

Um fortzufahren, wähle ich Azure Repos Git aus. Nun sollten alle möglichen Repositories aufgelistet werden. In meinem Fall ist es nur ein Repository (Xamarin Playground), das ich auswählen werde.

Im nächsten Schritt stellt Azure DevOps einige vordefinierte Vorlagen für verschiedene Pipelines bereit. Ich verwende hier die Starter-Pipeline, um eine grundlegende Struktur der YAML-Datei zu erhalten, aber wir werden diese im nächsten Schritt gleich anpassen.

Es wird nun ein Editor angezeigt, der die aktuelle Version der YAML-Datei enthält. Jetzt müssen wir diese Datei aktualisieren, um unsere Anwendung erstellen und die APK- und AAB-Datei erstellen zu können. Das Android-Paket mit der Dateierweiterung APK ist das Dateiformat, das vom Android-Betriebssystem und einer Reihe anderer Android-basierter Betriebssysteme für die Verteilung und Installation mobiler Apps verwendet wird. Google hat das Android App Bundle (AAB) eingeführt, das neue Format zum Veröffentlichen von Apps im Google Play Store. Dieses Paket enthält den Code und die Ressourcen der Anwendung. Es reduziert die anfängliche Downloadgröße der App, da nur die benötigten Teile auf das Gerät heruntergeladen werden.

Das folgende Code-Snippet zeigt die vollständige Pipeline, aber keine Sorge, ich werde diese anschließend erläutern.

# Xamarin.Android

trigger:
- main

variables:
- group: 'variables'

jobs:
  - job: 'BuildAndroid'
    pool:
      vmImage: 'windows-2022'
      
    variables:
      buildConfiguration: 'Release'
      outputDirectory: '$(build.binariesDirectory)/$(buildConfiguration)'

    steps:
      - task: NuGetToolInstaller@1

      - task: NuGetCommand@2
        inputs:
          restoreSolution: '**/*.sln'
      
      - task: XamarinAndroid@1
        inputs:
          projectFile: '**/*droid*.csproj'
          outputDirectory: '$(build.binariesDirectory)'
          configuration: '$(buildConfiguration)'
          msbuildVersionOption: latest
      
      - task: DownloadSecureFile@1
        name: keystore
        inputs:
          secureFile: '$(KeyStore-FileName)'
          
      - task: AndroidSigning@3
        inputs:
          apkFiles: '**/*.apk'
          apksign: true
          zipalign: true
          apksignerKeystoreFile: '$(KeyStore-FileName)'
          apksignerKeyPassword: '$(KeyStore-Password)'
          apksignerKeystoreAlias: '$(KeyStore-Alias)'
          apksignerKeystorePassword: '$(KeyStore-Password)'
      
      - task: CopyFiles@2
        inputs:
          Contents: '**/*.apk'
          TargetFolder: '$(Build.ArtifactStagingDirectory)'
          OverWrite: true
          flattenFolders: true
          
      - task: PublishBuildArtifacts@1
        inputs:
          PathtoPublish: '$(Build.ArtifactStagingDirectory)'
          ArtifactName: 'MyAwesomeApp-$(Build.BuildNumber)'
          publishLocation: Container

      - task: XamarinAndroid@1
        inputs:
          projectFile: '**/*droid*.csproj'
          outputDirectory: '$(Build.BinariesDirectory)'
          configuration: '$(BuildConfiguration)'
          clean: true
          msbuildVersionOption: latest
          msbuildArguments: '/p:JavaSdkDirectory="$(JAVA_HOME_11_X64)/" 
                             /p:AndroidPackageFormat=aab 
                             /t:SignAndroidPackage 
                             /p:AndroidNdkDirectory="$(androidNdkPath)" 
                             /p:AndroidKeyStore="True" 
                             /p:AndroidSigningKeyStore="$(keystore.secureFilePath)" 
                             /p:AndroidSigningKeyPass="$(KeyStore-Password)" 
                             /p:AndroidSigningKeyAlias="$(KeyStore-Alias)" 
                             /p:AndroidSigningStorePass="$(KeyStore-Password)"'

      - task: CopyFiles@2
        inputs:
          Contents: '**/*.aab'
          TargetFolder: '$(Build.ArtifactStagingDirectory)'
          OverWrite: true
          flattenFolders: true

      - task: PublishBuildArtifacts@1
        inputs:
          PathtoPublish: '$(Build.ArtifactStagingDirectory)'
          ArtifactName: 'MyAwesomeApp-$(Build.BuildNumber)'
          publishLocation: Container

Der Anfang definiert die Metadaten. In meinem Fall möchte ich nur auf Änderungen im main-Branch lauschen, aber es können auch alle möglichen Zweige wie dev oder staging definiert werden.

Die Schlüsselwort variables verbinden unsere erstellte Variablengruppe mit der Pipeline. Stellen Sie sicher, dass der Variablenname mit dem Namen der Variablengruppe übereinstimmt.

Ich verwende Jobs in dieser Pipeline, weil ich später auch die Schritte zum Erstellen der iOS-Version in diese Pipeline einfügen möchte. Aber im Moment haben wir nur einen Job namens BuildAndroid.

Da die Android-App bereits auf Android 12 abzielt, benötigen wir Visual Studio 2022, um das Projekt erstellen zu können. Aus diesem Grund verwenden wir windows-2022, aber wir können auch windows-Lastest verwenden.
Der nächste Abschnitt enthält einige Variablen. In unserem Fall ist es die aktuelle Build-Konfiguration und das Ausgabeverzeichnis.

Jetzt passiert die Magie, denn wir definieren die Schritte für unsere Pipeline. Zunächst müssen wir sicherstellen, dass NuGet installiert ist. Anschließend führen wir ein NuGet Restore für unsere Lösung durch, um alle benötigten NuGet-Pakete zu installieren.

Der XamarinAndroid@1-Task wird zum Erstellen des Android-Projekts verwendet. Wir geben den Pfad zur csproj-Datei des Android-Projekts an und übergeben die Konfiguration.

Die nächste Aufgabe lädt die Keystore-Datei aus den sicheren Dateien herunter. Wir verwenden den Namen, um eine Referenz auf diese Datei zu erhalten, da wir diese später benötigen.

Unsere Pipeline wird in der Lage sein, eine APK-Datei zu erstellen, die seitlich auf ein Android-Gerät geladen werden kann. Dazu müssen wir diese Datei signieren. Daher verwenden wir den Task AndroidSigning@3. Wir suchen nach der APK-Datei und verwenden die definierte Variable, um Zugriff auf das Passwort, den Alias ​​und den Keystore-Dateinamen zu erhalten. In meinem Fall sind apksignerKeyPassword und apksignerKeystorePassword identisch, da ich im Erstellungsprozess der Keystore-Datei kein anderes Passwort festlege.

Die nächsten beiden Schritte sind das Kopieren und Veröffentlichen der entsprechenden APK-Datei.

Der Google Play Store akzeptiert nur AAB-Dateien, die nicht von der Seite auf Ihr Android-Gerät geladen werden können. Aber mit unserer Pipeline sollte es möglich sein, auch die AAB-Datei zu erstellen. Daher benötigen wir eine weiteren XamarinAndroid@1-Task. Aber dieses Mal geben wir einige msbuild-Argumente an, um die AAB-Datei zu erstellen. Wie man in den Argumenten sehen kann, verwenden wir auch hier den Verweis auf unsere heruntergeladene sichere Datei.

Die letzten beiden Schritte sind nur das Kopieren und Veröffentlichen der entsprechenden AAB-Datei.

Ausführen der Pipeline

Jetzt ist es an der Zeit, die Pipeline laufen zu lassen. Klicken Sie einfach auf Save und entscheiden, ob wir einen separaten Branch für die Pipeline erstellen möchten oder diese direkt auf den aktuellen Branch commiten wollen. Lasst uns nun die Pipeline ausführen.

Wie man sehen kann, war die Pipeline erfolgreich und wenn man auf den Link 1 published klickt, der im Abschnitt Related auf der Zusammenfassungsseite angezeigt wird, hat man Zugriff auf die APK- und die AAB-Datei.

Zusammenfassung

In diesem Beitrag habe ich gezeigt, wie man eine Pipeline zum Erstellen und Veröffentlichen einer Xamarin.Android-Anwendung mit Azure DevOps einrichten kann. Diese Pipeline erstellt beide Dateien im selben Lauf, was möglicherweise nicht so nützlich ist, da man entweder eine Testversion möchte, bei der es sich um die APK-Datei handelt, oder man möchte eine Store-Version, bei der es sich um die AAB-Datei handelt. Aber nun stehen alle erforderlichen Tasks, um diese Dateien zu erstellen, zur Verfügung und ihr könnt entscheiden, welche Variante ihr benötigt.

Map Control mit bindable Pins erweitern Nützliche Converter Sammlung – Teil 2 Eigene Schriftarten in Xamarin.Forms Apps