App Center is a great way to distribute (alpha/beta) releases of your Windows or UWP app to (internal) testers.
Especially when you make the distribution to App Center a part of your pipelines. You commit (or trigger it manually) and *bam* moments later, your testers can test out the awesome changes you made to your app!
Some time ago, however, I struggled getting my AppxBundle to App Center. Everything would just run, no error messages of whatsoever, but in AppCenter my new build wouldn’t show up.
This is what the ‘distribute to App Center step’ in my Azure DevOps pipeline looked like:
- task: AppCenterDistribute@3 inputs: serverEndpoint: 'AppCenterConnection' appSlug: '[*redacted*]' appFile: '$(Build.ArtifactStagingDirectory)\AppxPackages\*\*.appxbundle' symbolsOption: 'UWP' releaseNotesOption: 'input' releaseNotesInput: 'New release' destinationType: 'groups' distributionGroupId: '$(appCenter.distributionGroupId)' buildVersion: '$(Build.BuildNumber)'
This would run just fine, but I wouldn’t see anything appearing in AppCenter.
After some investigation, it turned out that the problem was due to the fact that the version number in my app manifest didn’t match the version number I passed in as ‘buildVersion’ parameter when pushing the appxbundle to App Center.
So the fix is simple: leave out the ‘buildVersion’ parameter. On the other hand, it’s a bit of a ‘smell’ as well… Shouldn’t your manifest have the same version as your build? I would suggest to include an extra step in you pipeline to update your app manifest so the version matches your buildnumber. This can be very valuable in terms of tracebility!
Leave the buildVersion parameter out
When uploading an appxbundle, we can leave the buildVersion parameter out. AppCenter will automatically pick the version number from your app manifest:
- task: AppCenterDistribute@3 inputs: serverEndpoint: 'AppCenterConnection' appSlug: '[*redacted*]' appFile: '$(Build.ArtifactStagingDirectory)\AppxPackages\*\*.appxbundle' symbolsOption: 'UWP' releaseNotesOption: 'input' releaseNotesInput: 'New release' destinationType: 'groups' distributionGroupId: '$(appCenter.distributionGroupId)'
Update Manifest version
As said, you should certainly think about adding an extra step to make sure the version in your app manifest matches your build number.
To do this, you can install the Manifest Versioning Build Tasks package. This package contains a task that can update your app manifest version. Once installed, you can use it like this:
- task: VersionAPPX@2 inputs: Path: '$(Build.SourcesDirectory)' VersionNumber: '$(Build.BuildNumber)' InjectVersion: False VersionRegex: '(0|[1-9][0-9]{0,3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])(\.(0|[1-9][0-9]{0,3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])){3}' OutputVersion: 'OutputedVersion'
I’ve included this step right before I trigger my MSBuild in my pipeline.
Optionally, you can now again pass in the ‘$(Build.BuildNumber)’ variable as ‘buildVersion’ parameter when sending my package to App Center. As App Center is able to retreive the version number from the Manifest, it is not needed, but you might choose to explicitly include it to safeguard your Manifest version is in sync with your build number. If they would’nt be in sync, your release won’t show up in App Center.
If you should be interested, this is what my etire pipeline looks like:
trigger: - none name: 1.1.$(date:yy)$(DayOfYear)$(rev:.r) pool: vmImage: 'windows-latest' variables: - group: UWPBuild - name: solution value: '**/*.sln' - name: buildPlatform value: 'x86|x64' - name: buildConfiguration value: 'Release' - name: appxPackageDir value: '$(build.artifactStagingDirectory)\AppxPackages\\' steps: - task: NuGetToolInstaller@1 - task: NuGetCommand@2 inputs: restoreSolution: '$(solution)' - task: DownloadSecureFile@1 name: mySecureFile displayName: 'Get the pfx file certificat' inputs: secureFile: '$(uwpSigningCert.secureFilePath)' - task: PowerShell@2 inputs: targetType: 'inline' script: | Write-Host "Start adding the PFX file to the certificate store." $pfxpath = '$(mySecureFile.secureFilePath)' $password = '$(uwpSigningCert.password)' Write-Host $password Add-Type -AssemblyName System.Security $cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2 $cert.Import($pfxpath, $password, [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]"PersistKeySet") $store = new-object system.security.cryptography.X509Certificates.X509Store -argumentlist "MY", CurrentUser $store.Open([System.Security.Cryptography.X509Certificates.OpenFlags]"ReadWrite") $store.Add($cert) $store.Close() - task: VersionAPPX@2 inputs: Path: '$(Build.SourcesDirectory)' VersionNumber: '$(Build.BuildNumber)' InjectVersion: False VersionRegex: '(0|[1-9][0-9]{0,3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])(\.(0|[1-9][0-9]{0,3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])){3}' OutputVersion: 'OutputedVersion' - task: VSBuild@1 inputs: platform: 'x86' solution: '$(solution)' configuration: '$(buildConfiguration)' msbuildArgs: '/p:AppxBundlePlatforms="$(buildPlatform)" /p:AppxPackageDir="$(appxPackageDir)" /p:AppxBundle=Always /p:UapAppxPackageBuildMode=StoreUpload /p:AppxPackageSigningEnabled=true /p:PackageCertificateThumbprint="$(uwpSigningCert.thumbprint)" /p:PackageCertificateKeyFile="$(mySecureFile.secureFilePath)" /p:PackageCertificatePassword="$(uwpSigningCert.password)"' - task: CopyFiles@2 displayName: 'Copy Files to: $(build.artifactstagingdirectory)' inputs: SourceFolder: '$(system.defaultworkingdirectory)' Contents: '**\bin\$(BuildConfiguration)\**' TargetFolder: '$(build.artifactstagingdirectory)' - task: PublishBuildArtifacts@1 displayName: 'Publish Artifact: drop' inputs: PathtoPublish: '$(build.artifactstagingdirectory)' - task: AppCenterDistribute@3 inputs: serverEndpoint: 'AppCenterConnection' appSlug: '[*Redacted*]' appFile: '$(Build.ArtifactStagingDirectory)\AppxPackages\*\*.appxbundle' symbolsOption: 'UWP' releaseNotesOption: 'input' releaseNotesInput: 'New release' destinationType: 'groups' distributionGroupId: '$(appCenter.distributionGroupId)' buildVersion: '$(Build.BuildNumber)'
September 16, 2021 at 10:50 am
Hi, I am trying this, but my build breaks once I add the VersionAPPX task.
It says “##[error]Could not find version number data in 20210916.6.”
September 19, 2021 at 4:52 pm
Hi Jonathan,
that’s unfortunate… At first glance, it seems like your version number isn’t in a format the VersionAPPX task expects it to be.
Maybe try adding this to your yaml file, right after the ‘trigger’:
name: 1.1.$(date:yy)$(DayOfYear)$(rev:.r)
September 19, 2021 at 5:24 pm
I will give that a try, thank you.