Erstellen, Testen und Bereitstellen von Android-Apps

Azure DevOps Services

Sie können Pipelines einrichten, um Android-Anwendungen automatisch zu erstellen, zu testen und bereitzustellen.

Voraussetzungen

Sie benötigen folgende Elemente:

Einrichten einer Pipeline

Führen Sie die folgenden Aufgaben aus, um eine Pipeline für eine Android-Beispielanwendung einzurichten.

  1. Forken Sie das folgende Repository in Ihr GitHub-Konto, um den Code für eine einfache Android-Anwendung abzurufen.

    https://github.com/MicrosoftDocs/pipelines-android
    
  2. Melden Sie sich bei Ihrer Azure DevOps-Organisation an, und wechseln Sie zu Ihrem Projekt.

  3. Wählen Sie Pipelines>Pipeline erstellen oderNeue Pipeline aus.

  4. Wählen Sie GitHub als Speicherort für Ihren Quellcode aus.

    Screenshot showing list of repositories to select from.

    Möglicherweise werden Sie zu GitHub weitergeleitet, um sich anzumelden. Geben Sie in diesem Fall Ihre Anmeldeinformationen für GitHub ein.

  5. Wählen Sie das Repository -android aus, das Sie zuvor geforkt haben.

  6. Wählen Sie auf dem folgenden Bildschirm Genehmigen und installieren aus.

    Azure Pipelines generiert eine YAML-Datei für Ihre Pipeline.

  7. Klicken Sie auf Run (Ausführen).

  8. Committen Sie direkt in den Mainbranch, und wählen Sie dann erneut Ausführen aus.

  9. Warten Sie, bis die Ausführung beendet ist.

Sie verfügen nun über eine funktionierende YAML-Datei (azure-pipelines.yml) in Ihrem Repository, die Sie anpassen können.

Tipp

Um Änderungen an der YAML-Datei vorzunehmen, wählen Sie die Pipeline auf der Seite Pipelines aus, und Bearbeiten Sie dann die azure-pipelines.yml-Datei.

Erstellen mit Gradle

Gradle ist ein gängiges Buildtool zum Erstellen von Android-Projekten. Weitere Informationen zu Ihren Optionen finden Sie in der Gradle-Aufgabe.

# https://learn.microsoft.com/azure/devops/pipelines/ecosystems/android
pool:
  vmImage: 'macOS-latest'

steps:
- task: Gradle@2
  inputs:
    workingDirectory: ''
    gradleWrapperFile: 'gradlew'
    gradleOptions: '-Xmx3072m'
    publishJUnitResults: false
    testResultsFiles: '**/TEST-*.xml'
    tasks: 'assembleDebug'

Anpassen des Buildpfads

  • Passen Sie den Wert workingDirectory an, wenn sich Ihre gradlew-Datei nicht im Stammverzeichnis des Repositorys befindet. Der Verzeichniswert sollte dem Stammverzeichnis des Repositorys ähneln, z. B. AndroidApps/MyApp oder $(system.defaultWorkingDirectory)/AndroidApps/MyApp.

  • Passen Sie den Wert gradleWrapperFile an, wenn sich Ihre gradlew-Datei nicht im Stammverzeichnis des Repositorys befindet. Der Dateipfadwert sollte dem Stammverzeichnis des Repositorys ähneln, z. B. AndroidApps/MyApp/gradlew oder $(system.defaultWorkingDirectory)/AndroidApps/MyApp/gradlew.

Anpassen von Gradle-Aufgaben

Passen Sie den Wert Aufgaben für die von Ihnen bevorzugte Buildvariante an, z. B. assembleDebug oder assembleRelease. Weitere Informationen finden Sie in der folgenden Entwicklungsdokumentation für Google Android:

Signieren und Ausrichten eines Android-Pakets (APK)

Wenn Ihr Build das APK noch nicht signiert und Zipalign dafür ausgeführt hat, fügen Sie der YAML die Android-Signaturaufgabe hinzu. Ein APK muss signiert sein, um auf einem Gerät statt auf einem Emulator ausgeführt zu werden. Das Ausführen von Zipalign reduziert den von der Anwendung verbrauchten RAM.

Wichtig

Es wird empfohlen, jedes der folgenden Kennwörter in einer geheimen Variablen zu speichern.

- task: AndroidSigning@2
  inputs:
    apkFiles: '**/*.apk'
    jarsign: true
    jarsignerKeystoreFile: 'pathToYourKeystoreFile'
    jarsignerKeystorePassword: '$(jarsignerKeystorePassword)'
    jarsignerKeystoreAlias: 'yourKeystoreAlias'
    jarsignerKeyPassword: '$(jarsignerKeyPassword)'
    zipalign: true

Test

Testen auf dem Android-Emulator

Erstellen Sie die Bash-Aufgabe, und fügen Sie den untenstehenden Code ein, um den Emulator zu installieren und auszuführen. Vergessen Sie nicht, die Emulatorparameter an Ihre Testumgebung anzupassen. Der Emulator beginnt als Hintergrundprozess und ist in späteren Aufgaben verfügbar.

#!/usr/bin/env bash

# Install AVD files
echo "y" | $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager --install 'system-images;android-27;google_apis;x86'

# Create emulator
echo "no" | $ANDROID_HOME/tools/bin/avdmanager create avd -n xamarin_android_emulator -k 'system-images;android-27;google_apis;x86' --force

$ANDROID_HOME/emulator/emulator -list-avds

echo "Starting emulator"

# Start emulator in background
nohup $ANDROID_HOME/emulator/emulator -avd xamarin_android_emulator -no-snapshot > /dev/null 2>&1 &
$ANDROID_HOME/platform-tools/adb wait-for-device shell 'while [[ -z $(getprop sys.boot_completed | tr -d '\r') ]]; do sleep 1; done; input keyevent 82'

$ANDROID_HOME/platform-tools/adb devices

echo "Emulator started"

Testen auf von Azure gehosteten Geräten

Fügen Sie die Aufgabe App Center Test hinzu, um die Anwendung in einem gehosteten Lab mit iOS- und Android-Geräten zu testen. Eine kostenlose Testversion von App Center ist erforderlich, deren kostenpflichtige Version später verwendet werden muss.

Registrieren Sie sich zuerst bei App Center.

# App Center test v1
# Test app packages with Visual Studio App Center.
- task: AppCenterTest@1
  inputs:
    appFile: # string. Alias: app. Required. Binary application file path. 
    artifactsDirectory: '$(Build.ArtifactStagingDirectory)/AppCenterTest' # string. Alias: artifactsDir. Required. Artifacts directory. Default: $(Build.ArtifactStagingDirectory)/AppCenterTest.
  # Prepare Tests
    #prepareTests: true # boolean. Alias: enablePrepare. Prepare tests. Default: true.
    frameworkOption: 'appium' # 'appium' | 'espresso' | 'calabash' | 'uitest' | 'xcuitest'. Alias: framework. Required when enablePrepare = true. Test framework. Default: appium.
    #appiumBuildDirectory: # string. Alias: appiumBuildDir. Required when enablePrepare = true && framework = appium. Build directory. 
    #espressoBuildDirectory: # string. Alias: espressoBuildDir. Optional. Use when enablePrepare = true && framework = espresso. Build directory. 
    #espressoTestApkFile: # string. Alias: espressoTestApkPath. Optional. Use when enablePrepare = true && framework = espresso. Test APK path. 
    #calabashProjectDirectory: # string. Alias: calabashProjectDir. Required when enablePrepare = true && framework = calabash. Project directory. 
    #calabashConfigFile: # string. Optional. Use when enablePrepare = true && framework = calabash. Cucumber config file. 
    #calabashProfile: # string. Optional. Use when enablePrepare = true && framework = calabash. Profile to run. 
    #calabashSkipConfigCheck: false # boolean. Optional. Use when enablePrepare = true && framework = calabash. Skip Configuration Check. Default: false.
    #uiTestBuildDirectory: # string. Alias: uitestBuildDir. Required when enablePrepare = true && framework = uitest. Build directory. 
    #uitestStorePath: # string. Optional. Use when enablePrepare = true && framework = uitest. Store file. 
    #uiTestStorePassword: # string. Alias: uitestStorePass. Optional. Use when enablePrepare = true && framework = uitest. Store password. 
    #uitestKeyAlias: # string. Optional. Use when enablePrepare = true && framework = uitest. Key alias. 
    #uiTestKeyPassword: # string. Alias: uitestKeyPass. Optional. Use when enablePrepare = true && framework = uitest. Key password. 
    #uiTestToolsDirectory: # string. Alias: uitestToolsDir. Optional. Use when enablePrepare = true && framework = uitest. Test tools directory. 
    #signInfo: # string. Optional. Use when framework = calabash || framework = uitest. Signing information. 
    #xcUITestBuildDirectory: # string. Alias: xcuitestBuildDir. Optional. Use when enablePrepare = true && framework = xcuitest. Build directory. 
    #xcUITestIpaFile: # string. Alias: xcuitestTestIpaPath. Optional. Use when enablePrepare = true && framework = xcuitest. Test IPA path. 
    #prepareOptions: # string. Alias: prepareOpts. Optional. Use when enablePrepare = true. Additional options. 
  # Run Tests
    #runTests: true # boolean. Alias: enableRun. Run tests. Default: true.
    credentialsOption: 'serviceEndpoint' # 'serviceEndpoint' | 'inputs'. Alias: credsType. Required when enableRun = true. Authentication method. Default: serviceEndpoint.
    #serverEndpoint: # string. Required when enableRun = true && credsType = serviceEndpoint. App Center service connection. 
    #username: # string. Required when enableRun = true && credsType = inputs. App Center username. 
    #password: # string. Required when enableRun = true && credsType = inputs. App Center password. 
    appSlug: # string. Required when enableRun = true. App slug. 
    devices: # string. Required when enableRun = true. Devices. 
    #series: 'master' # string. Optional. Use when enableRun = true. Test series. Default: master.
    #dsymDirectory: # string. Alias: dsymDir. Optional. Use when enableRun = true. dSYM directory. 
    localeOption: 'en_US' # 'da_DK' | 'nl_NL' | 'en_GB' | 'en_US' | 'fr_FR' | 'de_DE' | 'ja_JP' | 'ru_RU' | 'es_MX' | 'es_ES' | 'user'. Alias: locale. Required when enableRun = true. System language. Default: en_US.
    #userDefinedLocale: # string. Optional. Use when enableRun = true && locale = user. Other locale. 
    #loginOptions: # string. Alias: loginOpts. Optional. Use when enableRun = true && credsType = inputs. Additional options for login. 
    #runOptions: # string. Alias: runOpts. Optional. Use when enableRun = true. Additional options for run. 
    #skipWaitingForResults: false # boolean. Alias: async. Optional. Use when enableRun = true. Do not wait for test result. Default: false.
  # Advanced
    #cliFile: # string. Alias: cliLocationOverride. App Center CLI location. 
    #showDebugOutput: false # boolean. Alias: debug. Enable debug output. Default: false.

Beibehalten von Artefakten mit dem Builddatensatz

Fügen Sie die Aufgaben zum Kopieren von Dateien und Veröffentlichen von Buildartefakten hinzu. Ihr APK wird mit dem Builddatensatz oder Test gespeichert und in späteren Pipelines bereitgestellt. Weitere Informationen finden Sie unter Artefakte.

- task: CopyFiles@2
  inputs:
    contents: '**/*.apk'
    targetFolder: '$(build.artifactStagingDirectory)'
- task: PublishBuildArtifacts@1

Bereitstellen

Hinzufügen von App Center

Fügen Sie die Aufgabe App Center Distribute hinzu, um eine Anwendung an eine Gruppe von Tester*innen oder Betabenutzer*innen zu verteilen, oder stufen Sie die Anwendung auf Intune oder Google Play höher. Ein kostenloses App Center-Konto wird benötigt (es ist keine Zahlung erforderlich).

# App Center distribute v3
# Distribute app builds to testers and users via Visual Studio App Center.
- task: AppCenterDistribute@3
  inputs:
    serverEndpoint: # string. Required. App Center service connection. 
    appSlug: # string. Required. App slug. 
    appFile: # string. Alias: app. Required. Binary file path. 
    #buildVersion: # string. Build version. 
    releaseNotesOption: 'input' # 'input' | 'file'. Alias: releaseNotesSelection. Required. Create release notes. Default: input.
    releaseNotesInput: # string. Required when releaseNotesSelection = input. Release notes. 
    #releaseNotesFile: # string. Required when releaseNotesSelection = file. Release notes file. 
    #isMandatory: false # boolean. Require users to update to this release. Default: false.
    destinationType: 'groups' # 'groups' | 'store'. Required. Release destination. Default: groups.
    #distributionGroupId: # string. Alias: destinationGroupIds. Optional. Use when destinationType = groups. Destination IDs. 
    #destinationStoreId: # string. Required when destinationType = store. Destination ID. 
    #isSilent: # boolean. Optional. Use when destinationType = groups. Do not notify testers. Release will still be available to install. 
  # Symbols
    #symbolsOption: 'Apple' # 'Apple' | 'Android' | 'UWP'. Alias: symbolsType. Symbols type. Default: Apple.
    #symbolsPath: # string. Optional. Use when symbolsType == AndroidNative || symbolsType = Windows. Symbols path. 
    #appxsymPath: # string. Optional. Use when symbolsType = UWP. Symbols path (*.appxsym). 
    #symbolsDsymFiles: # string. Alias: dsymPath. Optional. Use when symbolsType = Apple. dSYM path. 
    #symbolsMappingTxtFile: # string. Alias: mappingTxtPath. Optional. Use when symbolsType = Android. Mapping file. 
    #nativeLibrariesPath: # string. Optional. Use when symbolsType == Android. Native Library File Path. 
    #symbolsIncludeParentDirectory: # boolean. Alias: packParentFolder. Optional. Use when symbolsType = Apple. Include all items in parent folder.

Installieren von Google Play

Installieren Sie die Google Play-Erweiterung, und verwenden Sie die folgenden Aufgaben, um die Interaktion mit Google Play zu automatisieren. Standardmäßig authentifizieren sich diese Aufgaben bei Google Play mit einer Dienstverbindung, die Sie konfigurieren.

Freigabe

Fügen Sie die Google Play Release-Aufgabe hinzu, um eine neue Android-App-Version im Google Play Store zu veröffentlichen.

- task: GooglePlayRelease@4
  inputs:
    apkFile: '**/*.apk'
    serviceEndpoint: 'yourGooglePlayServiceConnectionName'
    track: 'internal'

Höherstufen

Fügen Sie die Google Play Promote-Aufgabe hinzu, um ein zuvor veröffentlichtes Android-Anwendungsupdate von einem Titel auf einen anderen höher zu stufen, z. B.alpha → beta.

- task: GooglePlayPromote@3
  inputs:
    packageName: 'com.yourCompany.appPackageName'
    serviceEndpoint: 'yourGooglePlayServiceConnectionName'
    sourceTrack: 'internal'
    destinationTrack: 'alpha'

Erhöhen des Rollouts

Fügen Sie die Google Play Increase Rollout-Aufgabe hinzu, um den Rollout-Prozentsatz einer Anwendung zu erhöhen, die zuvor für den rollout-Titel veröffentlicht wurde.

- task: GooglePlayIncreaseRollout@2
  inputs:
    packageName: 'com.yourCompany.appPackageName'
    serviceEndpoint: 'yourGooglePlayServiceConnectionName'
    userFraction: '0.5' # 0.0 to 1.0 (0% to 100%)

Statusaktualisierung

Fügen Sie die Google Play Status Update-Aufgabe hinzu, um den Rolloutstatus einer Anwendung zu aktualisieren, die zuvor für den rollout-Titel veröffentlicht wurde.

  - task: GooglePlayStatusUpdate@2
    inputs:
      authType: ServiceEndpoint
      packageName: 'com.yourCompany.appPackageName'
      serviceEndpoint: 'yourGooglePlayServiceConnectionName'
      status: 'inProgress' # draft | inProgress | halted | completed

Häufig gestellte Fragen

F: Wie erstelle ich App Bundle?

A: Sie können Ihr App Bundle mit einem Inlineskript und einer sicheren Datei erstellen und signieren. Laden Sie dazu zunächst Ihren Keystore herunter, und speichern Sie ihn als sichere Datei in der Bibliothek. Erstellen Sie dann Variablen für keystore.password, key.alias und key.password in einer Variablengruppe.

Verwenden Sie als Nächstes die Aufgaben Sichere Datei herunterladen und Bash, um Ihren Keystore herunterzuladen und Ihr App Bundle zu erstellen und zu signieren.

Laden Sie in dieser YAML-Datei eine sichere app.keystore-Datei herunter, und verwenden Sie ein Bash-Skript zum Generieren eines App Bundle. Verwenden Sie dann Dateien kopieren, um das App Bundle zu kopieren. Erstellen und speichern Sie dort ein Artefakt mit Buildartefakt veröffentlichen, oder verwenden Sie die Google Play-Erweiterung zum Veröffentlichen.

- task: DownloadSecureFile@1
  name: keyStore
  displayName: "Download keystore from secure files"
  inputs:
    secureFile: app.keystore

- task: Bash@3
  displayName: "Build and sign App Bundle"
  inputs:
    targetType: "inline"
    script: |
      msbuild -restore $(Build.SourcesDirectory)/myAndroidApp/*.csproj -t:SignAndroidPackage -p:AndroidPackageFormat=aab -p:Configuration=$(buildConfiguration) -p:AndroidKeyStore=True -p:AndroidSigningKeyStore=$(keyStore.secureFilePath) -p:AndroidSigningStorePass=$(keystore.password) -p:AndroidSigningKeyAlias=$(key.alias) -p:AndroidSigningKeyPass=$(key.password)

- task: CopyFiles@2
  displayName: 'Copy deliverables'
  inputs:
    SourceFolder: '$(Build.SourcesDirectory)/myAndroidApp/bin/$(buildConfiguration)'
    Contents: '*.aab'
    TargetFolder: 'drop'