A Distribution Certificate is used to identify a developer for the purpose of installing and testing apps on iOS devices. Certificates can be obtained from Apple’s iOS Provisioning Portal and a Certificate Signing Request (CSR) file needs to be generated first.
The process for generating a CSR differs depending on your choice of operating system. In this post, I’ll cover how to generate Certificate Signing Request (CSR) file on Windows as well as how to use the generated certificate and provisioning profile to build and sign an iOS application in Azure DevOps.
First open a PowerShell window, then run the following command to create a private key:
1
openssl genrsa -out appstore-distribution.key 2048
Next, run the following command to generate the Certificate Signing Request (CSR) file using the previously created private key:
1
openssl req -new -key appstore-distribution.key -out appstore-distribution.csr -subj "/emailAddress=devops@example.com, CN=Example, C=CA"
Next, go to the Apple Developer Portal and click the “+” button next to “Certificates”:
Choose the type of certificate you want to create, then click “Continue”
Upload the Certificate Signing Request (CSR) file generated earlier and click “Continue”:
A certificate will be generated and will be available for download. click “Download the Certificate”.
In order to sign the application in Azure DevOps, we need the certificate in
.p12
format. So to convert the.cer
file to.p12
, execute the following commands:1
openssl x509 -in appstore-distribution.cer -inform DER -out appstore-distribution.pem -outform PEM
followed by:
1
openssl pkcs12 -export -out appstore-distribution.p12 -inkey appstore-distribution.key -in appstore-distribution.pem
This will prompt for a password. Please provide a password and store it in a safe place. This password will be needed when signing the application.
Next, we need to generate a provisioning profile by going back to the Apple Developer Portal and clicking “+” next to “Profiles”:
Choose the type of Provisioning Profile you want to create, then click “Continue”
Select the App ID you would like associated with the provisioning profile, then click “Continue”.
Select the certificate we created earlier, then click “Continue”.
Give the provisioning profile a name, then click “Generate”. You will be able to download the provisioning profile after it is generated.
Upload the P12 certificate and provisioning profile to Azure DevOps Secure Files Library. During upload, your certificate will be encrypted and securely stored.
Create a new pipeline, or go to the pre-existing pipeline if one already exists.
Go to the Variables tab and add the following variables:
CertificateFile
: Set the value toappstore-distribution.p12
(or whatever name you gave to your P12 certificate file in step #13).CertificatePassword
: Set the value to the password you set in step #7 above. Be sure check “Keep this value secret”. This will secure your password and obscure it in logs.ProvisioningFile
: Set the value toappstore-distribution.mobileprovision
(or whatever name you gave your provisioning file in step #13).
Update the
azure-pipelines.yml
using the following example:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
name: $(Build.BuildId) trigger: - main - dev pool: vmImage: 'macOS-latest' variables: - name: configuration value: Release - name: sdk value: iphoneos - name: scheme value: Example - name: workspace value: Example.xcworkspace - name: plistFile value: Info.plist steps: - task: Cache@2 inputs: key: 'pods | "$(Agent.OS)" | Podfile.lock' path: 'Pods' cacheHitVar: 'PODS_CACHE_RESTORED' - task: CocoaPods@0 displayName: 'pod install using the CocoaPods task with defaults' inputs: forceRepoUpdate: true condition: ne(variables.PODS_CACHE_RESTORED, 'true') - task: InstallAppleCertificate@2 inputs: certSecureFile: '$(certificateFile)' certPwd: '$(CertificatePassword)' keychain: 'temp' deleteCert: true - task: InstallAppleProvisioningProfile@1 inputs: provisioningProfileLocation: 'secureFiles' provProfileSecureFile: '$(provisioningFile)' - task: CmdLine@2 displayName: 'Set Build Number' inputs: script: '/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $(Build.BuildId)" $(Build.SourcesDirectory)/$(scheme)/$(plistFile)' - task: Xcode@5 inputs: actions: 'build' configuration: '$(configuration)' sdk: '$(sdk)' xcWorkspacePath: '$(workspace)' scheme: '$(scheme)' packageApp: true signingOption: 'manual' signingIdentity: '$(APPLE_CERTIFICATE_SIGNING_IDENTITY)' provisioningProfileUuid: '$(APPLE_PROV_PROFILE_UUID)' - task: CopyFiles@2 inputs: contents: '**/*.ipa' targetFolder: '$(build.artifactStagingDirectory)' - task: PublishBuildArtifacts@1 displayName: 'Publish artifact' condition: succeededOrFailed()
References:
Convert .cer to .p12
Build, test, and deploy Xcode apps
Sign your mobile app