okaryo.log

Building a Workflow to Upload a Flutter iOS App to Firebase App Distribution Using CircleCI (Non-AutoSigning) | okaryo.log

Building a Workflow to Upload a Flutter iOS App to Firebase App Distribution Using CircleCI (Non-AutoSigning)

    #Flutter#Firebase#AppDistribution#CircleCI#CI/CD

Introduction

Recently, I built a workflow to upload a Flutter iOS app to Firebase App Distribution using GitHub Actions.

https://blog.okaryo.io/en/20240911-flutter-iosfirebase-app-distribution-github-actions-not-auto-signing

However, running it on macos was quickly draining the free tier minutes. While I plan to switch to a self-hosted runner to avoid this, for the time being, I decided to run it on CircleCI as a temporary workaround.

The Workflow I Built

Here is the final workflow I ended up with. Since this is a temporary workflow that will be discarded once it’s no longer needed, the processing is hardcoded and not organized for long-term use. Please keep that in mind.

version: 2.1

orbs:
  flutter: circleci/flutter@2
  firebase-app-distribution: nnsnodnb/firebase-app-distribution@0

executors:
  macos-executor:
    macos:
      xcode: 15.4.0
    resource_class: macos.m1.medium.gen1

jobs:
  ios_deploy_app_distribution:
    executor: macos-executor
    parameters:
      firebase_app_id:
        type: string
      app_distribution_service_account:
        type: string
      ios_bundle_id:
        type: string
      ios_provisioning_profile_name:
        type: string
      ios_adhoc_provision_profile_base64:
        type: string
      runner_keychain_password:
        type: string
    steps:
      - checkout
      - flutter/install_sdk_and_pub:
          version: 3.19.5
      - run:
          name: Update cocoapods
          command: gem update cocoapods
      - flutter/install_ios_pod
      - run:
          name: Install Apple certificate and provisioning profile
          environment:
            IOS_ADHOC_PROVISION_PROFILE_BASE64: $IOS_ADHOC_PROVISION_PROFILE_BASE64
            RUNNER_KEYCHAIN_PASSWORD: $RUNNER_KEYCHAIN_PASSWORD
          command: |
            CERTIFICATE_PATH=$CIRCLE_WORKING_DIRECTORY/build_certificate.p12
            PP_PATH=$CIRCLE_WORKING_DIRECTORY/build_pp.mobileprovision
            KEYCHAIN_PATH=$CIRCLE_WORKING_DIRECTORY/app-signing.keychain-db
            
            mkdir -p $(dirname "$CERTIFICATE_PATH")
            mkdir -p $(dirname "$PP_PATH")

            echo -n "$IOS_CERTIFICATE_P12_BASE64" | base64 --decode -o $CERTIFICATE_PATH
            echo -n << parameters.ios_adhoc_provision_profile_base64 >> | base64 --decode -o $PP_PATH

            security create-keychain -p << parameters.runner_keychain_password >> $KEYCHAIN_PATH
            security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
            security unlock-keychain -p << parameters.runner_keychain_password >> $KEYCHAIN_PATH

            security import $CERTIFICATE_PATH -P "$IOS_P12_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
            security set-key-partition-list -S apple-tool:,apple: -k << parameters.runner_keychain_password >> $KEYCHAIN_PATH
            security list-keychain -d user -s $KEYCHAIN_PATH

            mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles
            cp $PP_PATH ~/Library/MobileDevice/Provisioning\ Profiles
      - run:
          name: Generate ExportOptions.plist
          command: |
            export EXPORT_METHOD=release-testing
            export EXPORT_DESTINATION=export
            export BUNDLE_ID=<< parameters.ios_bundle_id >>
            export PROVISIONING_PROFILE=<< parameters.ios_provisioning_profile_name >>
            envsubst < ios/Runner/ExportOptions-Template.plist > ios/Runner/ExportOptions.plist
      - run:
          name: Install Rosetta 2
          command: sudo softwareupdate --install-rosetta --agree-to-license
      - run:
          name: Build ipa
          command: |
            flutter build ipa \
              --release \
              --flavor << parameters.environment >> \
              --export-options-plist=ios/Runner/ExportOptions.plist
      - run:
          name: Set up Firebase App Distribution Service Credentials
          command: echo << parameters.app_distribution_service_account >> > /tmp/firebase-app-distribution-service-credentials.json
      - firebase-app-distribution/deploy:
          app: << parameters.firebase_app_id >>
          binary_path: build/ios/ipa/app-<< parameters.environment >>-release.ipa
          groups: ios_testers
          release_note: << pipeline.git.revision >>
          service_credentials_file: /tmp/firebase-app-distribution-service-credentials.json

workflows:
  ios_deploy_app_distribution:
    jobs:
      - ios_deploy_app_distribution:
          firebase_app_id: $FIREBASE_IOS_APP_ID
          app_distribution_service_account: $APP_DISTRIBUTION_SERVICE_ACCOUNT_JSON
          ios_bundle_id: $IOS_BUNDLE_ID
          ios_provisioning_profile_name: $IOS_PROVISIONING_PROFILE_NAME
          ios_adhoc_provision_profile_base64: $IOS_ADHOC_PROVISION_PROFILE_BASE64
          runner_keychain_password: $RUNNER_KEYCHAIN_PASSWORD
          filters:
            branches:
              only: develop

Since the steps aren’t significantly different from what I built with GitHub Actions, I’ll skip the detailed explanations.

https://blog.okaryo.io/en/20240911-flutter-iosfirebase-app-distribution-github-actions-not-auto-signing

Also, it appears that CircleCI provides an Orb for Flutter, making workflow construction more straightforward. There are several jobs and commands you can use with this Orb, so please check it out if necessary.

Conclusion

I couldn’t simply copy-paste the workflow from GitHub Actions, as CircleCI has its own setup and syntax that I needed to account for. So, even though this is a throwaway workflow, it still took a bit of time.

I hope to quickly set up a self-hosted runner and free myself from the anxiety of macos build times.


Related Posts
Related Posts
Promotion

This site uses Google Analytics.