Azure DevOps Flutter IOS CI Pipeline
December 21, 2024

Azure DevOps Flutter IOS CI Pipeline

Because it took me a long time and effort to iron out all the kinks in Azure DevOps to get my build pipeline working properly. I need to share the problem I faced and how I finally made it work


Certificates and Introduction


cocoa pods


Pipeline steps


Problem and how I solved it

  • Mod not found
  • Credentials generated from xcode don’t work with pipelines
  • Pod does not support profiles

Certificates and Introduction:
In the Android Play Store, you have one certificate for all your apps, and that certificate is tied to your app, so in your configuration and build, you only need to use one certificate in all cases. Sign the application package file. In Apple, no, there are too many different types for each use, and it’s not just certificates, but certificates with profiles. This makes this more complex than in Android. So during development, you have temporary profiles and certificates in the app store, you have the app store and so on

cocoa pods:
Cocoapods is a dependency module that your project requires, so you need to consider it as part of your build pipeline, as I will mention later in this article

*Pipeline steps:*
Here I will mention the entire piping steps and all the issues I faced during the build process

pool:
  name: Azure Pipelines
  demands: xcode

steps:
# getting version number and build number from pubsec.yaml file , please change it if you don't need this to work like this 
- bash: |
   echo "preparing build variables"
   echo "getting build version and build number from pubsec file"
   buildVersion=`grep version src/app/pubspec.yaml |  cut -d':' -f2 | cut -d'+' -f1 | sed 's/ //'`
   buildNumber=`grep version src/app/pubspec.yaml |  cut -d':' -f2 | cut -d'+' -f2 | sed 's/ //'`
   echo "version will be ===> $buildVersion"
   echo "build number will be ===> $buildNumber"
   echo "##vso[task.setvariable variable=buildVersion;]$buildVersion"
   echo "##vso[task.setvariable variable=buildNumber;]$buildNumber"

  displayName: 'prepare build variables '

- task: InstallAppleCertificate@2
  displayName: 'Install an Apple certificate'
  inputs:
    certSecureFile: '********'
    certPwd: '$(P12password)'
    setUpPartitionIdACLForPrivateKey: false

- task: InstallAppleProvisioningProfile@1
  displayName: 'Install an Apple provisioning profile'
  inputs:
    provProfileSecureFile: '******'

- task: Hey24sheep.flutter.flutter-install.FlutterInstall@0
  displayName: 'Flutter Install'

- task: Hey24sheep.flutter.flutter-build.FlutterBuild@0
  displayName: 'Flutter Build ios'
  inputs:
    target: ios
    projectDirectory: src/app
    iosCodesign: false

## This step is very important to consider .. because of pod doesn't support code sign and profile,
## I removed last 6 lines of Podfile which contains post_install section .. please check how many lines you have and remove them 
## After I removed it I added the below section 
- bash: |
   echo "podfile old =================================================================="
   cat Podfile 
   awk 'NR>c{print A[NR%c]} {A[NR%c]=$0}' c=6 Podfile > PodfileTemp
   echo "podfile new =================================================================="
   cat PodfileTemp
   mv PodfileTemp Podfile 
   echo " " >> Podfile
   echo "post_install do |installer| " >> Podfile
   echo "  installer.pods_project.targets.each do |target| " >> Podfile
   echo "    flutter_additional_ios_build_settings(target)" >> Podfile
   echo "    target.build_configurations.each do |config| " >> Podfile
   echo "      config.build_settings['EXPANDED_CODE_SIGN_IDENTITY'] = \"\" " >> Podfile
   echo "      config.build_settings['CODE_SIGNING_REQUIRED'] = \"NO\" " >> Podfile
   echo "      config.build_settings['CODE_SIGNING_ALLOWED'] = \"NO\" " >> Podfile
   echo "    end " >> Podfile
   echo "  end " >> Podfile
   echo "end " >> Podfile

   sudo gem uninstall cocoapods -ax
   sudo gem install cocoapods

  workingDirectory: src/app/ios
  displayName: 'Modify Podfile'

# This is the trick again .. after you prepare your Podfile you will need to run cocoapod install again .. else the above step will not reflect 
- task: CocoaPods@0
  displayName: 'pod install'
  inputs:
    workingDirectory: src/app/ios
# MARKETING_VERSION and CURRENT_PROJECT_VERSION are variables defined in my code to represent version and build 
# please change it with yours 
- task: Xcode@5
  displayName: 'Xcode build'
  inputs:
    xcWorkspacePath: src/app/ios/Runner.xcworkspace
    scheme: Runner
    packageApp: true
    signingOption: manual
    signingIdentity: '$(APPLE_CERTIFICATE_SIGNING_IDENTITY)'
    provisioningProfileUuid: '$(APPLE_PROV_PROFILE_UUID)'
    args: 'MARKETING_VERSION="$(buildVersion)" CURRENT_PROJECT_VERSION="$(buildNumber)"'

- task: CopyFiles@2
  displayName: 'Copy Files to: $(build.artifactstagingdirectory)'
  inputs:
    SourceFolder: '$(system.defaultworkingdirectory)'
    Contents: '**/*.ipa'
    TargetFolder: '$(build.artifactstagingdirectory)'
  condition: succeededOrFailed()

- task: PublishBuildArtifacts@1
  displayName: 'Publish Artifact: drop'
  inputs:
    PathtoPublish: '$(build.artifactstagingdirectory)'
  condition: succeededOrFailed()

Enter full screen mode

Exit full screen mode

`

2024-12-21 02:27:52

Leave a Reply

Your email address will not be published. Required fields are marked *