(2).swift fastlane

2024. 5. 12. 21:15블로그/ios

fastlane 을 마무리 짓도록 하겠습니다. 

 

https://mint-soft.tistory.com/9

 

(1).swift fastlane 사용법

아이폰 빌드는 너무 귀찮은 작업도 많고 jenkins,circleci,github action 마다 처리 하는게 너무 제각각이어서 fastlane이 필수 아닌 필수가 되었습니다. 몇년간 아이폰 개발을 진행하면 정리하여서 템플릿

blog.mint-soft.com

1회차에서는 기본 fastlane 설정을 알아봤습니다. 

이제 실제로 배포 하는 방법을 적어보겠습니다. 

애플 이중인증도 이 방법으로 따라하시면 다 통과 될수 있습니다. 

###############################################################
# create key chain
###############################################################
def create_temp_keychain()
  @KEYCHAIN_PATH = File.expand_path("~/Library/Keychains/#{TEMP_KEYCHAIN_NAME}-db")
  create_keychain(
    name:TEMP_KEYCHAIN_NAME,
    default_keychain: false,
    unlock: true,
    timeout: 36000,
    lock_when_sleeps: true,
    password: TEMP_KEYCHAIN_PASSWORD,
    require_create: false
  )
end

###############################################################
# import p12
###############################################################
def import_p12()
  import_certificate(
    certificate_path: P12_FILE_PATH,
    certificate_password: P12_PASSWORD,
    keychain_name: TEMP_KEYCHAIN_NAME,
    keychain_password: TEMP_KEYCHAIN_PASSWORD
  )
end

###############################################################
# get api key
###############################################################
def get_api_key()
  @API_KEY = app_store_connect_api_key(
    key_id: APPLE_KEY_ID,
    issuer_id: APPLE_ISSUER_ID,
    key_content: APPLE_KEY_CONTENT,
    duration: 1200,
    in_house: false
  )
end

###############################################################
# get version
###############################################################
def init_versions()
  @VERSION = get_version_number( xcodeproj: XCODE_PROJECT, target: APP_TARGET)
  @BUILD_NUMBER = get_info_plist_value(path: APP_INFO_PLIST, key: "CFBundleVersion")
end

###############################################################
# get commit message
###############################################################
def init_commit()
  @GIT_COMMIT =  changelog_from_git_commits(
    commits_count: 10,
    pretty: "- %s",
    date_format: "short",
    match_lightweight_tag: false,
    merge_commit_filtering: "exclude_merges"
  )
end

###############################################################
# send slack
###############################################################
def send_slack(message)
   slack(
      slack_url: SLACK_URL,
      message: "#{message}\n앱정보=>build_type:#{@BUILD_TYPE},app_name:#{@BUILD_APP_NAME}\ncommit:#{@GIT_COMMIT}",
      success: true,
      channel: SLACK_CHANNEL,
      payload: {
        "Build Date" => Time.new.to_s,
      },
      default_payloads: [:git_branch, :git_author, :last_git_commit]
   )
end

###############################################################
# change app name
###############################################################
def change_app_name()
  update_info_plist(
    plist_path: APP_INFO_PLIST,
    display_name: @BUILD_APP_NAME
  )
end


###############################################################
# sign & update provisioning
###############################################################
def sigh_update_provisioning()
  #1.APP
  sigh(
    cert_id: CERT_ID,
    app_identifier: APP_IDENTIFIER,
    skip_certificate_verification: false,
    skip_install: false,
    api_key:@API_KEY,
    adhoc: @IS_AD_HOC,
    force: true)

  update_project_provisioning(
    build_configuration: APP_BUILD_CONF,
    target_filter: APP_TARGET,
    xcodeproj: XCODE_PROJECT,
  )

  #2.PUSH
  sigh(
    cert_id: CERT_ID,
    app_identifier: APP_PUSH_IDENTIFIER,
    skip_certificate_verification: false,
    skip_install: false,
    api_key:@API_KEY,
    adhoc: @IS_AD_HOC,
    force: true)

  update_project_provisioning(
    build_configuration: APP_BUILD_CONF,
    target_filter: PUSH_TARGET,
    xcodeproj: XCODE_PROJECT,
  )
end


###############################################################
# build
###############################################################
def build()
  build_app(
    scheme: APP_TARGET,
    workspace: XCODE_WORKSPACE,
    export_method: @BUILD_EXPORT_METHOD,
    codesigning_identity:CODE_SIGN_IDENTIFIER,
    include_bitcode: false,
    output_name: APP_OUTPUT_NAME,
    export_team_id:TEAM_ID,
    export_xcargs: "OTHER_CODE_SIGN_FLAGS=\"--keychain=#{@KEYCHAIN_PATH}\""
  )
end


###############################################################
# upload sentry
###############################################################
def updload_sentry()
  sentry_upload_dsym(
    auth_token: SENTRY_AUTH_TOKEN,
    org_slug: SENTRY_ORG_SLUG,
    project_slug: SENTRY_PROJECT_SLUG,
    dsym_path: APP_DSYM_OUTPUT_PATH
  )
end


###############################################################
# upload appcenter
###############################################################
def upload_appcenter()
  appcenter_upload(
    api_token: APPCENTER_API_TOKEN,
    owner_type: APPCENTER_OWNER_TYPE,
    owner_name: APPCENTER_PROJECT_SLUG,
    app_name: APPCENTER_APP_NAME,
    ipa: APP_OUTPUT_NAME,
    notify_testers: true,
    release_notes: @GIT_COMMIT
  )
end


###############################################################
# init build
###############################################################
def init_build(type)
  #종류에 따른 변수 초기화
  if(type == BUILD_TYPE_APPCENTER)
    @BUILD_EXPORT_METHOD = "ad-hoc"
    @IS_AD_HOC = true
    @BUILD_TYPE = BUILD_TYPE_APPCENTER
    @BUILD_APP_NAME = BUILD_APP_NAME_APPCENTER
  else
    @BUILD_EXPORT_METHOD = "app-store"
    @IS_AD_HOC = false
    @BUILD_TYPE = BUILD_TYPE_TESTFLIGHT
    @BUILD_APP_NAME = BUILD_APP_NAME_TESTFLIGHT
  end

  #init version
  #init_versions()

  init_commit()

  #send slack
  send_slack("#{@BUILD_TYPE} 빌드을 시작합니다.")
end

###############################################################
# start build
###############################################################
def start_build()
  #1.create key chain
  create_temp_keychain()

  #2.import p12
  import_p12()

  #3.get api key
  get_api_key()

  #4.sigin
  sigh_update_provisioning()

  #cocoapods
  cocoapods(
    clean_install: true,
    use_bundle_exec: false
  )


  #6.build
  build()

  #7.upload build ipa
  if(@BUILD_TYPE == BUILD_TYPE_APPCENTER)
    upload_appcenter()
  else
    testflight(
      skip_waiting_for_build_processing: true,
      skip_submission: true
    )
  end

  #9.send slack
  send_slack("#{@BUILD_TYPE} 빌드을 성공하였습니다.")
end

###############################################################
# fastlane lane function
###############################################################
platform :ios do
  lane :alpha do
    SLACK_URL  = "{incomming_webhook}"
    SLACK_CHANNEL  = "#build_iphone_beta"

    init_build(BUILD_TYPE_APPCENTER)
    start_build()
  end
  lane :beta do
    SLACK_URL  =  "{incomming_webhook}"
    SLACK_CHANNEL  = "#release-build-iphone"

    init_build(BUILD_TYPE_TESTFLIGHT)
    start_build()
  end
end

 

 

코드가 상당히 긴데요. 

 

1.먼저 lane의 함수 먼저 살펴 보겠습니다.

alpha는 appcenter로 업로는 하는 함수 입니다.

테스트플라이트는 애플에서 코드 분석하는 시간이 오래 걸려서 내부 테스트 용으로는 앱센터를 선택하여 진행하고 있습니다. 

다른 좋은것들 있으면 대체 하시면 됩니다.

 

beta는 실제로 테스트 플라이트에 업로드 하는 함수 입니다. 

모두 동일하게 슬랙으로 메시지를 전송하게 되어있습니다. 

슬랙은 incomming_webhook을 이용하여 채널명을 다르게 하여 빌드 될때 마다 메시를 전송하시면 됩니다. 

 

(0).빌드를 초기화 합니다. 

ad-hoc,app-store의 값을 설정하고 빌드할 파일의 이름도 정의해줍니다.

###############################################################
# init build
###############################################################
def init_build(type)
  #종류에 따른 변수 초기화
  if(type == BUILD_TYPE_APPCENTER)
    @BUILD_EXPORT_METHOD = "ad-hoc"
    @IS_AD_HOC = true
    @BUILD_TYPE = BUILD_TYPE_APPCENTER
    @BUILD_APP_NAME = BUILD_APP_NAME_APPCENTER
  else
    @BUILD_EXPORT_METHOD = "app-store"
    @IS_AD_HOC = false
    @BUILD_TYPE = BUILD_TYPE_TESTFLIGHT
    @BUILD_APP_NAME = BUILD_APP_NAME_TESTFLIGHT
  end

  #init version
  #init_versions()

  init_commit()

  #send slack
  send_slack("#{@BUILD_TYPE} 빌드을 시작합니다.")
end

 

 

(1).임시 키체인을 생성합니다. 

ci 툴에서는 키체인이 존재 하지 않으므로 빌드때 사용할 키체인을 임시로 생성을 합니다.

비밀번호는 임의로 사용하셔도 무방합니다. 1회성 키체인이 생성되므로 노출만 되지 않으면 상관 없습니다.

###############################################################
# create key chain
###############################################################
def create_temp_keychain()
  @KEYCHAIN_PATH = File.expand_path("~/Library/Keychains/#{TEMP_KEYCHAIN_NAME}-db")
  create_keychain(
    name:TEMP_KEYCHAIN_NAME,
    default_keychain: false,
    unlock: true,
    timeout: 36000,
    lock_when_sleeps: true,
    password: TEMP_KEYCHAIN_PASSWORD,
    require_create: false
  )
end

 

 

 

(2).다음 생성된 키체인에 p12 파일을 임포트 합니다. 

p12 파일을 소스코드안에 추가하는게 부담되시면 ci 툴의 variable 넣는곳이 있을겁니다. 

거기에 추가하셔도 됩니다. 

github action,circleci에서는 지원을 하고 있습니다. 

###############################################################
# import p12
###############################################################
def import_p12()
  import_certificate(
    certificate_path: P12_FILE_PATH,
    certificate_password: P12_PASSWORD,
    keychain_name: TEMP_KEYCHAIN_NAME,
    keychain_password: TEMP_KEYCHAIN_PASSWORD
  )
end

 

(3).appstore key를 가져옵니다.

api_key를 이용하여 SIGH를 진행할거기 때문에 매우 중요한 작업입니다.

 

###############################################################
# get api key
###############################################################
def get_api_key()
  @API_KEY = app_store_connect_api_key(
    key_id: APPLE_KEY_ID,
    issuer_id: APPLE_ISSUER_ID,
    key_content: APPLE_KEY_CONTENT,
    duration: 1200,
    in_house: false
  )
end

 

(4).sigh&provisioning을 수정합니다. 

인증서 정보를 설정하고 프로젝트의 provisioning을 업데이트 합니다.

push는 extension 프로젝트 이므로 추가로 extension이 있다면 마찬가지로 추가해줍니다.

 

###############################################################
# sign & update provisioning
###############################################################
def sigh_update_provisioning()
  #1.APP
  sigh(
    cert_id: CERT_ID,
    app_identifier: APP_IDENTIFIER,
    skip_certificate_verification: false,
    skip_install: false,
    api_key:@API_KEY,
    adhoc: @IS_AD_HOC,
    force: true)

  update_project_provisioning(
    build_configuration: APP_BUILD_CONF,
    target_filter: APP_TARGET,
    xcodeproj: XCODE_PROJECT,
  )

  #2.PUSH
  sigh(
    cert_id: CERT_ID,
    app_identifier: APP_PUSH_IDENTIFIER,
    skip_certificate_verification: false,
    skip_install: false,
    api_key:@API_KEY,
    adhoc: @IS_AD_HOC,
    force: true)

  update_project_provisioning(
    build_configuration: APP_BUILD_CONF,
    target_filter: PUSH_TARGET,
    xcodeproj: XCODE_PROJECT,
  )
end

(5).cocoapod 설치입니다. 

아이폰 개발자라면 따로 설명 드릴게 없네요. 

 

(6).ipa 파일을 생성하는 빌드단계입니다. 

키체인의 경로를 반드시 적어줘야합니다. 그래야 xcode가 어떤 키체인을 바라보는지 설정이 가능합니다.

설정 값들은 1회차에  설명되어있습니다. 

###############################################################
# build
###############################################################
def build()
  build_app(
    scheme: APP_TARGET,
    workspace: XCODE_WORKSPACE,
    export_method: @BUILD_EXPORT_METHOD,
    codesigning_identity:CODE_SIGN_IDENTIFIER,
    include_bitcode: false,
    output_name: APP_OUTPUT_NAME,
    export_team_id:TEAM_ID,
    export_xcargs: "OTHER_CODE_SIGN_FLAGS=\"--keychain=#{@KEYCHAIN_PATH}\""
  )
end

 

(7).앱센터 혹은 테스트플라이트로 업로드 합니다. 

 

###############################################################
# upload appcenter
###############################################################
def upload_appcenter()
  appcenter_upload(
    api_token: APPCENTER_API_TOKEN,
    owner_type: APPCENTER_OWNER_TYPE,
    owner_name: APPCENTER_PROJECT_SLUG,
    app_name: APPCENTER_APP_NAME,
    ipa: APP_OUTPUT_NAME,
    notify_testers: true,
    release_notes: @GIT_COMMIT
  )
end

 

(8).추가로 sentry에 업로드 하실려면 아래의 코드를 입력하여 센트리로 dsym 업로드 하면 됩니다. 

###############################################################
# upload sentry
###############################################################
def updload_sentry()
  sentry_upload_dsym(
    auth_token: SENTRY_AUTH_TOKEN,
    org_slug: SENTRY_ORG_SLUG,
    project_slug: SENTRY_PROJECT_SLUG,
    dsym_path: APP_DSYM_OUTPUT_PATH
  )
end

 

 

이상으로 ci에서도 잘돌아가는 아이폰 fastlane에 대해 알아봤습니다. 

한번 구축 제대로 해놓으면 정말 편리하게 개발을 진행할수 있습니다.

 


민트소프트는 모바일 앱 개발 전문회사입니다. 하이브리드앱,크로스플랫폼,네이티브영역 전반에 걸친 모바일 앱을 개발하고 있습니다.

하이브리드는 민트앱이라는 솔루션을 보유하고 있어서 Time To Market에 매우 유리합니다. 

언제는 찾아주시면 신속하고 빠른 상담을 진행하도록 하겠습니다. 

 

https://www.mint-soft.com 

사업자 정보 표시
민트소프트 | 최강식 | 경상북도 구미시 구미대로 350-27 경북산학융합원 512호 | 사업자 등록번호 : 535-81-00882 | TEL : 070-8809-1512 | Mail : choiks14@mint-soft.com | 통신판매신고번호 : 호 | 사이버몰의 이용약관 바로가기

'블로그 > ios' 카테고리의 다른 글

(1).swift fastlane 사용법  (0) 2024.05.12
애플 앱 키 생성하는 방법  (0) 2024.05.12
테스트 플라이트 사용법  (0) 2024.05.12
ios UDID 얻는 방법  (0) 2024.05.12