Skip to content

Instantly share code, notes, and snippets.

@softlion
Created February 20, 2024 17:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save softlion/cd25e99980d89c37b34f399945637bd8 to your computer and use it in GitHub Desktop.
Save softlion/cd25e99980d89c37b34f399945637bd8 to your computer and use it in GitHub Desktop.
Build a xamarin iOS app for release and publish it to testflight via AppCenter Distribute
# Xamarin.iOS
# Build a Xamarin.iOS project.
# Add steps that install certificates, test, sign, and distribute an app, save build artifacts, and more:
# https://docs.microsoft.com/azure/devops/pipelines/languages/xamarin
trigger:
- release/store
pool:
vmImage: 'macos-latest'
name: $(TeamProject)_$(SourceBranchName)_$(Rev:r)
variables:
outputDirectory: '$(build.binariesDirectory)/$(BuildConfiguration)'
steps:
- checkout: self
persistCredentials: true
clean: true
- script: |
echo "Build.SourceBranch: $(Build.SourceBranch)"
# To manually select a Xamarin SDK version on the Microsoft-hosted macOS agent,
# configure this task with the *Mono* version that is associated with the
# Xamarin SDK version that you need, and set the "enabled" property to true.
# See https://go.microsoft.com/fwlink/?linkid=871629
- script: sudo $AGENT_HOMEDIRECTORY/scripts/select-xamarin-sdk.sh 6_12_24
displayName: 'Select the Xamarin SDK version'
enabled: true
- task: Bash@3
displayName: 'Change some app features'
inputs:
targetType: 'inline'
failOnStderr: true
script: |
INFOPLIST_PATH="$(Build.SourcesDirectory)/MyApp/MyApp.iOS/info.plist"
#xamarin tooling adds "Production" automatically but does not remove "Development" ... So correct that.
ENTITLEMENTS_PATH="$(Build.SourcesDirectory)/MyApp/MyApp.iOS/Entitlements.plist"
/usr/libexec/PlistBuddy -c "Delete :com.apple.developer.icloud-container-environment" "$ENTITLEMENTS_PATH"
/usr/libexec/PlistBuddy -c "Add :com.apple.developer.icloud-container-environment string Production" "$ENTITLEMENTS_PATH"
#change some app features (app bundle name, app name, icon)
#when adhoc build is used, so adhoc and testflight apps can be installed side by side
BRANCH_NAME=${BUILD_SOURCEBRANCH##refs/heads/}
buildShift=0
acSlug=""
#URL: https://openapi.appcenter.ms/#/distribute/stores_list
#API: /v0.1/apps/{owner_name}/{app_name}/distribution_stores
acStoreId=""
if [ "$BRANCH_NAME" = "release/xxx/store" ]; then
echo "xxx branch detected: changing some app features"
buildShift=750
acSlug="MyApp-Xxx-iOS"
acStoreId="aabbccb0-aac2-bb6a-cc74-dd46440a3df2"
#change bundle name
plutil -replace CFBundleIdentifier -string "com.companyname.MyApp-xxx-iOS" "$INFOPLIST_PATH"
#change app name
plutil -replace CFBundleName -string "MyApp Xxx" "$INFOPLIST_PATH"
plutil -replace CFBundleDisplayName -string "MyApp xxx" "$INFOPLIST_PATH"
#/usr/libexec/PlistBuddy -c "Set :CFBundleURLTypes:0:CFBundleURLName com.companyname.MyApp-xxx-iOS" "$INFOPLIST_PATH"
#change app icon
plutil -replace XSAppIconAssets -string "Resources/MyAppXxx.xcassets/MyApp.appiconset" "$INFOPLIST_PATH"
#change the appcenter crash log id
sed -i '' 's/AppCenterIosKey = "[^"]*"/AppCenterIosKey = "aa36bb1e-cc80-dd11-ee0a-ffe830a1e787"/g' "$(Build.SourcesDirectory)/MyApp/MyApp.Data/Services/AppSettings.cs"
################## NORMAL
elif [ "$BRANCH_NAME" = "release/store" ]; then
echo "todo"
else
echo "Unknown branch '$BRANCH_NAME' detected, cancelling"
exit 1;
fi
build="$(Build.BuildNumber)"
build="${build##*_}"
build="$((build + buildShift))"
echo "Using build $build"
plutil -replace CFBundleVersion -string "$build" "$INFOPLIST_PATH"
echo "##vso[task.setvariable variable=BUILD_NUMBER]$build"
echo "##vso[task.setvariable variable=APPCENTER_SLUG]$acSlug"
echo "##vso[task.setvariable variable=APPCENTER_STOREID]$acStoreId"
- task: InstallAppleCertificate@2
inputs:
certSecureFile: 'MyApp Store.p12'
certPwd: '$(CERT_PASSWORD)'
keychain: 'temp'
#for release/store branch
- task: InstallAppleProvisioningProfile@1
condition: eq(variables['Build.SourceBranch'], 'refs/heads/release/store')
inputs:
provisioningProfileLocation: 'secureFiles'
provProfileSecureFile: 'MyApp_Normal_AppStore.mobileprovision'
#for release/xxx/store branch
- task: InstallAppleProvisioningProfile@1
condition: eq(variables['Build.SourceBranch'], 'refs/heads/release/xxx/store')
inputs:
provisioningProfileLocation: 'secureFiles'
provProfileSecureFile: 'MyApp_Xxx_AppStore.mobileprovision'
- task: NuGetToolInstaller@1
inputs:
versionSpec: ">=6.7.0"
- task: NuGetCommand@2
inputs:
restoreSolution: '$(Build.SourcesDirectory)/MyApp.sln'
feedsToUse: config
#This task uses msbuild from mono, which is old. We need msbuild from VSMac.
#- task: XamariniOS@2
# inputs:
# solutionFile: '$(Build.SourcesDirectory)/MyApp.sln'
# configuration: 'Release'
# packageApp: true
# runNugetRestore: false
#signIdentityEscaped below is required, as our apple signing certificate name contains a comma ...!!!
- task: Bash@3
displayName: 'Build iOS IPA'
inputs:
targetType: 'inline'
failOnStderr: true
script: |
signIdentityEscaped=$(echo "$APPLE_CERTIFICATE_SIGNING_IDENTITY" | sed 's/,/%2C/g')
cmd='
/Library/Frameworks/Mono.framework/Versions/Current/Commands/mono
"/Applications/Visual Studio.app/Contents/MonoBundle/MSBuild/Current/bin/MSBuild.dll"
"'"$(Build.SourcesDirectory)"'/MyApp.sln"
/t:Build
/p:Configuration=Release
/p:Platform=iPhone
/p:buildForSimulator=false
/p:BuildIpa=true
/p:Codesignkey="'"$signIdentityEscaped"'"
/p:CodesignProvision='"$APPLE_PROV_PROFILE_UUID"'
'
echo $cmd
eval $cmd
#- task: CopyFiles@2
# inputs:
# SourceFolder: '$(Build.SourcesDirectory)/MyApp/iOS/bin/iPhone/Release'
# Contents: '*.ipa'
# TargetFolder: '$(Build.ArtifactStagingDirectory)'
#- task: PublishBuildArtifacts@1
# inputs:
# PathtoPublish: '$(Build.ArtifactStagingDirectory)'
# ArtifactName: 'IPA'
# publishLocation: 'Container'
#see https://github.com/microsoft/azure-pipelines-tasks/blob/master/Tasks/AppCenterDistributeV3/task.json
- task: AppCenterDistribute@3
displayName: 'Post IPA and Symbols to appcenter distribute'
condition: eq(variables['Build.SourceBranch'], 'refs/heads/release/store')
inputs:
serverEndpoint: 'AppCenter MyApp'
destinationType: 'store'
destinationStoreId: '$(APPCENTER_STOREID)'
appSlug: 'MyCompany/$(APPCENTER_SLUG)'
app: 'MyApp/MyApp.iOS/bin/iPhone/Release/MyApp.ipa'
symbolsType: Apple
dsymPath: 'MyApp/MyApp.iOS/bin/iPhone/Release/MyApp.app.dSYM'
releaseNotesSelection: 'input'
releaseNotesInput: 'Updates to our mobile app'
- task: Bash@3
displayName: 'Tag Git Branch'
inputs:
targetType: 'inline'
failOnStderr: false
script: |
if [ "${AGENT_JOBSTATUS}" == "Succeeded" ]; then
git config --global user.email "azure@pipeline"
git config --global user.name "Azure Pipeline"
# Extract branch name from SourceBranch
branchName=${BUILD_SOURCEBRANCH##refs/heads/}
#Build.SourceBranchName
# Tag the branch if the build succeeded
TAG="$branchName-$BUILD_NUMBER"
git tag "$TAG"
git push origin "HEAD:$branchName" --tags
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment