241216 TIL

나고수·2024년 12월 18일
0

2024 TIL

목록 보기
91/94
post-thumbnail

① 배운 것

하나의 github workflow와 fastlnae 로 ios firebase app distribution과 testflight에 업로드 하기

  • 여기여기에서 했던 것을 합쳐 하나의 github workflow와 fastlnae 로 ios firebase app distribution과 testflight에 업로드 하기
//workflows.yml
name: IOS CD Release

on:
  push:
    tags:
      - "v_dev_*"
      - "v_prod_*"

jobs:
  release:
    runs-on: macos-latest

    steps:
      # 1. 코드 체크아웃
      - name: Checkout repository
        uses: actions/checkout@v3

      # 2. SSH 키 설정 - fastLane match에서 사용
      - name: Setup SSH
        uses: shimataro/ssh-key-action@v2
        with:
          key: ${{ secrets.SSH_KEY }}
          known_hosts: ${{ secrets.KNOWN_HOSTS }}

      # 3. Ruby 설정 및 캐싱
      - name: Setup Ruby with caching
        uses: ruby/setup-ruby@v1
        with:
          ruby-version: 3.0
          bundler-cache: true

      # 4. Fastlane 캐싱
      - name: Cache Fastlane
        uses: actions/cache@v3
        with:
          path: |
            ~/.bundle
            ~/.fastlane
          key: ${{ runner.os }}-fastlane-${{ hashFiles('**/Gemfile.lock') }}
          restore-keys: |
            ${{ runner.os }}-fastlane-

      # 5. Install Fastlane
      - name: Install Fastlane
        run: |
          cd ios
          gem install bundler
          bundle install

      - name: Cache Flutter dependencies
        uses: actions/cache@v3
        with:
          path: ${{ matrix.flutter_path }}
          key: ${{ runner.os }}-flutter-${{ hashFiles('**/pubspec.lock') }}
          restore-keys: |
            ${{ runner.os }}-flutter-

      # 6. Flutter 설치
      - name: Setup Flutter
        uses: subosito/flutter-action@v1
        with:
          channel: 'stable'

      #7. github에서 가져오는 dependency에 접근하기위한 설정
      - name: Configure Git
        run: |
          git config --global url."https://${{ vars.USER_NAME }}:${{ secrets.TOKEN_GITHUB }}@github.com/".insteadOf "https://github.com/"    

      # 8. Flutter 의존성 설치
      - name: Install Dependencies
        run: flutter pub get

      # 9. config.dart 생성
      - name: Generate Config
        run: |
          echo '${{ secrets.CONFIG }}' | base64 --d >> ./lib/common/config.dart      

      # 10. Fastlane 실행
      - name: Build and Upload to TestFlight
        run: |
          cd ios
          if [[ "${GITHUB_REF}" == refs/tags/v_dev_* ]]; then
            echo "APP_IDENTIFIER=co.example.example.dev" >> $GITHUB_ENV
            echo "MATCH_TYPE=adhoc" >> $GITHUB_ENV
            echo "GIT_URL=https://github.com/..." >> $GITHUB_ENV
            fastlane release environment:dev 
          elif [[ "${GITHUB_REF}" == refs/tags/v_prod_* ]]; then
            echo "APP_IDENTIFIER=co.example.example" >> $GITHUB_ENV
            echo "MATCH_TYPE=appstore" >> $GITHUB_ENV
            echo "GIT_URL=https://github.com/..." >> $GITHUB_ENV
            fastlane release environment:prod
          else
            echo "Tag does not match any pattern. Exiting..."
            exit 1
          fi
        env:
          CI: true
          APPLE_ID: ${{ secrets.APPLE_ID }}
          TEAM_ID: ${{ secrets.TEAM_ID }}
          MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
          SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
          FASTLANE_USER: ${{ secrets.FASTLANE_USER }}
          FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD: ${{ secrets.FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD }}
          FIREBASE_CLI_TOKEN: ${{ secrets.FIREBASE_CLI_TOKEN }}
          FIREBASE_APP_ID: ${{ secrets.FIREBASE_APP_ID_IOS_DEV }}
          APP_DISTRIBUTION_GROUPS: ${{ vars.APP_DISTRIBUTION_GROUPS }}

달라진점은, 'Build and Upload to TestFlight'에서 tag에 따라 필요한 환경변수를 설정하고 어떤 fastlane을 실행시킬지 결정한다.

#fastfile
default_platform(:ios)

platform :ios do
  desc "Deploy to App Distribution or TestFlight"
  lane :release do |options|
    # 옵션 처리
    environment = options[:environment] || "dev" # 기본값: dev
    flavor = environment == "prod" ? "prod" : "dev"
    export_method = environment == "prod" ? "app-store" : "ad-hoc"
    provisioning_profile_name = environment == "prod" ? "AppStore" : "AdHoc"
    app_id = environment == "prod" ? "co.example.example" : "co.example.example.dev"

    # CI 환경 설정
    setup_ci if ENV['CI']

    # 인증서 및 프로비저닝 프로파일 설정
    match(
      git_url: environment == "prod" ? "git@github.com:..." : "git@github.com:...",
      app_identifier: [
        app_id,
        "#{app_id}.NotificationServiceExtension"
      ],
      type: export_method == "app-store" ? "appstore" : "adhoc",
      readonly: true
    )

    # 버전 관리
    pubspec = YAML.load_file("../../pubspec.yaml")
    version = pubspec["version"].split('+')

    increment_version_number(
      version_number: version[0],
      xcodeproj: "Runner.xcodeproj"
    )

    increment_build_number(
      build_number: version[1],
      xcodeproj: "Runner.xcodeproj"
    )

    # 코코아팟 업데이트 및 빌드
    cocoapods(
      repo_update: true,
      clean_install: true,
      use_bundle_exec: false
    )

    # Flutter 빌드
    sh("flutter build ios --release --flavor #{flavor} --no-codesign")

    # 앱 빌드
    build_app(
      workspace: "Runner.xcworkspace",
      scheme: flavor,
      export_method: export_method,
      export_options: {
        provisioningProfiles: {
          app_id => "match #{provisioning_profile_name} #{app_id}",
          "#{app_id}.NotificationServiceExtension" => "match #{provisioning_profile_name} #{app_id}.NotificationServiceExtension"
        }
      }
    )

    # 배포 처리
    if environment == "prod"
      # TestFlight 업로드
      upload_to_testflight(
        skip_waiting_for_build_processing: true,
        apple_id: ENV["APPLE_ID"],
        team_id: ENV["TEAM_ID"]
      )
      slack(message: "TestFlight 배포 완료 🎉", slack_url: ENV["SLACK_WEBHOOK_URL"])
    else
      # Firebase App Distribution 업로드
      firebase_app_distribution(
        app: ENV["FIREBASE_APP_ID"],
        firebase_cli_token: ENV["FIREBASE_CLI_TOKEN"],
        groups: ENV["APP_DISTRIBUTION_GROUPS"]
      )
      slack(message: "IOS Dev App Distribution 배포 완료 🎉", slack_url: ENV["SLACK_WEBHOOK_URL"])
    end
  end

  error do |lane, exception, options|
    # 배포 실패 시 Slack 알림
    slack(
      message: "IOS 자동배포 실패 🥲\n #{exception}",
      success: false,
      slack_url: ENV["SLACK_WEBHOOK_URL"]
    )
  end
end

여기도 달라진점은, lane 이름으로 들어온 options에 따라 환경변수를 설정하고 options에 따라 testflight에 올릴지 app distribution에 올릴지 결정한다.

appfile과 matchfile에서도 환경에 따라 구분되어야 하는 변수들은 workflow에서 설정해서 받음

#appFile
app_identifier(ENV['APP_IDENTIFIER']) # The bundle identifier of your app
apple_id("...") # Your Apple Developer Portal username

itc_team_id("...") # App Store Connect Team ID
team_id("...") # Developer Portal Team ID

# For more information about the Appfile, see:
#     https://docs.fastlane.tools/advanced/#appfile
#matchFile
git_url(ENV['GIT_URL'])

storage_mode("git")

type(ENV['MATCH_TYPE'])

# app_identifier(["tools.fastlane.app", "tools.fastlane.app2"])
# username("user@fastlane.tools") # Your Apple Developer Portal username

# For all available options run `fastlane match --help`
# Remove the # in the beginning of the line to enable the other options

# The docs are available on https://docs.fastlane.tools/actions/match

② 회고 (restropective)
ios는 플러터 빌드 후 아카이브를 따로 해줘야하는 부분이 너무너무 귀찮았는데 이것을 자동으로 할 수 있어서 완전 편하다.
그런데 github에서 제공하는 Ruuner가 너무 느리다. 거의 20분 넘게 걸림. 특히 build하고 testflight에 올리는 부분이 너무 느린데, 흠..🤔 찾아보니까 젠킨스를 이용하면 훨씬 빠르게 할 수 있다는 후기가 있어서 나중에 백앤드 분들한테 부탁해서 젠킨스로 옮겨봐야겠다!!

③ 개선을 위한 방법
이제 안드로이드 자동배포까지 가보자고

profile
되고싶다

1개의 댓글

comment-user-thumbnail
2024년 12월 19일

캐시해두니까 두번째 실행부터는 빨라진거같기도하고? 전체 워크프로우 시작~끝 까지 12분 정도 걸림

답글 달기