ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Fastlane 으로 iOS 빌드 과정을 손쉽게 자동화하자
    카테고리 없음 2019. 3. 2. 18:11

    Fastlane 으로 iOS 빌드하기

    https://fastlane.tools/

    fastlane은 루비 기반 클라이언트 자동 빌드 오픈소스 라이브러리입니다.

    iOS 프로젝트에서는 코드 사이닝 관리, 스크린샷, 테스트플라이트 업로드, 앱스토어 업로드 등을 커맨드 라인으로 할 수 있는 장점이 있습니다.

    그 외에도 info_plist 의 값을 변경하거나 cocoapods를 인스톨하는 과정 등도 자동화할 수 있습니다.

    iOS 배포 과정은 기본적으로 다음과 같은 플로우를 거쳐야 합니다.

    1. Info_plist 를 들어가 버전과 빌드를 올린다. 타겟이 여러개인 경우, 모든 타겟이 버전과 빌드가 동일한지 일일히 체크해주어야 한다.
    2. 빌드하고, 필요시 cocoapods 를 업데이트하거나 인스톨한다.
    3. 3인 이상의 개발자가 동시에 개발할 경우, 1년에 한번씩 프로파일과 인증서를 발급받고 공유한다.
    4. 단위 테스트, UI 테스트를 돌려서 통과 여부를 체크한다.
    5. 아카이브 버튼을 누르고, 아카이브가 완료될 때까지 기다린다.
    6. 아카이브가 완료되면 배포 버튼을 누르고, 배포가 다 될 떄까지 기다린다.
    7. 테스트플라이트에 알림이 뜨면 앱 설명을 작성하고 배포 버튼을 누른다.
    8. Dsym 파일을 압축해서 Firebase 오류 보고서에 올린다.
    9. slack에 배포가 완료되었음을 공유한다.

    fastlane 은 해당 프로세스를 커맨드 라인 하나로 자동화해주는 장점을 가지고 있습니다.

     

    fastlane 설치하기

    https://docs.fastlane.tools/getting-started/ios/setup/

    Xcode 커맨드 라인 툴을 설치합니다.

    xcode-select --install

    fastlane을 설치합니다.

    # RubyGems 사용
    sudo gem install fastlane -NV
    
    # Homebrew 사용
    brew cask install fastlane
    

    fastlane 설정하기

    iOS 프로젝트로 들어가, 다음과 같은 명령어를 입력홥니다.

    fastlane init

    콘솔에 이렇게 나타날 것입니다.

    [17:11:43]: -----------------------------
    [17:11:43]: --- Welcome to fastlane 🚀 ---
    [17:11:43]: -----------------------------
    [17:11:43]: fastlane can help you with all kinds of automation for your mobile app
    [17:11:43]: We recommend automating one task first, and then gradually automating more over time
    [17:11:43]: What would you like to use fastlane for?
    1. 📸  Automate screenshots
    2. 👩‍✈️  Automate beta distribution to TestFlight
    3. 🚀  Automate App Store distribution
    4. 🛠  Manual setup - manually setup your project to automate your tasks
    

    저희가 보통 관심을 가지고 있는 것은 앱 자동 배포이므로, 3을 누르고 엔터를 누릅니다.

    [17:12:34]: ----------------------------------------------------------
    [17:12:34]: --- Setting up fastlane for iOS App Store distribution ---
    [17:12:34]: ----------------------------------------------------------
    [17:12:34]: Parsing your local Xcode project to find the available schemes and the app identifier
    [17:12:37]: --------------------------------
    [17:12:37]: --- Login with your Apple ID ---
    [17:12:37]: --------------------------------
    [17:12:37]: To use App Store Connect and Apple Developer Portal features as part of fastlane,
    [17:12:37]: we will ask you for your Apple ID username and password
    [17:12:37]: This is necessary for certain fastlane features, for example:
    [17:12:37]: 
    [17:12:37]: - Create and manage your provisioning profiles on the Developer Portal
    [17:12:37]: - Upload and manage TestFlight and App Store builds on App Store Connect
    [17:12:37]: - Manage your App Store Connect app metadata and screenshots
    [17:12:37]: 
    [17:12:37]: Your Apple ID credentials will only be stored in your Keychain, on your local machine
    [17:12:37]: For more information, check out
    [17:12:37]: 	https://github.com/fastlane/fastlane/tree/master/credentials_manager
    [17:12:37]: 
    [17:12:37]: Please enter your Apple ID developer credentials
    [17:12:37]: Apple ID Username:
    
    

    배포할 애플 계정을 입력합니다.

    [17:13:30]: ✅  Logging in with your Apple ID was successful
    [17:13:30]: Checking if the app '_' exists in your Apple Developer Portal...
    [17:13:31]: It looks like the app '_' isn't available on the Apple Developer Portal
    [17:13:31]: for the team ID '_' on Apple ID '_'
    [17:13:31]: Do you want fastlane to create the App ID for you on the Apple Developer Portal? (y/n)
    
    

    앱이 이미 실서버에 있는 경우에는 나타나지 않을 수 있지만, 그렇지 않은 경우에는 애플 개발자 계정에 앱 아이디를 자동으로 생성해 줍니다.

    그 외 설정을 입력하면 fastlane이 자동으로 생성됩니다.

     

    fastlane 을 설치하고 배포하면, 폴더에 dSym 등이 들어가서 깃이 더러워질 수 있습니다. fastlane 관련 깃이그노어를 추가합니다.

    # Created by https://www.gitignore.io/api/fastlane
    # Edit at https://www.gitignore.io/?templates=fastlane
    
    ### fastlane ###
    # fastlane - A streamlined workflow tool for Cocoa deployment
    #
    # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
    # screenshots whenever they are needed.
    # For more information about the recommended setup visit:
    # https://docs.fastlane.tools/best-practices/source-control/#source-control
    
    # fastlane specific
    fastlane/report.xml
    
    # deliver temporary files
    fastlane/Preview.html
    
    # snapshot generated screenshots
    fastlane/screenshots/**/*.png
    fastlane/screenshots/screenshots.html
    
    # scan temporary files
    fastlane/test_output
    
    # End of https://www.gitignore.io/api/fastlane
    

     

    빌드 스크립트 세팅하기

    fastlane을 성공적으로 설치하면 fastlane/Fastfile 폴더에 다음과 같은 스크립트가 자동 생성되어 있을 것입니다.

    default_platform(:ios)
    
    platform :ios do
      desc "Push a new release build to the App Store"
      lane :release do
        build_app(scheme: "test")
        upload_to_app_store(skip_metadata: true, skip_screenshots: true)
      end
    end
    

     

    fastlane release 를 쓰면 앱을 빌드해서 앱스토어에 업로드를 하는 스크립트입니다.

    사이닝의 이슈가 없다면, 별도의 세팅 없이도

    fastlane release

    커맨드로 앱스토어까지 단번에 업로드 됩니다.

     

    버전 올리기

    앱스토어에 업로드하기 위해서는 버전을 한번씩 수정해 주어야 합니다.

    현재 버전을 읽고 자동으로 추가하는 커맨드를 만들어 보겠습니다.

    이때는 get_info_plist_value와 set_info_plist_value 함수를 활용하면 됩니다.

    https://docs.fastlane.tools/actions/get_info_plist_value/

    # This file contains the fastlane.tools configuration
    # You can find the documentation at https://docs.fastlane.tools
    #
    # For a list of all available actions, check out
    #
    #     https://docs.fastlane.tools/actions
    #
    # For a list of all available plugins, check out
    #
    #     https://docs.fastlane.tools/plugins/available-plugins
    #
    
    # Uncomment the line if you want fastlane to automatically update itself
    # update_fastlane
    
    default_platform(:ios)
    
    platform :ios do
      desc "Push a new release build to the App Store"
      lane :release do
        match(type: "appstore")
        build_app(workspace: "iOS-todoApp.xcworkspace", scheme: "iOS-todoApp")
        upload_to_app_store(skip_metadata: true, skip_screenshots: true)
      end
      lane :increase_build_number do
          identifier = get_info_plist_value(path: "./iOS-todoApp/Info.plist", key: "CFBundleVersion")
          new_identifier = (identifier.to_i + 1).to_s
          set_info_plist_value(path: "./iOS-todoApp/Info.plist", key: "CFBundleVersion", value: new_identifier)
          puts("버전 넘버 " + identifier + "가 " + new_identifier + "로 변경 되었습니다.")
      end
    end
    
    

     

    CFBundleVersion를 Info.plist 에서 가져오고, 스트링으로 된 번들 버전을 정수로 바꾼 뒤에 1을 대입해 다시 저장하는 코드입니다.

    다음과 같은 커맨드를 입력하면,

    fastlane increase_build_number

    다음과 같은 메시지가 뜨면서 빌드 넘버가 손쉽게 증가됩니다.

    [17:34:27]: fastlane detected a Gemfile in the current directory
    [17:34:27]: however it seems like you don't use `bundle exec`
    [17:34:27]: to launch fastlane faster, please use
    [17:34:27]: 
    [17:34:27]: $ bundle exec fastlane increase_build_number
    [17:34:27]: 
    [17:34:27]: Get started using a Gemfile for fastlane https://docs.fastlane.tools/getting-started/ios/setup/#use-a-gemfile
    [17:34:29]: ------------------------------
    [17:34:29]: --- Step: default_platform ---
    [17:34:29]: ------------------------------
    [17:34:29]: Driving the lane 'ios increase_build_number' 🚀
    [17:34:29]: ----------------------------------
    [17:34:29]: --- Step: get_info_plist_value ---
    [17:34:29]: ----------------------------------
    [17:34:29]: ----------------------------------
    [17:34:29]: --- Step: set_info_plist_value ---
    [17:34:29]: ----------------------------------
    [17:34:29]: 버전 넘버 4가 5로 변경 되었습니다.
    
    +------+----------------------+-------------+
    |             fastlane summary              |
    +------+----------------------+-------------+
    | Step | Action               | Time (in s) |
    +------+----------------------+-------------+
    | 1    | default_platform     | 0           |
    | 2    | get_info_plist_value | 0           |
    | 3    | set_info_plist_value | 0           |
    +------+----------------------+-------------+
    
    [17:34:29]: fastlane.tools finished successfully 🎉
    

    사이닝 이슈 해결하기

    fastlane release

    커맨드를 입력했을 때, 실무에서 쓰는 경우 사이닝 이슈가 나서 성공적으로 앱스토어에 올리지 않는 경우가 왕왕 있습니다. 사이닝에서 뭔가 오류(?)가 뜨는 경우인데요.

    fastlane은 사이닝하는 다음과 같은 방법을 제공합니다.

    https://docs.fastlane.tools/codesigning/getting-started/

    Match를 이용해 사이닝하는 방법

    팀별로 공유할 수 있는 프라이빗 깃에 사이닝 정보를 저장하고, 빌드시 해당 레포지토리에서 정보를 가져오고 사이닝과 프로비저닝을 필요시 철회해서 자동으로 커밋하는 방식입니다.

    match 를 사용할 경우, 존재하는 인증서를 리보크가 필요합니다만, 개발시 Xcode 사용하는 오토매틱 사이닝 옵션을 그대로 유지해도 되는 장점이 있으며, 간편하고 사이닝 오류가 덜 발생합니다.

    cert, sigh 를 이용해 사이닝 하는 방법

    존재하는 인증서를 리보크하지 않고 사용하는 방법입니다. 개인적으로는 추천하지 않습니다. 오류가 간헐적으로 발생해서 아카이브에서 빵꾸가 나고, Xcode의 사이닝 옵션을 마음대로 바꿔버리고, 프로비저닝 파일이 지속적으로 생성되어서 git 관리에 피곤함이 있습니다.

    Xcode 사이닝 피처를 사용하는 방법

    Xcode 의 오토메틱 사이닝을 해제하고, 매뉴얼로 바꿔서 하는 방법입니다. 새로운 팀원이 올때마다 인증서를 일일히 발급해줘야 하므로 fastlane 사용에 득보다 실이 많은 방법입니다.

    여기서는 match 를 이용해 사이닝을 처리하는 방법을 알아보겠습니다.

     

    match 로 사이닝 하기

    https://codesigning.guide/

    깃허브에 리포지터리를 프라이빗으로 생성하고, 해당 리포지터리를 클론합니다.

    클론한 곳에 가서 아래 커맨드를 실행합니다.

    match init

    WARNING: You are running Ruby 2.2.4, which has reached end-of-life and is no longer supported by Ruby Core.
    The Google Cloud API clients work best on supported versions of Ruby. It is strongly recommended that you upgrade to Ruby 2.4 or later.
    See https://www.ruby-lang.org/en/downloads/branches/ for more info on the Ruby maintenance schedule.
    To suppress this message, set the GOOGLE_CLOUD_SUPPRESS_RUBY_WARNINGS environment variable.
    [17:49:47]: fastlane match supports multiple storage modes, please select the one you want to use:
    1. git
    2. google_cloud
    
    

    저희는 깃에 세팅했으므로, 1을 입력합니다.

    [17:50:11]: Please create a new, private git repository to store the certificates and profiles there
    [17:50:11]: URL of the Git Repo: 
    

    생성한 레포지토리의 url 을 입력합니다.

    [17:50:34]: Successfully created './Matchfile'. You can open the file using a code editor.
    [17:50:34]: You can now run `fastlane match development`, `fastlane match adhoc`, `fastlane match enterprise` and `fastlane match appstore`
    [17:50:34]: On the first run for each environment it will create the provisioning profiles and
    [17:50:34]: certificates for you. From then on, it will automatically import the existing profiles.
    [17:50:34]: For more information visit https://docs.fastlane.tools/actions/match/
    
    

    이어서 새 인증서와 프로비저닝 프로파일을 올리기위해 다음 커맨드 중 하나를 입력합니다.

    match appstore
    match development
    

     

    [17:52:17]: Get started using a Gemfile for fastlane https://docs.fastlane.tools/getting-started/ios/setup/#use-a-gemfile
    WARNING: You are running Ruby 2.2.4, which has reached end-of-life and is no longer supported by Ruby Core.
    The Google Cloud API clients work best on supported versions of Ruby. It is strongly recommended that you upgrade to Ruby 2.4 or later.
    See https://www.ruby-lang.org/en/downloads/branches/ for more info on the Ruby maintenance schedule.
    To suppress this message, set the GOOGLE_CLOUD_SUPPRESS_RUBY_WARNINGS environment variable.
    [17:52:19]: Successfully loaded '/Users/sesang/Documents/fastlane-match-blog/Matchfile' 📄
    
    +--------------+--------------------------------------+
    |         Detected Values from './Matchfile'          |
    +--------------+--------------------------------------+
    | git_url      | _                        |
    | storage_mode | git                                  |
    | type         | development                          |
    +--------------+--------------------------------------+
    
    
    +-----------------------+--------------------------------------+
    |                  Summary for match 2.117.1                   |
    +-----------------------+--------------------------------------+
    | type                  | appstore                             |
    | readonly              | false                                |
    | storage_mode          | git                                  |
    | git_url               | __                         |
    | git_branch            | master                               |
    | shallow_clone         | false                                |
    | clone_branch_directly | false                                |
    | keychain_name         | login.keychain                       |
    | force                 | false                                |
    | force_for_new_devices | false                                |
    | skip_confirmation     | false                                |
    | skip_docs             | false                                |
    | platform              | ios                                  |
    | verbose               | false                                |
    +-----------------------+--------------------------------------+
    
    [17:52:20]: Cloning remote git repo...
    [17:52:20]: If cloning the repo takes too long, you can use the `clone_branch_directly` option in match.
    [17:52:21]: 🔓  Successfully decrypted certificates repo
    [17:52:21]: To not be asked about this value, you can specify it using 'username'
    [17:52:21]: Your Apple ID Username: 
    
    

    애플 아이디를 입력합니다.

    2
    [17:53:38]: To not be asked about this value, you can specify it using 'app_identifier'
    [17:53:38]: The bundle identifier(s) of your app (comma-separated): 
    

    앱의 번들 아이덴티파이어를 입력합니다.

    [17:56:36]: Successfully logged in
    [17:56:36]: Fetching profiles...
    [17:56:37]: Verifying certificates...
    [17:56:38]: No existing profiles found, that match the certificates you have installed locally! Creating a new provisioning profile for you
    [17:56:41]: Creating new provisioning profile for 'sesang06.iOS-todoApp' with name '_' for 'ios' platform
    [17:56:43]: Downloading provisioning profile...
    [17:56:43]: Successfully downloaded provisioning profile...
    [17:56:43]: Installing provisioning profile...
    [17:56:44]: Installing provisioning profile...
    [17:56:44]: Enter the passphrase that should be used to encrypt/decrypt your certificates
    [17:56:44]: This passphrase is specific per repository and will be stored in your local keychain
    [17:56:44]: Make sure to remember the password, as you'll need it when you run match on a different machine
    [17:56:44]: Passphrase for Git Repo: 
    

    다른 팀원이 해당 매치를 사용할 수 있도록 적절한 비밀번호를 입력합니다. fastlane 이 변경사항을 푸시까지 해주면서 매칭 프로파일 생성이 완료됩니다. 해당 레포지토리를 팀원에게 공유합니다.

     

    match 를 이용해 사이닝해 앱스토어에 배포하기

    match를 해서 업로드를 해봅시다!

    fastlane/Fastfile 파일에 match(type: "appstore") 를 빌드 전에 추가합니다.

    platform :ios do
      desc "Push a new release build to the App Store"
      lane :release do
        match(type: "appstore")
        build_app(workspace: "_.xcworkspace", scheme: "_")
        upload_to_app_store(skip_metadata: true, skip_screenshots: true)
      end
    end
    

     

    또 리포지터리 url 을 입력해야 합니다.

    fastlane 폴더에 Matchfile 파일을 생성하고 아래처럼 입력하고 저장합니다.

    git_url "https://github.com/매치파일 주소"
    

    이제

    fastlane release

    를 입력하면, 알아서 인증을 해주고 배포까지 끝마추어 줍니다.

    Xcode 에서 사이닝 관련 별다른 설정을 해줄 필요가 없습니다.

     

     

    더 가능한 것들

    기본적인 사이닝과 빌드 버전쪽만 했지만, fastlane 을 더 활용할 방법은 많습니다. 참고해서 연구할 만한 포스트를 첨부합니다.

Designed by Tistory.