This is specifically for Android. I have a flutter application that goes through DevOps pipelines to build an apk and then publish it to App Center for internal use. I’ve been having issues getting an effortless update process on my apk when downloading a new one through app center and selecting update. Every time I get the message "App not installed as package conflicts with an existing package".
I know about the solution to just uninstall your old app and then install the new one, but is there not any other way for me to just get my update in a working condition? Is there any potential places where my packages would conflict that I can just match to get an effortless update process?
I tried looking everywhere in my project and pipelines for any identifiers or processes that might make it seem like it is a different package with the same name with the help of forums such as:
- The Android namespace
- The keystore that I sign my app with in the pipelines
But the namespace stayed the same between the two versions and my keystore definitely did not change since it is stored in a secure file on DevOps and that has not been touched at all.
There are some things however that did change that could be considered major that I do not know if it would consider it a different package altogether such as:
- Updating my flutter, gradle, and all other packages to the latest version
- Adding flavors
- The majority of the image assets were replaced
- My apk name changed from app-release.apk to app-prod-release.apk due to flavors
- And updating the pipelines with new tasks and a new way of building my apk with flavors and config files as seen below:
Old pipeline:
trigger:
branches:
include:
- dev
- main
- release/*
stages:
- stage: AndroidStage
pool:
vmImage: 'ubuntu-latest'
dependsOn: []
displayName: Android
jobs:
- job: AndroidJob
displayName: Android
steps:
- task: FlutterInstall@0
displayName: "Install Flutter SDK"
inputs:
mode: 'auto'
channel: 'stable'
version: 'latest'
- task: FlutterCommand@0
displayName: "Run Flutter diagnostics"
inputs:
projectDirectory: '.'
arguments: 'doctor -v'
- task: FlutterBuild@0
displayName: "Build application"
inputs:
target: 'apk'
projectDirectory: '$(Build.SourcesDirectory)'
- task: AndroidSigning@3
displayName: 'Signing and aligning APK file(s) **/*.apk'
inputs:
apkFiles: '**/*.apk'
apksign: true
apksignerKeystoreFile: pinnies-v2-release.keystore
apksignerKeystorePassword: $(keystorePass)
apksignerKeystoreAlias: $(keystoreAlias)
apksignerKeyPassword: $(keystorePass)
- task: CopyFiles@2
inputs:
contents: '**/*.apk'
targetFolder: '$(build.artifactStagingDirectory)'
OverWrite: true
- task: PublishBuildArtifacts@1
condition: ne(variables['Build.Reason'], 'PullRequest')
inputs:
artifactName: 'drop'
- script: |
version=$(grep "version:" pubspec.yaml | awk '{print $2}' | cut -d'+' -f1)
echo "##vso[task.setvariable variable=AppVersion]$version"
displayName: 'Extract App Version'
- script: |
if [ "$(Build.SourceBranch)" == "refs/heads/main" ]; then
echo '$url = "$(teamsUrl)"' > $(Build.ArtifactStagingDirectory)/send_teams.ps1
else
echo '$url = "$(teamsGradUrl)"' > $(Build.ArtifactStagingDirectory)/send_teams.ps1
fi
echo '$jsonPayload = @{' >> $(Build.ArtifactStagingDirectory)/send_teams.ps1
echo ' "version" = "$(AppVersion)"' >> $(Build.ArtifactStagingDirectory)/send_teams.ps1
if [ "$(Build.SourceBranch)" == "refs/heads/main" ]; then
echo ' "url" = "https://install.appcenter.ms/orgs/agilebridge/apps/pinnies-android/distribution_groups/public"' >> $(Build.ArtifactStagingDirectory)/send_teams.ps1
else
echo ' "url" = "https://install.appcenter.ms/orgs/AgileBridge/apps/Pinnies-Test-Android/releases/latest"' >> $(Build.ArtifactStagingDirectory)/send_teams.ps1
fi
echo '}' >> $(Build.ArtifactStagingDirectory)/send_teams.ps1
echo '$jsonBody = $jsonPayload | ConvertTo-Json' >> $(Build.ArtifactStagingDirectory)/send_teams.ps1
echo '$headers = @{ "Content-Type" = "application/json" }' >> $(Build.ArtifactStagingDirectory)/send_teams.ps1
echo '$response = Invoke-RestMethod -Uri $url -Method Post -Body $jsonBody -Headers $headers' >> $(Build.ArtifactStagingDirectory)/send_teams.ps1
echo '$response' >> $(Build.ArtifactStagingDirectory)/send_teams.ps1
displayName: 'Generate PowerShell Script'
- publish: $(Build.ArtifactStagingDirectory)/send_teams.ps1
artifact: SendTeams
New pipeline:
trigger:
branches:
include:
- dev
- main
- release/*
stages:
- stage: AndroidStage
pool:
vmImage: 'ubuntu-latest'
dependsOn: []
displayName: Android
jobs:
- job: AndroidJob
displayName: Android
steps:
- bash: 'wget --no-check-certificate -c --header "Cookie: oraclelicense=accept-securebackup-cookie" https://download.oracle.com/java/21/latest/jdk-21_linux-x64_bin.tar.gz '
displayName: 'Bash Script'
- task: JavaToolInstaller@0
displayName: 'Use Java 21'
inputs:
versionSpec: 21
jdkArchitectureOption: x64
jdkSourceOption: LocalDirectory
jdkFile: '$(build.sourcesdirectory)/jdk-21_linux-x64_bin.tar.gz'
jdkDestinationDirectory: '$(agent.toolsDirectory)/jdk21'
- task: FlutterInstall@0
displayName: "Install Flutter SDK"
inputs:
mode: 'auto'
channel: 'stable'
version: 'latest'
- task: FlutterCommand@0
displayName: "Run Flutter diagnostics"
inputs:
projectDirectory: '.'
arguments: 'doctor -v'
- task: FlutterCommand@0
displayName: "Clean application"
inputs:
projectDirectory: '.'
flutterDirectory: '$(Build.SourcesDirectory)'
arguments: 'clean'
- script: |
if [[ "$(Build.SourceBranch)" == "refs/heads/dev" ]]; then
flavor="dev"
elif [[ "$(Build.SourceBranch)" == "refs/heads/main" ]]; then
flavor="prod"
else
flavor="uat"
fi
echo "Building with flavor: $flavor"
flutter build apk --flavor $flavor --dart-define-from-file=config/app_config_$flavor.json
displayName: "Build application with flavor"
- task: AndroidSigning@3
displayName: 'Signing and aligning APK file(s) **/*.apk'
inputs:
apkFiles: '**/*.apk'
apksign: true
apksignerKeystoreFile: pinnies-v2-release.keystore
apksignerKeystorePassword: $(keystorePass)
apksignerKeystoreAlias: $(keystoreAlias)
apksignerKeyPassword: $(keystorePass)
- task: CopyFiles@2
inputs:
contents: '**/*.apk'
targetFolder: '$(build.artifactStagingDirectory)'
OverWrite: true
- task: PublishBuildArtifacts@1
condition: ne(variables['Build.Reason'], 'PullRequest')
inputs:
artifactName: 'drop'
- script: |
version=$(grep "version:" pubspec.yaml | awk '{print $2}' | cut -d'+' -f1)
echo "##vso[task.setvariable variable=AppVersion]$version"
displayName: 'Extract App Version'
- script: |
if [ "$(Build.SourceBranch)" == "refs/heads/main" ]; then
echo '$url = "$(teamsUrl)"' > $(Build.ArtifactStagingDirectory)/send_teams.ps1
else
echo '$url = "$(teamsGradUrl)"' > $(Build.ArtifactStagingDirectory)/send_teams.ps1
fi
echo '$jsonPayload = @{' >> $(Build.ArtifactStagingDirectory)/send_teams.ps1
echo ' "version" = "$(AppVersion)"' >> $(Build.ArtifactStagingDirectory)/send_teams.ps1
if [ "$(Build.SourceBranch)" == "refs/heads/main" ]; then
echo ' "url" = "https://install.appcenter.ms/orgs/agilebridge/apps/pinnies-android/distribution_groups/public"' >> $(Build.ArtifactStagingDirectory)/send_teams.ps1
else
echo ' "url" = "https://install.appcenter.ms/orgs/AgileBridge/apps/Pinnies-Test-Android/releases/latest"' >> $(Build.ArtifactStagingDirectory)/send_teams.ps1
fi
echo '}' >> $(Build.ArtifactStagingDirectory)/send_teams.ps1
echo '$jsonBody = $jsonPayload | ConvertTo-Json' >> $(Build.ArtifactStagingDirectory)/send_teams.ps1
echo '$headers = @{ "Content-Type" = "application/json" }' >> $(Build.ArtifactStagingDirectory)/send_teams.ps1
echo '$response = Invoke-RestMethod -Uri $url -Method Post -Body $jsonBody -Headers $headers' >> $(Build.ArtifactStagingDirectory)/send_teams.ps1
echo '$response' >> $(Build.ArtifactStagingDirectory)/send_teams.ps1
displayName: 'Generate PowerShell Script'
- publish: $(Build.ArtifactStagingDirectory)/send_teams.ps1
artifact: SendTeams
I’m really at a loss here. I don’t think app center would cause this issue because that also has not changed. I’m relatively new to mobile dev so any advice that could point me in the right direction would be appreciated
2
Answers
Are you upping the version code of the app each time? Specifically, I’m referring to the versionCode in the Apps build.gradle.
As far as I know, this issue might be caused by any of the following things:
As
@John Wiese
mentioned, a same versionCode of the APK. You may need to check the versionCode and ensure it is a new one.The outdated version of Android. You can try to check for software updates and upgrade your device to the latest version of Android.
The problem with the APK file itself. Make sure that the APK file is not corrupted or incomplete, and try downloading it again from a reputable source.
The problem with the firmware on the device. If you suspect that this is the case, you can try to check the possible security settings on the device, and if required, you also can try to contact the manufacturer for further assistance.
The lack of storage space on the device. You can try to free up some space by deleting unnecessary files or moving them to an external storage device.
The problem with the Google Play Store. you can try to clear the cache and data for the Google Play Store app, and make sure that you have a stable internet connection.
The potential malware or virus on the device. You can try to run a full scan on the device using a reliable antivirus software.