<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Carlos Gabriel Goiani Flor</title>
    <description>The latest articles on DEV Community by Carlos Gabriel Goiani Flor (@carlosgit2016).</description>
    <link>https://dev.to/carlosgit2016</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F284594%2Ff4d756f1-1af6-4364-9e39-c5490f812545.jpeg</url>
      <title>DEV Community: Carlos Gabriel Goiani Flor</title>
      <link>https://dev.to/carlosgit2016</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/carlosgit2016"/>
    <language>en</language>
    <item>
      <title>Creating, building and deploying an ionic application using Azure DevOps and App Center</title>
      <dc:creator>Carlos Gabriel Goiani Flor</dc:creator>
      <pubDate>Fri, 05 Jun 2020 01:34:58 +0000</pubDate>
      <link>https://dev.to/carlosgit2016/creating-building-and-deploying-an-ionic-application-using-azure-devops-and-app-center-1bhj</link>
      <guid>https://dev.to/carlosgit2016/creating-building-and-deploying-an-ionic-application-using-azure-devops-and-app-center-1bhj</guid>
      <description>&lt;p&gt;Currently there is a high market demand for the creation of mobile solutions to meet customer needs, and for that frameworks and tools like Ionic, React Native and Flutter provide good solutions and facilities to build and deploy our Apps adding store facilities like Play Store and App Store (not so easy) which offers us good platforms and APIs to make the job of deploying, testing and monitoring easier. However if you are working or managing large teams and your App does a lot of builds and deploys, using only these approaches may not be efficient and quite problematic. With this in mind my goal in this article is to demonstrate the complete creation of CI/CD pipelines to test, build and deploy an Ionic hybrid application using Azure Pipelines, Github and Visual Studio App Center that can distribute the apk to Play Store.&lt;/p&gt;

&lt;h2&gt;
  
  
  Preparation and required setup
&lt;/h2&gt;

&lt;p&gt;For the steps that will be shown here, you need the following prerequisite:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: I'm using a docker image created by beevelop and you can be found &lt;a href="https://hub.docker.com/r/beevelop/ionic/dockerfile" rel="noopener noreferrer"&gt;here&lt;/a&gt;, this will simplify our setup because the image already contains the essencial tools like nodejs, android build tools, cordova, gradle etc..., but isn't necessary in this case if you don't want to.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Tools
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;The latest version of &lt;a href="https://nodejs.org/en/" rel="noopener noreferrer"&gt;node&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Ionic CLI, you can install running &lt;code&gt;# npm install -g @ionic/cli&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Cordova to build the application for the android platform (generating the apk), you can install with this command &lt;code&gt;# npm install -g cordova&lt;/code&gt; &lt;/li&gt;
&lt;li&gt;Android Studio, which can be downloaded &lt;a href="https://developer.android.com/studio?hl=pt-br#downloads" rel="noopener noreferrer"&gt;here&lt;/a&gt; &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you don't want to install the full android studio, you can just download the &lt;em&gt;Command line tools&lt;/em&gt; which can be found on the same Android Studio Download page, and configure in the PATH, see the example.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Gradle, which can be installed following these &lt;a href="https://gradle.org/install/" rel="noopener noreferrer"&gt;steps&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This tool need jdk or jre installed as well, all the necessary information is present in the official documentation, i really recommend that you use a docker image that can be found &lt;a href="https://hub.docker.com/_/gradle" rel="noopener noreferrer"&gt;here&lt;/a&gt;. On the other hand you need configure in PATH, see the &lt;a href="https://docs.gradle.org/current/userguide/installation.html#step_3_configure_your_system_environment" rel="noopener noreferrer"&gt;example&lt;/a&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An &lt;strong&gt;&lt;em&gt;text editor&lt;/em&gt;&lt;/strong&gt; i used &lt;strong&gt;&lt;em&gt;Visual Studio Code&lt;/em&gt;&lt;/strong&gt; , which can be downloaded &lt;a href="https://code.visualstudio.com/" rel="noopener noreferrer"&gt;here&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: These tools like Cordova, Android Studio, Android Sdk Tools and gradle are optional to making local tests, basically all of these tools are available on Hosted Microsoft agents that we are going to use.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Accounts
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Github account to maintain our repo, you can create &lt;a href="https://github.com/" rel="noopener noreferrer"&gt;here&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;An Azure DevOps account and an &lt;strong&gt;&lt;em&gt;organization&lt;/em&gt;&lt;/strong&gt; created, more information can be found &lt;a href="https://azure.microsoft.com/pt-br/services/devops/" rel="noopener noreferrer"&gt;here&lt;/a&gt;
&amp;gt; Note: it is also possible use github account to make login on Azure DevOps.&lt;/li&gt;
&lt;li&gt;Visual Studio App Center account to deploy the App and enable distribution to Play Store, you can create &lt;a href="https://visualstudio.microsoft.com/app-center/" rel="noopener noreferrer"&gt;here&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Creating an ionic project
&lt;/h2&gt;

&lt;p&gt;First let's create the App using &lt;code&gt;ionic cli&lt;/code&gt; to start a simple app with Tabs, so execute &lt;code&gt;ionic start SampleApp tabs --type=ionic-angular --cordova&lt;/code&gt;, this makes it explicit that we want to use &lt;a href="https://angular.io/" rel="noopener noreferrer"&gt;&lt;em&gt;Angular&lt;/em&gt;&lt;/a&gt; and &lt;a href="https://cordova.apache.org/" rel="noopener noreferrer"&gt;&lt;em&gt;cordova&lt;/em&gt;&lt;/a&gt;, after that you can navigate to the app folder using &lt;code&gt;cd SampleApp&lt;/code&gt;, the structure should look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FQpS8QgN%2Fbuild-and-deploy-ionic-app-using-azure-pipelines-ls-sample-app.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FQpS8QgN%2Fbuild-and-deploy-ionic-app-using-azure-pipelines-ls-sample-app.png" alt="Sample App Struct"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At this moment the App was successfully created, now the next step is to test the App locally in the browser to see what the initial structure looks like to do this run &lt;code&gt;ionic serve&lt;/code&gt; this command automatically open the App (simulated) in the browser, it is also possible to choose the port, browser and other options see more running &lt;code&gt;ionic serve --help&lt;/code&gt;. After these steps you can change the App as you wish to differentiate from the template created automatically by ionic.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: It is also possible to use a docker container to create the initial structure of the App (e.g. &lt;code&gt;docker run -it --rm -v $($PWD):/usr/app beevelop/ionic:latest ionic start SampleApp tabs --type=ionic-angular --cordova&lt;/code&gt;) note that in this case the variable $PWD is used, this variable contains the name of current working directory.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Finally you can modify the App as you wish, to do this use Visual Studio Code or any text editor of your choice.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a repository on github and pushing the App code
&lt;/h2&gt;

&lt;p&gt;To create a repo to the App on &lt;a href="https://github.com/" rel="noopener noreferrer"&gt;Github&lt;/a&gt;, first log into your account and select &lt;strong&gt;&lt;em&gt;New repository&lt;/em&gt;&lt;/strong&gt; , fill in the fields then choose the one of these two options: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;em&gt;Public&lt;/em&gt;&lt;/strong&gt; (Anyone can see this repository. You choose who can commit)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;em&gt;Private&lt;/em&gt;&lt;/strong&gt; (You choose who can see and commit to this repository)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Keep the &lt;strong&gt;&lt;em&gt;&lt;em&gt;Initialize this repository with a README&lt;/em&gt;&lt;/em&gt;&lt;/strong&gt; option unchecked because we're importing an existing repository, if you filled everything in correctly, the fields should look like these: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2Fvm3Js72%2Fbuild-and-deploy-ionic-app-using-azure-pipelines-create-repo-github.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2Fvm3Js72%2Fbuild-and-deploy-ionic-app-using-azure-pipelines-create-repo-github.png" alt="Create New Github Repo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Go back to the terminal and navigate to the App code and run these commands:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

git remote add origin https://github.com/&amp;lt;github_user&amp;gt;/&amp;lt;project_name&amp;gt;.git
git push -u origin master


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now you have a repo created and the code inside it, in the next steps we will talk a little bit about Azure DevOps and how to create and configure pipelines.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a project in Azure DevOps
&lt;/h2&gt;

&lt;p&gt;Azure DevOps is a powerful Service (or on-premise) that offers support to teams plan work, collaborate with code development, build, deploy, tests and create and manage many different kinds of integrations to Azure or third-party services by default, such as Jenkins, Chef, Nuget and &lt;a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/library/service-endpoints?view=azure-devops&amp;amp;tabs=yaml#common-service-connection-types" rel="noopener noreferrer"&gt;others&lt;/a&gt;. To learn more access the &lt;a href="https://docs.microsoft.com/pt-br/azure/devops/user-guide/what-is-azure-devops?view=azure-devops" rel="noopener noreferrer"&gt;official microsoft documentation&lt;/a&gt; to see all possible capabilities.&lt;/p&gt;

&lt;p&gt;To create a project on Azure DevOps, make &lt;a href="https://azure.microsoft.com/pt-br/services/devops/" rel="noopener noreferrer"&gt;log in&lt;/a&gt; with your microsoft account (or github account) and follow these steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Select &lt;strong&gt;&lt;em&gt;New project&lt;/em&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FxCGXZnB%2Fbuild-and-deploy-ionic-app-using-azure-pipelines-azuredevops-newproject.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FxCGXZnB%2Fbuild-and-deploy-ionic-app-using-azure-pipelines-azuredevops-newproject.png" alt="Azure DevOps Create Project"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Just fill in the &lt;strong&gt;&lt;em&gt;Project name field&lt;/em&gt;&lt;/strong&gt; and click on &lt;strong&gt;&lt;em&gt;New project&lt;/em&gt;&lt;/strong&gt; , you can check the project created to this article &lt;a href="https://dev.azure.com/gabrielggff25/Ionic%20App" rel="noopener noreferrer"&gt;here&lt;/a&gt;. &lt;/p&gt;

&lt;h3&gt;
  
  
  Creating build and deploy pipelines
&lt;/h3&gt;

&lt;p&gt;To manage pipelines Azure DevOps provides the Azure Pipelines that can be used to automatically build, tests and deploys supporting any language or project types, in our case we will use to create three pipelines to build, test and deploy our App.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: Don't necessarily have to be three pipelines, this separation is only logical&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Azure DevOps has a division between Build and Release Pipeline, the first one is generally used to generate one or more artifacts using the source code of the project and the second one is more common used to deploy this artifacts generated. The two next topics explain how to create two Build Pipelines and one Release Pipeline to deploy the App. &lt;/p&gt;

&lt;h4&gt;
  
  
  Build pipelines
&lt;/h4&gt;

&lt;p&gt;Then to create the first pipeline that is responsible for building (Angular part) and testing the App, follow these steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Click on &lt;strong&gt;&lt;em&gt;Pipelines&lt;/em&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FqJ0HkpJ%2Fbuild-pipelines-menu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FqJ0HkpJ%2Fbuild-pipelines-menu.png" alt="build-pipelines-menu.png"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Select &lt;strong&gt;&lt;em&gt;New pipeline&lt;/em&gt;&lt;/strong&gt; or &lt;strong&gt;&lt;em&gt;Create Pipeline&lt;/em&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;&lt;em&gt;Github&lt;/em&gt;&lt;/strong&gt; as the source code option&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;You can choose the &lt;em&gt;User the classic editor&lt;/em&gt; option if you want a GUID to help while creating the pipeline&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Select the repository created for your App &lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;At this point Azure DevOps will redirect you to the github page for you accept and install Azure Pipelines app.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Select approve and install&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If everything is ok, some templates will appear to choose one, let's start from scratch.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Select &lt;strong&gt;&lt;em&gt;Starter Pipeline&lt;/em&gt;&lt;/strong&gt;. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Finally you can see the minimum pipeline structure, delete all lines and put the following:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="c1"&gt;# Disables CI builds entirely, then commits don't trigger a build&lt;/span&gt;
&lt;span class="na"&gt;trigger&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;none&lt;/span&gt;

&lt;span class="c1"&gt;# Activates pull request trigger, so any pull request to the master trigger a build&lt;/span&gt;
&lt;span class="na"&gt;pr&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;master&lt;/span&gt;

&lt;span class="c1"&gt;# Specifies which pool (Hosted or Self-hosted) to use for this pipeline. &lt;/span&gt;
&lt;span class="c1"&gt;# In this case it is in the scope of the pipeline, but you can use it at the stage or job level&lt;/span&gt;
&lt;span class="na"&gt;pool&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;vmImage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ubuntu-latest'&lt;/span&gt;

&lt;span class="c1"&gt;# Specific variables to use, in our case it is just one and at the pipeline level &lt;/span&gt;
&lt;span class="na"&gt;variables&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;chromeDriverVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;80.0.3987.106'&lt;/span&gt;

&lt;span class="c1"&gt;# Specifies a linear sequence of operations that make up a job&lt;/span&gt;
&lt;span class="c1"&gt;# We need only one job, so we can use the simplified structure&lt;/span&gt;
&lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="c1"&gt;# Tasks are the building blocks of a pipeline&lt;/span&gt;
&lt;span class="c1"&gt;# We can choose from a catalog of tasks available by default or download from the Azure DevOps marketplace &lt;/span&gt;
&lt;span class="c1"&gt;# In this case I chose to use 6 tasks (not mandatory) to install dependencies and build the App. &lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Npm@1&lt;/span&gt; &lt;span class="c1"&gt;# Run npm install&lt;/span&gt;
    &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;npm&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;install'&lt;/span&gt;
    &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;install&lt;/span&gt;
      &lt;span class="na"&gt;workingDir&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$(System.DefaultWorkingDirectory)'&lt;/span&gt;

  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Npm@1&lt;/span&gt; &lt;span class="c1"&gt;# Run npm run build&lt;/span&gt;
    &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;npm&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;run&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;build'&lt;/span&gt;
    &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;custom&lt;/span&gt;
      &lt;span class="na"&gt;customCommand&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;run build&lt;/span&gt;

  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt; &lt;span class="c1"&gt;# Run unit tests&lt;/span&gt;
      &lt;span class="s"&gt;npx --no-install ng test --watch=false --reporters=progress,junit&lt;/span&gt;
    &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ng&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;test'&lt;/span&gt;

&lt;span class="c1"&gt;# This task download the chromedriver binary, required for e2e tests&lt;/span&gt;
&lt;span class="c1"&gt;# In this case I installed a specific version of chromedriver to avoid errors with the version of Chrome in the hosted agent microsoft, see the troubleshooting topic.&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
      &lt;span class="s"&gt;node node_modules/.bin/webdriver-manager update --versions.chrome=$(chromeDriverVersion) --gecko false --standalone false&lt;/span&gt;
    &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;changing&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;version&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;of&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;chromedriver&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;to&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;$(chromeDriverVersion)'&lt;/span&gt;


  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt; &lt;span class="c1"&gt;# Run e2e tests without update webdriver&lt;/span&gt;
      &lt;span class="s"&gt;npx --no-install ng e2e --webdriverUpdate=false&lt;/span&gt;
    &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ng&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;e2e&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;tests'&lt;/span&gt;

  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PublishTestResults@2&lt;/span&gt; &lt;span class="c1"&gt;# Publish tests results&lt;/span&gt;
    &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Publishing&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;test&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;results'&lt;/span&gt;
    &lt;span class="na"&gt;condition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;succeededOrFailed()&lt;/span&gt;
    &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;testResultsFormat&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;JUnit'&lt;/span&gt;
      &lt;span class="na"&gt;testResultsFiles&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;**/TESTS-*.xml'&lt;/span&gt;

  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;publish&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;www/'&lt;/span&gt; &lt;span class="c1"&gt;# Publish App artifact&lt;/span&gt;
    &lt;span class="na"&gt;artifact&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;www'&lt;/span&gt;
    &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Publishing&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Artifact'&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Click on &lt;strong&gt;&lt;em&gt;Save and Run&lt;/em&gt;&lt;/strong&gt; to test the pipeline&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can now rename this pipeline to &lt;strong&gt;&lt;em&gt;App Build CI&lt;/em&gt;&lt;/strong&gt; by clicking &lt;strong&gt;&lt;em&gt;Edit&lt;/em&gt;&lt;/strong&gt; → &lt;strong&gt;&lt;em&gt;Three dots&lt;/em&gt;&lt;/strong&gt; → &lt;strong&gt;&lt;em&gt;Triggers&lt;/em&gt;&lt;/strong&gt; → &lt;strong&gt;&lt;em&gt;YAML&lt;/em&gt;&lt;/strong&gt; and editing the &lt;strong&gt;&lt;em&gt;Name&lt;/em&gt;&lt;/strong&gt; field.   &lt;/p&gt;

&lt;p&gt;This build specification is responsible to install, build and test the App, this pipeline generates the &lt;code&gt;www&lt;/code&gt; artifact whenever it is successfully executed, you can see a example of the artifact generated &lt;a href="https://dev.azure.com/gabrielggff25/Ionic%20App/_build/results?buildId=569&amp;amp;view=artifacts&amp;amp;type=publishedArtifacts" rel="noopener noreferrer"&gt;here&lt;/a&gt;, this artifact includes assets, styles and scripts that have been compiled and will be used to build the .apk file in the next step.&lt;/p&gt;

&lt;p&gt;Finally, to generate the .apk file, it is necessary to create another pipeline with the name &lt;strong&gt;&lt;em&gt;Android App CI&lt;/em&gt;&lt;/strong&gt;, and put the following content:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="c1"&gt;# Enable CI builds, trigger a build whenever the master branch receive new modifications &lt;/span&gt;
&lt;span class="na"&gt;trigger&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;master'&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="na"&gt;pr&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;none&lt;/span&gt; &lt;span class="c1"&gt;# Disable PR builds entirely&lt;/span&gt;

&lt;span class="na"&gt;pool&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;vmImage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ubuntu-latest'&lt;/span&gt;

&lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="c1"&gt;# This task trigger a new build to run, this build is the same as the step above that generates the bundle&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TriggerBuild@3&lt;/span&gt;
  &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;trigger&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;App&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Build&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;CI'&lt;/span&gt;
  &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;definitionIsInCurrentTeamProject&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;buildDefinition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;App&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Build&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;CI'&lt;/span&gt;
    &lt;span class="na"&gt;queueBuildForUserThatTriggeredBuild&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;ignoreSslCertificateErrors&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;useSameSourceVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
    &lt;span class="na"&gt;useCustomSourceVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
    &lt;span class="na"&gt;useSameBranch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;waitForQueuedBuildsToFinish&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;waitForQueuedBuildsToFinishRefreshTime&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;10'&lt;/span&gt;
    &lt;span class="na"&gt;failTaskIfBuildsNotSuccessful&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;cancelBuildsIfAnyFails&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
    &lt;span class="na"&gt;treatPartiallySucceededBuildAsSuccessful&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
    &lt;span class="na"&gt;downloadBuildArtifacts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
    &lt;span class="na"&gt;storeInEnvironmentVariable&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;authenticationMethod&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;OAuth&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Token'&lt;/span&gt;
    &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$(System.AccessToken)'&lt;/span&gt; &lt;span class="c1"&gt;# Necessary allow permission of Queue builds to &amp;lt;Project&amp;gt; Build Service, See the troubleshooting topic &lt;/span&gt;
    &lt;span class="na"&gt;enableBuildInQueueCondition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
    &lt;span class="na"&gt;dependentOnSuccessfulBuildCondition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
    &lt;span class="na"&gt;dependentOnFailedBuildCondition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
    &lt;span class="na"&gt;checkbuildsoncurrentbranch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
    &lt;span class="na"&gt;failTaskIfConditionsAreNotFulfilled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;

&lt;span class="c1"&gt;# Download the artifact of the build triggered above&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;DownloadPipelineArtifact@2&lt;/span&gt;
  &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;download&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;artifact&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;App&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Build&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;CI'&lt;/span&gt;
  &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;buildType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;specific'&lt;/span&gt;
    &lt;span class="na"&gt;project&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Ionic&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;App'&lt;/span&gt;
    &lt;span class="na"&gt;definition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;App&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Build&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;CI'&lt;/span&gt;
    &lt;span class="na"&gt;specificBuildWithTriggering&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;buildVersionToDownload&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;specific'&lt;/span&gt;
    &lt;span class="na"&gt;runId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$(TriggeredBuildIds)'&lt;/span&gt;
    &lt;span class="na"&gt;targetPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$(Build.BinariesDirectory)'&lt;/span&gt;

&lt;span class="c1"&gt;# Moves the www folder containing bundle to the Default Working Directory path (e.g. /agent/_work/1/s)&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;bash&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
      &lt;span class="s"&gt;mv $(Build.BinariesDirectory)/www $(System.DefaultWorkingDirectory)&lt;/span&gt;
  &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;mv&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;$(Build.BinariesDirectory)/www&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;$(System.DefaultWorkingDirectory)'&lt;/span&gt;

&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;bash&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt; &lt;span class="c1"&gt;# Installing cordova&lt;/span&gt;
    &lt;span class="s"&gt;sudo npm i -g cordova&lt;/span&gt;
  &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;npm&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;i&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-g&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;cordova@latest'&lt;/span&gt;

&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;bash&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt; &lt;span class="c1"&gt;# Build android App using cordova&lt;/span&gt;
    &lt;span class="s"&gt;npx ionic cordova build android --no-build --release&lt;/span&gt;
  &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ionic&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;cordova&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;build&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;android&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;--no-build&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;--release'&lt;/span&gt;

&lt;span class="c1"&gt;# Needed to solve missing dependency problem, see the troubleshooting topic&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;bash&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
    &lt;span class="s"&gt;sudo apt-get install lib32z1&lt;/span&gt;
  &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;sudo&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;apt-get&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;install&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;lib32z1'&lt;/span&gt;

&lt;span class="c1"&gt;# Signin the .apk file with the specified keystore&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AndroidSigning@3&lt;/span&gt;
  &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;android&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;signing'&lt;/span&gt;
  &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;apkFiles&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;**/outputs/apk/release/app*.apk'&lt;/span&gt;
    &lt;span class="na"&gt;apksignerKeystoreFile&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;sampleapp.keystore'&lt;/span&gt;
&lt;span class="c1"&gt;# This password is placed in Variables inside the pipeline and the option to keep the value secret is checked.&lt;/span&gt;
    &lt;span class="na"&gt;apksignerKeystorePassword&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$(password_keystore)'&lt;/span&gt;
    &lt;span class="na"&gt;apksignerKeystoreAlias&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;sampleapp'&lt;/span&gt;

&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;CopyFiles@2&lt;/span&gt; &lt;span class="c1"&gt;# Copies all .apk files to publish&lt;/span&gt;
  &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;copy&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;**/outputs/apk/release/app*.apk&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;to&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;$(Build.BinariesDirectory)'&lt;/span&gt;
  &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;SourceFolder&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$(System.DefaultWorkingDirectory)'&lt;/span&gt;
    &lt;span class="na"&gt;Contents&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;**/outputs/apk/release/app*.apk'&lt;/span&gt;
    &lt;span class="na"&gt;CleanTargetFolder&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;TargetFolder&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$(Build.BinariesDirectory)'&lt;/span&gt;
    &lt;span class="na"&gt;flattenFolders&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;


&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;publish&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$(Build.BinariesDirectory)'&lt;/span&gt; &lt;span class="c1"&gt;# Publish artifact&lt;/span&gt;
  &lt;span class="na"&gt;artifact&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;android-app'&lt;/span&gt;
  &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;publish&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;artifact'&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Before running this pipeline it is necessary to generate the keystore file on your local machine using the following command that comes with the JDK:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

$ keytool -genkey -v -keystore sampleapp.keystore -alias sampleapp -keyalg RSA -keysize 2048 -validity 10000


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Then put in &lt;strong&gt;&lt;em&gt;Library&lt;/em&gt;&lt;/strong&gt; → &lt;strong&gt;&lt;em&gt;Secure File&lt;/em&gt;&lt;/strong&gt; which can be found in the &lt;strong&gt;&lt;em&gt;Pipelines&lt;/em&gt;&lt;/strong&gt; menu. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2F0jrYZPT%2Fpipelines-menu-library.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2F0jrYZPT%2Fpipelines-menu-library.png" alt="pipelines-menu-library"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FqNwk52Z%2Flibrary-secure-files-option.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FqNwk52Z%2Flibrary-secure-files-option.png" alt="library-secure-files-option"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now you can run and see the result, whenever you run the &lt;strong&gt;&lt;em&gt;Android App CI&lt;/em&gt;&lt;/strong&gt; pipeline, another &lt;strong&gt;&lt;em&gt;App Build CI&lt;/em&gt;&lt;/strong&gt; will triggered and the generated artifact will be downloaded to generate the &lt;code&gt;.apk&lt;/code&gt; file. You can find more information about yaml structure in the &lt;a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=azure-devops&amp;amp;tabs=schema%2Cparameter-schema#pr-trigger" rel="noopener noreferrer"&gt;official Microsoft YAML reference.&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Release pipeline
&lt;/h4&gt;

&lt;p&gt;The last pipeline is responsible for deploying the App to the &lt;strong&gt;&lt;em&gt;Visual Studio App Center&lt;/em&gt;&lt;/strong&gt;, So to do that you need to first create an app in the App Center and then a new release pipeline in Azure DevOps.&lt;/p&gt;

&lt;h5&gt;
  
  
  Creating an App in Visual Studio App Center
&lt;/h5&gt;

&lt;p&gt;Access your account at the App Center and click on  &lt;strong&gt;&lt;em&gt;Add new&lt;/em&gt;&lt;/strong&gt; →  &lt;strong&gt;&lt;em&gt;Add new app&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2F27d8VDC%2Fapp-center-add-new-app.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2F27d8VDC%2Fapp-center-add-new-app.png" alt="app_center_add_new_app"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Make sure you are checking the following options:

&lt;ul&gt;
&lt;li&gt;Release Type &lt;strong&gt;&lt;em&gt;Alpha&lt;/em&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;OS &lt;strong&gt;&lt;em&gt;Android&lt;/em&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Platform &lt;strong&gt;&lt;em&gt;Java/Kotlin&lt;/em&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2F98rVp1F%2Fapp-center-new-app-fields.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2F98rVp1F%2Fapp-center-new-app-fields.png" alt="app-center-new-app-fields"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;After that you need your App Center API key. To get it navigate to your &lt;strong&gt;&lt;em&gt;Account Settings&lt;/em&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FMgtj3LY%2Fapp-center-account-settings.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FMgtj3LY%2Fapp-center-account-settings.png" alt="app-center-account-settings"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Edit &lt;strong&gt;&lt;em&gt;User API Tokens&lt;/em&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;&lt;em&gt;New API Token&lt;/em&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Make sure you are selecting the &lt;strong&gt;&lt;em&gt;Full Access&lt;/em&gt;&lt;/strong&gt; option&lt;/li&gt;
&lt;li&gt;Copy and save the generated API token &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You'll need to use this API token to configure the automatic deployment of the App.&lt;/p&gt;

&lt;h5&gt;
  
  
  Creating a Release pipeline
&lt;/h5&gt;

&lt;p&gt;Log in to Azure DevOps and navigate to &lt;strong&gt;&lt;em&gt;Pipelines&lt;/em&gt;&lt;/strong&gt;  → &lt;strong&gt;&lt;em&gt;Releases&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Select &lt;strong&gt;&lt;em&gt;New&lt;/em&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;&lt;em&gt;New release pipeline&lt;/em&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FZYBLHcc%2Frelease-pipeline-new-release-pipeline.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FZYBLHcc%2Frelease-pipeline-new-release-pipeline.png" alt="release-pipeline-new-release-pipeline"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The pipeline configuration should appear to add stages and artifacts.&lt;/p&gt;

&lt;p&gt;First you need to add an artifact to the pipeline, click &lt;strong&gt;&lt;em&gt;Add an artifact&lt;/em&gt;&lt;/strong&gt; and select &lt;strong&gt;&lt;em&gt;Android App CI&lt;/em&gt;&lt;/strong&gt; as &lt;em&gt;Source (build pipeline)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2F9W8JBGM%2Frelease-pipeline-add-an-artifact.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2F9W8JBGM%2Frelease-pipeline-add-an-artifact.png" alt="release_pipeline_add_an_artifact"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Add a new stage by clicking on &lt;strong&gt;&lt;em&gt;Add a stage&lt;/em&gt;&lt;/strong&gt; box and select &lt;strong&gt;&lt;em&gt;Empty Job&lt;/em&gt;&lt;/strong&gt; because it is not necessary to use any templates, next change the stage name to &lt;em&gt;Deploy Alpha&lt;/em&gt; for example, now it is necessary to add the deploy task for this click on &lt;strong&gt;&lt;em&gt;Tasks&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FkJ6DM1b%2Frelease-pipeline-tasks.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FkJ6DM1b%2Frelease-pipeline-tasks.png" alt="release-pipeline-tasks"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Click the plus icon to add a new task&lt;/li&gt;
&lt;li&gt;Search for &lt;strong&gt;&lt;em&gt;Visual Studio App Center&lt;/em&gt;&lt;/strong&gt; in the task catalog&lt;/li&gt;
&lt;li&gt;Add the &lt;strong&gt;&lt;em&gt;App Center distribute&lt;/em&gt;&lt;/strong&gt; task to the job&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FJxy3cPC%2Frelease-pipeline-new-task-visual-studio.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FJxy3cPC%2Frelease-pipeline-new-task-visual-studio.png" alt="release-pipeline-new-task-visual-studio"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FpzPwY2H%2Frelease-pipeline-new-task-visual-studio-fields.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FpzPwY2H%2Frelease-pipeline-new-task-visual-studio-fields.png" alt="release_pipeline_new_task_visual_studio_fields"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After that for everything to work well you must fill in the fields of the task, below i'll explain how to fill each of them.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;App Center service connection&lt;/em&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2F7b1CCs8%2Ftask-visual-studio-app-center.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2F7b1CCs8%2Ftask-visual-studio-app-center.png" alt="task-visual-studio-app-center"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Select the service connection to Visual Studio App Center, in this case you need to create one first by following these steps: Enter &lt;strong&gt;&lt;em&gt;Manage&lt;/em&gt;&lt;/strong&gt;, select &lt;strong&gt;&lt;em&gt;New service connection&lt;/em&gt;&lt;/strong&gt; → &lt;strong&gt;&lt;em&gt;Visual Studio App Center&lt;/em&gt;&lt;/strong&gt; → &lt;strong&gt;&lt;em&gt;Next&lt;/em&gt;&lt;/strong&gt; and fill in the &lt;em&gt;API Token&lt;/em&gt; with the token generated in Visual Studio App Center, Lastly give a name to connection and go back to the task and select the created connection.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;App slug&lt;/em&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2F6nZ4stc%2Ftask-visual-studio-app-center-field-app-slug.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2F6nZ4stc%2Ftask-visual-studio-app-center-field-app-slug.png" alt="task-visual-studio-app-center-field-app-slug"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To find the slug app go to Visual Studio App Center and click on the App and extract from the &lt;em&gt;URL&lt;/em&gt; (e.g. &lt;code&gt;https://appcenter.ms/users/carlosggflor-gmail.com/apps/SampleApp&lt;/code&gt; → &lt;code&gt;carlosggflor-gmail.com/SampleApp&lt;/code&gt;)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;Binary file path&lt;/em&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2F0qSWDyy%2Ftask-visual-studio-app-center-field-binary-file-path.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2F0qSWDyy%2Ftask-visual-studio-app-center-field-binary-file-path.png" alt="task-visual-studio-app-center-field-binary-file-path"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Relative path from the repo root to the APK/AAB or IPA file you want to publish, in this case you need to select the artifact (.apk file) path generated by running &lt;strong&gt;&lt;em&gt;Android App CI&lt;/em&gt;&lt;/strong&gt; build (e.g. &lt;code&gt;$(System.DefaultWorkingDirectory)/_Android App CI/android-app/app-release-unsigned.apk&lt;/code&gt;).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;Release notes&lt;/em&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2F3mWFsyQ%2Ftask-visual-studio-app-center-field-create-release-notes.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2F3mWFsyQ%2Ftask-visual-studio-app-center-field-create-release-notes.png" alt="task-visual-studio-app-center-field-create-release-notes"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Release notes will be attached to the release and shown to testers on the installation page.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;Release destination&lt;/em&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FgFy2Zh4%2Ftask-visual-studio-app-center-field-release-destination.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FgFy2Zh4%2Ftask-visual-studio-app-center-field-release-destination.png" alt="task-visual-studio-app-center-field-release-destination"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This field is very important because it is where you decide the destination that the release will be distributed, in the case if &lt;strong&gt;&lt;em&gt;Groups&lt;/em&gt;&lt;/strong&gt; is selected you can deploy it to one or more groups using commas or semicolons to separate multiple IDs, you can create these groups in the Visual Studio App Center navigating to your &lt;strong&gt;&lt;em&gt;App&lt;/em&gt;&lt;/strong&gt; → &lt;strong&gt;&lt;em&gt;Distribute&lt;/em&gt;&lt;/strong&gt; → &lt;strong&gt;&lt;em&gt;Groups&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2Fz8FHP9r%2Fapp-center-distribute-groups.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2Fz8FHP9r%2Fapp-center-distribute-groups.png" alt="app-center-distribute-groups"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To get the ID, just select the group created and click on the &lt;strong&gt;&lt;em&gt;settings icon&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FFs7TzVP%2Fapp-center-distribute-groups-settings.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FFs7TzVP%2Fapp-center-distribute-groups-settings.png" alt="app-center-distribute-groups-settings"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FsKCJJbC%2Fapp-center-distribute-groups-settings-id.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FsKCJJbC%2Fapp-center-distribute-groups-settings-id.png" alt="app-center-distribute-groups-settings-id"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In case of you leave the Destination ID field empty, then the default group (&lt;em&gt;Collaborators&lt;/em&gt;) is chosen.&lt;/p&gt;

&lt;p&gt;Otherwise, if you select &lt;strong&gt;&lt;em&gt;Store&lt;/em&gt;&lt;/strong&gt; you need to enter the ID of distribution store to deploy, in our case we didn't create the store connection (e.g. Google play or Intune Company Portal), but if you want to create enter Visual Studio App Center navigating to your &lt;strong&gt;&lt;em&gt;App&lt;/em&gt;&lt;/strong&gt; → &lt;strong&gt;&lt;em&gt;Distribute&lt;/em&gt;&lt;/strong&gt; → &lt;strong&gt;&lt;em&gt;Stores&lt;/em&gt;&lt;/strong&gt; → &lt;strong&gt;&lt;em&gt;Connect to store&lt;/em&gt;&lt;/strong&gt; and follow the steps.&lt;/p&gt;

&lt;p&gt;Finally you can rename your pipeline and run clicking on &lt;strong&gt;&lt;em&gt;Create release&lt;/em&gt;&lt;/strong&gt; → &lt;strong&gt;&lt;em&gt;Create&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FRgjsM6x%2Frelease-pipeline-create-new-release.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FRgjsM6x%2Frelease-pipeline-create-new-release.png" alt="release-pipeline-create-new-release"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After the deployment as finished you can see the release in the &lt;strong&gt;&lt;em&gt;Visual Studio App Center&lt;/em&gt;&lt;/strong&gt; → &lt;strong&gt;&lt;em&gt;Distribute&lt;/em&gt;&lt;/strong&gt; → &lt;strong&gt;&lt;em&gt;Releases&lt;/em&gt;&lt;/strong&gt;, the image below mark the main information about this page.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FYt4s6x4%2Fapp-center-distribute-releases.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FYt4s6x4%2Fapp-center-distribute-releases.png" alt="app_center_distribute_releases"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;1 - The App version, you can change that version by editing the &lt;code&gt;config.xml&lt;/code&gt; file in the source code.&lt;/p&gt;

&lt;p&gt;2 - The destination chosen in the deployment task for the App Center.&lt;/p&gt;

&lt;p&gt;From here you can distribute the same release to other groups and stores (Google Play or Intune), set up testers and generate links to download the App. &lt;/p&gt;

&lt;p&gt;Lastly, you need to configure Continuous deployment in the pipeline for create a release whenever build &lt;strong&gt;&lt;em&gt;Android App CI&lt;/em&gt;&lt;/strong&gt; is finished, to do this click on &lt;strong&gt;&lt;em&gt;lightning icon&lt;/em&gt;&lt;/strong&gt; and enable the &lt;strong&gt;&lt;em&gt;Continuous deployment trigger&lt;/em&gt;&lt;/strong&gt; option. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FLRtDbr1%2Frelease-pipeline-enable-continuous-deployment.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FLRtDbr1%2Frelease-pipeline-enable-continuous-deployment.png" alt="release-pipeline-enable-continuous-deployment"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;We created an hybrid application using ionic with cordova and Azure DevOps to integrated with Github to keep the code and created CI/CD pipelines to test, build and deploy our App in the Visual Studio App Center. We can change any part related to Azure DevOps like the CI/CD tool and still use it as an intermediary. We went through a detailed explanation of each step of the build and the deployment stage. &lt;/p&gt;

&lt;h3&gt;
  
  
  Source code and pipelines
&lt;/h3&gt;

&lt;p&gt;SampleApp on Github. &lt;a href="https://github.com/carlosgit2016/SampleApp" rel="noopener noreferrer"&gt;https://github.com/carlosgit2016/SampleApp&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ionic App on Azure DevOps. &lt;a href="https://dev.azure.com/gabrielggff25/Ionic%20App" rel="noopener noreferrer"&gt;https://dev.azure.com/gabrielggff25/Ionic%20App&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Extras
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;a&gt;&lt;/a&gt; Configuring Android SDK tools in PATH
&lt;/h3&gt;

&lt;p&gt;I didn't find a simple example of this, so if you don't want to install Android Studio or are using Linux and need to configure the tools in PATH, see below&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Linux&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="c"&gt;# i downloaded the command line tools in /tmp/ and unzipped it in /opt/android/tools&lt;/span&gt;
&lt;span class="c"&gt;# use any editor to edit the /etc/profile&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;vi /etc/profile
&lt;span class="nb"&gt;cat&lt;/span&gt; /etc/profile 
&lt;span class="c"&gt;# put the PATH variable at the end of the file&lt;/span&gt;
&lt;span class="c"&gt;# should look like this&lt;/span&gt;

&lt;span class="c"&gt;# /etc/profile: system-wide .profile file for the Bourne shell (sh(1))&lt;/span&gt;
&lt;span class="c"&gt;# and Bourne compatible shells (bash(1), ksh(1), ash(1), ...).&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PS1&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BASH&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$BASH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="s2"&gt;"/bin/sh"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
    &lt;span class="c"&gt;# The file bash.bashrc already sets the default PS1.&lt;/span&gt;
    &lt;span class="c"&gt;# PS1='\h:\w\$ '&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; /etc/bash.bashrc &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
      &lt;span class="nb"&gt;.&lt;/span&gt; /etc/bash.bashrc
    &lt;span class="k"&gt;fi
  else
    if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt; &lt;span class="nt"&gt;-u&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-eq&lt;/span&gt; 0 &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
      &lt;/span&gt;&lt;span class="nv"&gt;PS1&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'# '&lt;/span&gt;
    &lt;span class="k"&gt;else
      &lt;/span&gt;&lt;span class="nv"&gt;PS1&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'$ '&lt;/span&gt;
    &lt;span class="k"&gt;fi
  fi
fi

if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; /etc/profile.d &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  for &lt;/span&gt;i &lt;span class="k"&gt;in&lt;/span&gt; /etc/profile.d/&lt;span class="k"&gt;*&lt;/span&gt;.sh&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
    if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="nv"&gt;$i&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
      &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$i&lt;/span&gt;
    &lt;span class="k"&gt;fi
  done
  &lt;/span&gt;&lt;span class="nb"&gt;unset &lt;/span&gt;i
&lt;span class="k"&gt;fi

&lt;/span&gt;&lt;span class="nv"&gt;PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$PATH&lt;/span&gt;:/opt/android/tools/bin


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Windows&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Open control panel&lt;/li&gt;
&lt;li&gt;Look for &lt;strong&gt;&lt;em&gt;Edit the system environment variables&lt;/em&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;&lt;em&gt;Environment Variables&lt;/em&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Two click on Path in &lt;strong&gt;&lt;em&gt;System Variables&lt;/em&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Click New and put the path where you unzip the file (e.g. &lt;code&gt;C:\Temp\tools\bin&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Troubleshooting
&lt;/h2&gt;

&lt;h5&gt;
  
  
  Without permission to trigger another build in the Android App CI pipeline.
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Error:&lt;br&gt;
&lt;code&gt;Error message: Error: TF215106: Access denied. Ionic App Build Service (gabrielggff25) needs Queue builds permissions for build pipeline 20:App Build CI in team project Ionic App to perform the action. For more information, contact the Azure DevOps administrator.&lt;br&gt;
&lt;/code&gt; &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Solution:&lt;br&gt;
Allow Queue builds permission to user &lt;strong&gt;&lt;em&gt;&lt;em&gt;Project&lt;/em&gt; Build Service&lt;/em&gt;&lt;/strong&gt;, see the image below.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FzGbw76G%2Fbuild-pipelines-permissions-queue-builds.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FzGbw76G%2Fbuild-pipelines-permissions-queue-builds.png" alt="build-pipelines-permissions-queue-builds"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h5&gt;
  
  
  Problem with dependency missing during the execution of pipeline Android App CI build
&lt;/h5&gt;

&lt;p&gt;The problem occurs during the build of the App for android, see &lt;a href="https://www.softprayog.in/troubleshooting/error-while-loading-shared-libraries-libz-so-1" rel="noopener noreferrer"&gt;Error while loading shared libraries&lt;/a&gt;&lt;/p&gt;

&lt;h5&gt;
  
  
  Problem with chromedriver version on agent
&lt;/h5&gt;

&lt;p&gt;Maybe the current version of chromedriver is new to Google Chrome installed on the agent, see &lt;a href="https://github.com/actions/virtual-environments/blob/master/images/linux/Ubuntu1804-README.md" rel="noopener noreferrer"&gt;installed softwares on ubuntu machines&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://docs.microsoft.com/en-us/appcenter/distribution/vsts-deploy" rel="noopener noreferrer"&gt;Deploy Azure DevOps Builds with App Center&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ionicframework.com/getting-started" rel="noopener noreferrer"&gt;Ionic Framework Getting Started&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.microsoft.com/pt-br/azure/devops/?view=azure-devops&amp;amp;viewFallbackFrom=vsts" rel="noopener noreferrer"&gt;Azure DevOps Official Documentation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=azure-devops&amp;amp;tabs=schema%2Cparameter-schema" rel="noopener noreferrer"&gt;YAML Schema Reference&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ionic</category>
      <category>azuredevops</category>
      <category>visualstudioappcenter</category>
      <category>cicd</category>
    </item>
  </channel>
</rss>
