Release Android App to Huawei AppGallery via Azure Pipeline

Build and release app to Google Play Store / Apple App Store via Azure Pipeline is relative straightforward by following the template / task provided in Azure Pipeline. But there is no such template / task for app publish to Huawei AppGallery. The tutorial I found in Huawei developer forum doesn’t work correctly either. After a few try and error, I have finally found a solution. Noted that I already have a build pipeline configured to build the Android app into Android App Bundles (aab) and another release pipeline to publish the app to Google Play Store, so I’m not going to show here how to do build and sign the app, but focus on how to upload and submit the signed app to Huawei AppGallery instead.

I will not go very in depth on how Azure DevOps work. I also assume those who searching how to publish app to Huawei AppGallery via Azure pipeline should already experienced how to setup a release pipeline to publish to other store like Google Play Store. I also assume that you already publish the app to AppGallery before this.

Create API Client in AppGallery

1. Login to Huawei AppGallery Connect.
2. Go to Users and permissions.

3. Go to Connect API then click Create on the right.

4. In Create API client, give it a name (example: App Publish) and assign the Administrator role. DO NOT assign a project to this client. Leave the project as N/A else Azure pipeline will fail with 403 error. Click OK to create the API client.

5. Remember / noted the Client ID and Key. You will need them later.

Get App ID

1. In Huawei AppGallery Connect, go to My App.

2. Select the app you want to publish.
3. Go to App Information on the left.
4. Remember / noted down the App ID. You will need it later.

Create A New Release Pipeline

1. Inside Azure DevOps, go to Release Pipelines.

2. Click on the New button and select New release pipeline to create a new release pipeline.

3. We will start with an Empty job without any template.

4. Since I already have a Android build pipeline setup and running already, I’m going to use the signed app (artifact) generated from that build pipeline as the source. This can be easily done by Add an artifact, then select the correct Project and Source (build pipeline). Important to remember the Source alias which we will need it later.

Add Tasks

Next, we already going to add task to the release pipeline. Go to Tasks.

Task 1: Install Python Request

  1. Add a command line task.
  2. Display name: Install Python request
  3. Script:
cd C:\hostedtoolcache\windows\Python\3.8.1\x64\Scripts

pip install requests

Task 2: Get AppGallery Access Token

  1. Add Python script task.
  2. Display name: Get AppGallery access token
  3. Script source: Inline
  4. Script:
import requests

json_data = {"client_id":"$(client_id)","client_secret":"$(client_secret)","grant_type":"client_credentials"}

req ="",json=json_data)

res_data = req.json()

res_data = "Bearer " + res_data['access_token']

print("##vso[task.setvariable variable=access_token]"+res_data)

Task 3: Get Upload URL

  1. Add Python script task.
  2. Display name: Get upload URL
  3. Script source: Inline
  4. Script:
import requests

headers = {
    'Authorization': '$(access_token)',
    'client_id': '$(client_id)'

url = ''

data = {
response = requests.get(url,headers=headers,params=data)
res_data = response.json()
print("##vso[task.setvariable variable=authCode]"+res_data['authCode'])
print("##vso[task.setvariable variable=uploadUrl]"+res_data['uploadUrl'])

Task 4: Upload File

  1. Add Python script task.
  2. Display name: Upload file
  3. Script source: Inline
  4. Script (Important: Replace Source Alias with the source alias from release pipeline):
import requests

filePath = r'$(System.DefaultWorkingDirectory)\<Source Alias>\Build\drop\$(fileName)'

files = {'file':open(filePath,'rb')}

data = {'authCode':'$(authCode)','fileCount':1}

reponse ='$(uploadUrl)',data=data,files=files)

text = reponse.json()

file_info = text['result']['UploadFileRsp']['fileInfoList'][0]

file_size = str(file_info['size'])

print("##vso[task.setvariable variable=fileDestUrl]"+file_info['fileDestUlr'])

print("##vso[task.setvariable variable=size]"+file_size)

Task 5: Update App File Info

  1. Add Python script task.
  2. Display name: Update app file info
  3. Script source: Inline
  4. Script (Important: replace en-US to language-region of the main language supported by your app):
import requests

file_size = int($(size))

headers = {
    'Authorization': '$(access_token)',
    'client_id': '$(client_id)'

params = {

data = {'lang':'en-US','fileType':5,'files':[{'fileName':'$(fileName)','fileDestUrl':'$(fileDestUrl)','size':file_size,'imageResolution':'','imageResolutionSingature':''}]}

reponse = requests.put('',headers=headers,json=data,params=params)

text = reponse.json()

Task 6: Submit

  1. Add Python script task.
  2. Display name: Submit
  3. Script source: Inline
  4. Script:
import requests

headers = {'Authorization': '$(access_token)','client_id': '$(client_id)'}

params = {'appId': '$(appId)'}

r11 ="",params=params,headers=headers)

res_data = r11.json()

You should have a total of 6 tasks in your release pipeline by now.

Add Variables

Next, we are going to add the variable with value taken from Huawei AppGallery in order to make the pipeline work.

  • Add “appId” variable with App ID retrieved from Huawei AppGallery.
  • Add “client_id” variable with Client Id from Huawei AppGallery.
  • Add “client_secret” variable with Key from Huawei AppGallery.
  • Add “fileName” variable with file name of signed app generated from release pipeline. (Refer to your previous build pipeline run if needed. Example


Remember to click Save to save the whole setup. Click Create release to see if everything is setup correctly. If you have problem access to the API or there is any API change, you can refer to their AppGallery Connect API document.