관리 메뉴

김종권의 iOS 앱 개발 알아가기

[fastlane] *8. fastlane과 Bitrise를 이용한 자동 배포 구축 방법 본문

iOS 앱 배포와 출시

[fastlane] *8. fastlane과 Bitrise를 이용한 자동 배포 구축 방법

jake-kim 2021. 11. 4. 23:55

1fastlane이란?

2. Bundler란? cocoapod 동기화 방법?

3. fastlane match (certificate, provisioning profile 정보를 git에 저장)

4. fastlane build_app (빌드, firebase에 배포)

5. fastlane 앱 스토어에 배포 (App Store Connect)

6. fastlane register devices, 디바이스 정보(UDID, Name) Apple Developer 등록 방법 (register_devices)

*7. fastlane 총 정리 및 phase별 configuration 설정, 환경변수 설정

*8. fastlane과 Bitrise를 이용한 자동 배포 구축 방법

 

cf) fastlane 환경 변수 (.env.default) 사용하여 가장 단순한 match 사용 방법

앱 build를 app store connect에 올리기 전에 준비 사항

  • 앱 Icon을 등록하지 않으면 build가 올라가지 않고 아래처럼 이메일을 받으므로 아이콘 등록이 필수

  • Assets > AppIcon에 이미지 추가

  • Info.plist에 CFBundleIconName 키-밸류 추가

fastlane 내용 수정

  • 빌드 번호를 올려주는 기능을 fastlane에서하지 않고 bitrise에서 수행
    • fastlane에서 하게되면 아래와같은 빌드 오류 발생

default_platform(:ios)

ENV["FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD"] = "wzwy-zcxl-xkev-lyft"

platform :ios do
  
  # deploy

  lane :deploy_alpha do |options|
    sync_codesign_alpha()
    build(configuration: "alpha")
    upload_to_firebase(appid: "1:773589851865:ios:d1dcae5400c3304acce8c8", tester_group: "tester-first, tester-second" )
  end

  lane :deploy_beta do |options|
    sync_codesign_beta()
    build(configuration: "beta")
    upload_to_firebase(appid: "1:773589851865:ios:749c1a7bffb649b1cce8c8", tester_group: "tester-first, tester-second" )
  end

  lane :deploy_real do |options|
    sync_codesign_real()
    build(configuration: "real")

    api_key = app_store_connect_api_key(
      key_id: "4KRU955ZYH",
      issuer_id: "c2fd1c9b-7e84-42ee-a638-8f1a776042ae",
      key_filepath: "fastlane/AuthKey_U4M68Y6BJ3.p8",
      duration: 1200,
      in_house: false
    )

    upload_to_testflight(api_key: api_key,
                          skip_waiting_for_build_processing: true, 
                          ipa: "fastlane/distribute/SavePhoto.ipa")
  end

  # sync

  lane :sync_codesign_alpha do
    sync_codesign(type:"development")
    sync_codesign(type:"adhoc")
  end

  lane :sync_codesign_beta do
    sync_codesign(type:"development")
    sync_codesign(type:"adhoc")
  end

  lane :sync_codesign_real do
    sync_codesign(type:"development")
    sync_codesign(type:"appstore")
  end

  private_lane :sync_codesign do|options|
    match(type:options[:type], readonly: true)
  end

  # renew

  lane :renew_codesign_alpha do
    renew_codesign(type:"development")
    renew_codesign(type:"adhoc")
  end

  lane :renew_codesign_beta do
    renew_codesign(type:"development")
    renew_codesign(type:"adhoc")
  end

  lane :renew_codesign_real do
    renew_codesign(type:"development")
    renew_codesign(type:"appstore")
  end

  private_lane :renew_codesign do|options|
    match(type:options[:type], force_for_new_devices: true)
  end

  # register new device

  lane :register_new_devices do
    register_devices(
      devices_file: "./fastlane/devices.txt",
      team_id: "SS7U83UJNK"
    )
  end

  # private

  private_lane :build do |options|
    case options[:configuration]
    when "alpha"
      scheme = "SavePhoto alpha"
      export_type = "ad-hoc"
    when "beta"
      scheme = "SavePhoto beta"
      export_type = "ad-hoc"
    when "real"
      scheme = "SavePhoto real"
      export_type = "app-store"
    end

    build_app(
      scheme: scheme,
      export_method: export_type,
      output_directory: "./fastlane/distribute",
      clean: true
    )
  end

  private_lane :upload_to_firebase do |options|
    firebase_app_distribution(
      app: options[:appid],
      groups: options[:tester_group],
      firebase_cli_token: "1//0ePS_knB0VXuOCgYIARAAGA4SNwF-L9IrcIritOpKCIwYh5Mdj288Jgw7euJG_uu6UPVsUgeuQzoIoCuPStvAu2o9qhNYKM_Lv6E",
      ipa_path: "./fastlane/distribute/SavePhoto.ipa"
      #release_notes: "Lots of amazing new features to test out!"
    )
  end

end

Bitrise 

  • webhook과 trigger 기능을 통해 git에 push, tag, merge되었을 때 배포되게끔 가능

  • 가입 완료

  • Dashboard > Add new app

Project 생성 - git과 연동

  • Add new app 클릭하면 아래 화면부터 시작
    • private 체크 후 Next

  • remote repository 지정
    • Connect Github 클릭

  • github에서 로그인 완료 시 connect 성공

  • 다시 Github을 선택하면 repository를 선택할 수 있고, 해당 배포할 repository 선택

  • Add own ssh 선택

  • bitrise용도의 ssh키를 생성해야 하므로 명령어 실행
$ ssh-keygen -t rsa -b 4096 -P '' -f ./bitrise-ssh -m PEM
  • 생성된 ssh key는 ~/ 디렉토리에 bitrise-ssh로 열어서 복사
    • private key: bitrise-ssh > 위 bitrise에 붙여넣기
    • public key: bitrise-ssh.pub > github의 ssh키에 등록

bitrise에 private 키 붙여넣기
github에 ssh key 붙여넣기하여 ssh 생성

  • bitrise에서 brach 지정
    • 추후 자동 배포 시, 브랜치 설정이 없으면 여기에서 설정한 브랜치 내용으로 배포
    • 만약 에러 발생 시, repository가 현재 public으로 설정되어 있어서 에러 발생할수 있으므로, repository를 private으로 access 수정하고 ssh키값이 맞지 않아서 그러므로 ssh키값 확인 필요

  • 결과
    • 자동으로 xcode에서 만들었던 scheme들과 fastlane 표출

  • 옵션을 모두 선택 후 next

  • 기타 설정값 선택 후 webhook 설정
    • Register a Webhook for me! 클릭

  • 완료
    • We've kicked off your first test build for you 클릭

Workflow 구현

  • 배포되는 하나의 flow를 정의한 것이며, step들로 이루어진 작업흐름단위

ex) alpha, beta, real 워크플로우가 있는 상태,

alpha 워크플로우: alpha버전 배포 용도

  • 생성
    • Dashboard > ... > workflow 선택
    • + Workflow 클릭

  • 추가
    • Based On은 디폴트로 생성된 primary workflow를 복사하여 만드는 것

  • Xcode Archive 스탭 삭제

  • Set Xcode Project Build Number 스텝 추가

> xcode에서 Info.plist에 bundle version string 키값 생성

$(CURRENT_PROJECT_VERSION)

> info.plist 경로 입력

Xcode에서 먼저 info.plist파일이 어디있는지 확인

Xcode에서 먼저 info.plist파일이 어디있는지 확인

$BITRISE_SOURCE_DIR/{위에서 확인한 path 붙여넣기}

  • fastlane 스탭 생성

  • Save 클릭

cf) 만약 cocoapod을 사용하고 있다면, Certificate and profile 다음 step에 Run cocoapods install 추가

환경 변수 설정

  • ssh private key 환경변수 등록 - 위에서 bitrise ssh key 만들었던 private key를 여기에도 입력
    • Key 이름은 `SSH_RSA_PRIVATE_KEY`로 입력

수동 빌드 방법

  • bitrise에서 직접 git에 있는 branch 이름을 지정하여 빌드되게 하는 방법
  • Dashboard > {user} > {project name} > Start/Schedule a Build 클릭

  • 빌드
    • Branch 선택
    • Message 입력
    • Workflow 선택 후 Start Build 클릭

  • 성공

adhoc 배포 완료

trigger 사용 방법

  • Workflow Editor 탭에서 Triggers 탭 클릭
  • 세 가지 옵션에서 trigger 정의
    • PUSH:  연결된 git의 branch와 workflow를 설정하면 해당 branch에 푸시가 될 때 workflow동작
      ex) `*` 기호는 모든을 뜻하므로, 아무 branch에 push가 되면 `primary` workflow동작
    • PULL REQUEST: Push와 설정 동일
    • TAG: 문자열과 workflow를 설정
      ex) *alpha* 문자열로 설정해놓으면, alpha-v0.1.1과 같은 tag도 트리거 동작

cf) bitrise를 사용하지 않고 로컬에서 fastlane만 사용하는 경우, bump_build_number()를 적용한 fastfile 내용 참고

default_platform(:ios)

ENV["FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD"] = "wzwy-zcxl-xkev-lyft"

platform :ios do
  
  # deploy

  lane :deploy_alpha do |options|
    sync_codesign_alpha()
    bump_build_number()
    build(configuration: "alpha")
    upload_to_firebase(appid: "1:773589851865:ios:d1dcae5400c3304acce8c8", tester_group: "tester-first, tester-second" )
  end

  lane :deploy_beta do |options|
    sync_codesign_beta()
    bump_build_number()
    build(configuration: "beta")
    upload_to_firebase(appid: "1:773589851865:ios:749c1a7bffb649b1cce8c8", tester_group: "tester-first, tester-second" )
  end

  lane :deploy_real do |options|
    sync_codesign_real()
    bump_build_number()
    build(configuration: "real")

    api_key = app_store_connect_api_key(
      key_id: "4KRU955ZYH",
      issuer_id: "c2fd1c9b-7e84-42ee-a638-8f1a776042ae",
      key_filepath: "fastlane/AuthKey_4KRU955ZYH.p8",
      duration: 1200,
      in_house: false
    )

    upload_to_testflight(
      api_key: api_key,
      skip_waiting_for_build_processing: true, 
      ipa: "fastlane/distribute/SavePhoto.ipa"
    )

  end

  # sync

  lane :sync_codesign_alpha do
    sync_codesign(type:"development")
    sync_codesign(type:"adhoc")
  end

  lane :sync_codesign_beta do
    sync_codesign(type:"development")
    sync_codesign(type:"adhoc")
  end

  lane :sync_codesign_real do
    sync_codesign(type:"development")
    sync_codesign(type:"appstore")
  end

  private_lane :sync_codesign do|options|
    match(type:options[:type], readonly: true)
  end

  # renew

  lane :renew_codesign_alpha do
    renew_codesign(type:"development")
    renew_codesign(type:"adhoc")
  end

  lane :renew_codesign_beta do
    renew_codesign(type:"development")
    renew_codesign(type:"adhoc")
  end

  lane :renew_codesign_real do
    renew_codesign(type:"development")
    renew_codesign(type:"appstore")
  end

  private_lane :renew_codesign do|options|
    match(type:options[:type], force_for_new_devices: true)
  end

  # register new device

  lane :register_new_devices do
    register_devices(
      devices_file: "./fastlane/devices.txt",
      team_id: "SS7U83UJNK"
    )
  end

  # private

  private_lane :build do |options|
    case options[:configuration]
    when "alpha"
      scheme = "SavePhoto alpha"
      export_type = "ad-hoc"
    when "beta"
      scheme = "SavePhoto beta"
      export_type = "ad-hoc"
    when "real"
      scheme = "SavePhoto real"
      export_type = "app-store"
    end

    build_app(
      scheme: scheme,
      export_method: export_type,
      output_directory: "./fastlane/distribute",
      clean: true
    )
  end

  private_lane :upload_to_firebase do |options|
    firebase_app_distribution(
      app: options[:appid],
      groups: options[:tester_group],
      firebase_cli_token: "1//0ePS_knB0VXuOCgYIARAAGA4SNwF-L9IrcIritOpKCIwYh5Mdj288Jgw7euJG_uu6UPVsUgeuQzoIoCuPStvAu2o9qhNYKM_Lv6E",
      ipa_path: "./fastlane/distribute/SavePhoto.ipa"
      #release_notes: "Lots of amazing new features to test out!"
    )
  end

  private_lane :bump_build_number do
    ensure_git_status_clean
    increment_build_number(xcodeproj: "./SavePhoto.xcodeproj")
    build_number = get_build_number(xcodeproj: "./SavePhoto.xcodeproj")
    commit_version_bump(message: "Bump build number to #{build_number} by fastlane", xcodeproj: "./SavePhoto.xcodeproj")
    push_to_git_remote
  end

end
  • app store connect에서 `빌드 +`버튼을 누르면 업로드된 것 확인 가능

* 전체 소스 코드: https://github.com/JK0369/SavePhoto

 

* 참고

https://devcenter.bitrise.io/faq/how-to-generate-ssh-keypair/

Comments