Compilación, prueba e implementación de aplicaciones Android

Azure DevOps Services

Puede configurar canalizaciones para compilar, probar e implementar automáticamente aplicaciones Android.

Requisitos previos

Debe tener lo siguiente:

  • Una cuenta de GitHub. Si no tiene una cuenta de GitHub, cree una ahora.
  • Proyecto de Azure DevOps. Si no tiene un proyecto, cree uno ahora.

Configuración de una canalización

Realice las siguientes tareas para configurar una canalización para una aplicación Android de ejemplo.

  1. Bifurque el repositorio siguiente a la cuenta de GitHub para obtener el código de una aplicación Android sencilla.

    https://github.com/MicrosoftDocs/pipelines-android
    
  2. Inicie sesión en su organización de Azure DevOps y vaya a su proyecto.

  3. Seleccione Canalizaciones>Crear canalización o Nueva canalización.

  4. Seleccione GitHub como ubicación del código fuente.

    Screenshot showing list of repositories to select from.

    Puede que se le redirija a GitHub para iniciar sesión. Si es así, escriba sus credenciales de GitHub.

  5. Seleccione el repositorio -android que bifurcó anteriormente.

  6. Seleccione Aprobar e instalar en la pantalla siguiente.

    Azure Pipelines genera un archivo YAML para la canalización.

  7. Seleccione Run (Ejecutar).

  8. Confirme directamente en la rama principal y, luego, vuelva a elegir Ejecutar.

  9. Espere a que finalice.

Ahora ya tiene una canalización YAML que funciona (azure-pipelines.yml) en el repositorio que está lista para que la personalice.

Sugerencia

Para realizar cambios en el archivo YAML, seleccione la canalización en la página Canalizaciones y, luego, selecciona Editar para modificar el archivo azure-pipelines.yml.

Compilación con Gradle

Gradle es una herramienta de compilación común que se usa para compilar proyectos de Android. Para más información sobre las opciones, consulte la tarea 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'

Ajuste de la ruta de acceso de compilación

  • Ajuste el valor workingDirectory si el archivo gradlew no está en la raíz del repositorio. El valor del directorio debe ser similar a la raíz del repositorio, como AndroidApps/MyApp o $(system.defaultWorkingDirectory)/AndroidApps/MyApp.

  • Ajuste el valor gradleWrapperFile si el archivo gradlew no está en la raíz del repositorio. El valor de la ruta de acceso del archivo debe ser similar a la raíz del repositorio, como AndroidApps/MyApp/gradlew o $(system.defaultWorkingDirectory)/AndroidApps/MyApp/gradlew.

Ajuste de las tareas de Gradle

Ajuste el valor de las tareas de la variante de compilación que prefiera, como assembleDebug o assembleRelease. Para más información, consulte la documentación siguiente sobre el desarrollo de Google Android:

Firma y alineamiento de un paquete de Android (APK)

Si la compilación aún no firma ni aplica zipalign al APK, agregue la tarea Firma de Android al archivo YAML. Para ejecutarse en un dispositivo en lugar de un emulador, un APK debe estar firmado. Zipaligning reduce la RAM que consume la aplicación.

Importante

Se recomienda guardar cada una de estas contraseñas en una variable secreta.

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

Prueba

Prueba en Android Emulator

Cree la tarea de Bash y copie el código siguiente para instalar y ejecutar el emulador. No olvide organizar los parámetros del emulador para que se ajusten al entorno de prueba. El emulador se inicia como un proceso en segundo plano y está disponible en tareas posteriores.

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

Prueba en dispositivos hospedados en Azure

Agregue la tarea Prueba de App Center para probar la aplicación en un laboratorio hospedado de dispositivos iOS y Android. Se requiere una evaluación gratuita de App Center, la que más adelante se debe pasar a la opción de pago.

Primero, regístrese en 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.

Retención de artefactos con el registro de compilación

Agregue las tareas Copiar archivos y Publicar artefactos de compilación. El APK se almacena con el registro de compilación o la prueba y se implementa en canalizaciones posteriores. Para más información, consulte Artefactos.

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

Implementar

Incorporación de App Center

Agregue la tarea Distribuir de App Center para distribuir una aplicación a un grupo de evaluadores o usuarios beta, o bien promover la aplicación a Intune o Google Play. Se requiere una cuenta gratuita de App Center (no es necesario ningún pago).

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

Instalación de Google Play

Instale la extensión de Google Play y use las tareas siguientes para automatizar la interacción con Google Play. De manera predeterminada, estas tareas se autentican en Google Play mediante una conexión de servicio que configure.

Release

Agregue la tarea Versión de Google Play para publicar una versión de aplicación de Android nueva en Google Play Store.

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

Promoción

Agregue la tarea Promover de Google Play para promover la actualización de una aplicación Android publicada anteriormente de una pista a otra, como alphabeta.

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

Aumento del lanzamiento

Agregue la tarea Aumento del lanzamiento de Google Play para aumentar el porcentaje de lanzamiento de una aplicación que se publicó anteriormente en la pista rollout.

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

Actualización del estado

Agregue la tarea Actualización del estado de Google Play para actualizar el estado del lanzamiento de la aplicación que se publicó anteriormente en la pista rollout.

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

Preguntas más frecuentes

P: ¿Cómo puedo crear lotes de aplicaciones?

R: Puede compilar y firmar el lote de aplicaciones con un script alineado y un archivo seguro. Para hacerlo, descargue primero el almacén de claves y almacénelo como un archivo seguro en la biblioteca. A continuación, cree variables para keystore.password, key.alias y key.password en un grupo de variables.

A continuación, use las tareas Descargar archivo seguro y Bash para descargar el almacén de claves y compilar y firmar el lote de aplicaciones.

En este archivo YAML, descargue un archivo seguro app.keystore y use un script de Bash para generar un lote de aplicaciones. A continuación, use Copiar archivos para copiar el lote de aplicaciones. Ahí, cree y guarde un artefacto con Publicar artefacto de compilación o use la extensión de Google Play para publicarlo.

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