Compilare, testare e distribuire app Android

Servizi di Azure DevOps

È possibile configurare le pipeline per compilare, testare e distribuire automaticamente applicazioni Android.

Prerequisiti

È necessario disporre degli elementi seguenti:

Configurare la pipeline

Eseguire le attività seguenti per configurare una pipeline per un'applicazione Android di esempio.

  1. Creare un fork del repository seguente nell'account GitHub per ottenere il codice per una semplice applicazione Android.

    https://github.com/MicrosoftDocs/pipelines-android
    
  2. Accedere all'organizzazione di Azure DevOps e passare al progetto.

  3. Selezionare Pipeline>Crea pipeline o Nuova pipeline.

  4. Selezionare GitHub come percorso del codice sorgente.

    Screenshot showing list of repositories to select from.

    Si potrebbe essere reindirizzati a GitHub per l'accesso. In questo caso, immettere le credenziali di GitHub.

  5. Selezionare il repository -android creato in precedenza tramite fork.

  6. Selezionare Approva e installa nella schermata seguente.

    Azure Pipelines genera un file YAML per la pipeline.

  7. Selezionare Esegui.

  8. Eseguire il commit direttamente nel ramo main e quindi scegliere Esegui di nuovo.

  9. Attendere il completamento dell'esecuzione.

È disponibile un file YAML funzionante (azure-pipelines.yml) nel repository pronto per la personalizzazione.

Suggerimento

Per apportare modifiche al file YAML, selezionare la pipeline nella pagina Pipeline e quindi Modificare il azure-pipelines.yml file.

Compilazione con Gradle

Gradle è uno strumento di compilazione comune usato per la compilazione di progetti Android. Per altre informazioni sulle opzioni, vedere l'attività Gradle .

# 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'

Modificare il percorso di compilazione

  • Modificare il valore workingDirectory se il gradlew file non si trova nella radice del repository. Il valore della directory deve essere simile alla radice del repository, ad esempio AndroidApps/MyApp o $(system.defaultWorkingDirectory)/AndroidApps/MyApp.

  • Modificare il valore gradleWrapperFile se il gradlew file non si trova nella radice del repository. Il valore del percorso del file deve essere simile alla radice del repository, ad esempio AndroidApps/MyApp/gradlew o $(system.defaultWorkingDirectory)/AndroidApps/MyApp/gradlew.

Regolare le attività gradle

Modificare il valore delle attività per la variante di compilazione preferita, ad esempio assembleDebug o assembleRelease. Per altre informazioni, vedere la documentazione di sviluppo di Google Android seguente:

Firmare e allineare un pacchetto Android (APK)

Se la compilazione non firma e comprime il file APK, aggiungere l'attività Di firma Android a YAML. Un APK deve essere firmato per l'esecuzione in un dispositivo anziché in un emulatore. Zipaligning riduce la RAM utilizzata dall'applicazione.

Importante

È consigliabile archiviare ognuna delle password seguenti in una variabile privata.

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

  Test

Testare l'emulatore Android

Creare l'attività Bash e copiare il codice seguente per installare ed eseguire l'emulatore. Non dimenticare di disporre i parametri dell'emulatore per adattarsi all'ambiente di test. L'emulatore viene avviato come processo in background ed è disponibile nelle attività successive.

#!/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"

Testare nei dispositivi ospitati in Azure

Aggiungere l'attività Test di App Center per testare l'applicazione in un lab ospitato di dispositivi iOS e Android. È necessaria una versione di valutazione gratuita di App Center , che deve essere convertita in un secondo momento a pagamento.

Iscriversi prima con 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.

Mantenere gli artefatti con il record di compilazione

Aggiungere le attività Copia file e Pubblica artefatti di compilazione . L'APK viene archiviato con il record di compilazione o il test e viene distribuito nelle pipeline successive. Per altre informazioni, vedere Artefatti.

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

Distribuzione

Aggiungere App Center

Aggiungere l'attività Distribuzione di App Center per distribuire un'applicazione a un gruppo di tester o utenti beta oppure alzare di livello l'applicazione a Intune o Google Play. È necessario un account App Center gratuito (non è necessario alcun pagamento).

# 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.

Installare Google Play

Installare l'estensione Google Play e usare le attività seguenti per automatizzare l'interazione con Google Play. Per impostazione predefinita, queste attività eseguono l'autenticazione a Google Play usando una connessione al servizio configurata.

Versione

Aggiungere l'attività Google Play Release per rilasciare una nuova versione dell'app Android in Google Play Store.

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

Promozione

Aggiungere l'attività Promuovere Google Play per alzare di livello un aggiornamento dell'applicazione Android rilasciato in precedenza da una traccia a un'altra, ad esempio alphabeta.

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

Aumentare l'implementazione

Aggiungere l'attività Di aumento dell'implementazione di Google Play per aumentare la percentuale di implementazione di un'applicazione rilasciata in precedenza alla rollout traccia.

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

Aggiornamento dello stato

Aggiungere l'attività Google Play Status Update per aggiornare lo stato di implementazione per l'applicazione rilasciata in precedenza alla rollout traccia.

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

Domande frequenti

D: Ricerca per categorie creare bundle di app?

R: È possibile compilare e firmare il bundle dell'app con uno script inline e un file sicuro. A tale scopo, scaricare prima di tutto l'archivio chiavi e archiviarlo come file sicuro nella libreria. Creare quindi variabili per keystore.password, key.aliase key.password in un gruppo di variabili.

Usare quindi le attività Scarica file protetti e Bash per scaricare l'archivio chiavi e compilare e firmare il bundle dell'app.

In questo file YAML scaricare un app.keystore file sicuro e usare uno script bash per generare un bundle dell'app. Usare quindi Copia file per copiare il bundle dell'app. Da qui creare e salvare un artefatto con Publish Build Artifact oppure usare l'estensione Google Play per pubblicare.

- 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'