-
fastlane match를 통해 팀원들과 인증서 공유하기Fastlane 2024. 6. 3. 18:53
안녕하세요. 그린입니다 🍏
이번 포스팅에서는 Fastlane match를 사용하여 팀원들과 인증서를 공유하고 또 배포까지 한번 해보도록 하겠습니다 🙋🏻
match?
우선, 팀원들과 협업하면서 Fastlane을 이용하고 있었을때 기존이라면 앱 배포를 위해 테스트 플라이트에 올리거나 애플 로그인 및 인증서과 필요한 개발 환경 구축을 위해서 아래와 같이 하고 있었을거에요 🤔
1️⃣ 해당 앱 등록을 한 애플 디벨로퍼 계정 소유주가 다른 팀원들의 CSR을 Apple developer의 Certificate에 등록
2️⃣ 인증서 다운로드하여 팀원에게 전달 > 팀원은 해당 인증서 키체인 등록 및 Xcode 연결
3️⃣ 팀원의 UDID를 Apple developer에서 Devices에 등록
4️⃣ Provisioning Profiles 생성 혹은 업데이트
이 과정을 사용하는 경우가 일반적입니다.
즉, 해당 팀원들이 업데이트될때마다 저 Provisioning Profiles를 업데이트하여 다시 Xcode에 import 시켜줘야하죠.
이 Provisiong Profiles을 통해서 배포가 이뤄집니다.
아래 그림은 Provisioning Profiles이 아까 위 스텝에서 말한 App ID / Certificates / Devices로 이뤄져있음을 보여주는 그림입니다.
그렇기에 이 작업은 꽤나 번거롭죠.
실수할 여지도 분명히 존재하고, 팀원들의 디바이스가 변경될때마다 업데이트도 시켜줘야하기에 생각보다 팀원이 많을수록 관리가 더욱 어려워집니다.
또한, 배포 인증서 발급의 수량도 리미트가 있기에 각자 이 인증서를 따로 발급받는 구조가 갈 경우에는 더욱 신경쓸게 많아지죠.
그래서 Fastlane에서는 match라는것을 통해 이 Certificate & Provisioning profile을 원격 레포에 저장해 팀원들끼리도 같은 인증서를 공유하며 사용할 수 있도록 도와줍니다.
즉, 이 Fastlane의 match를 활용한다면 보다 편리하게 인증서를 공유할 수 있겠죠?
그럼 이 match가 어떤 역할을 하는지 알았으니 어떻게 사용하는지 알아보겠습니다!
match 사용하기
1️⃣ 원격 레포 생성하기
우선 이 인증서들을 보관하고 있을 원격 레포 하나를 만들어야 합니다.
인증서는 암호화가 자동으로 되지만 private으로 만들어 볼께요!
추가로, 팀원들을 해당 레포에 초대해줘야합니다. (프라이빗이기에)
그래야 추후 인증서를 팀원들도 해당 레포에 접근하여 명령을 통해 가져올 수 있습니다.
2️⃣ match 초기화 및 Matchfile 구성하기
아래 match 초기화 명령어를 해당 match를 적용시킬 레포(여러분들의 프로젝트 앱 레포)에서 실행해줍니다.
fastlane match init
그럼 이렇게 fastlane match를 지원할 여러 저장소 중 선택하라고 나옵니다.
우리는 git 원격 저장소를 이용할것이니 1을 선택해주죠!
그럼 이렇게 해당 깃 원격 레포의 URL을 입력하라고 나올테고 입력하면 정상적으로 초기화가 된걸 확인할 수 있습니다.
그리고, 이제 해당 프로젝트 디렉토리에서 fastlane 폴더로 가보시면 아래와 같이 Matchfile이 생성되어 있을거에요 😃
해당 Matchfile을 이제 적절히 수정하여 인증서를 생성해야 합니다.
먼저 Matchfile을 열어 아래와 같이 편집해볼께요.
git_url("https://github.com/GREENOVER/matchTet") storage_mode("git") type("development") # The default type, can be: appstore, adhoc, enterprise or development app_identifier(["com.mashup.seeYouAgain-dev", "com.mashup.seeYouAgain"]) username("humains@nate.com") # 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
여기서 중요한 부분인 type부터 보겠습니다.
type은 해당 파일의 유형으로 만약 개발용 인증서가 필요하면 지금처럼 development로 배포용 인증서가 필요하면 appstore로 변경하면 됩니다.
그리고 해당 프로젝트 앱의 번들 ID와 같은 App ID를 app_identifier에 설정합니다.
여러 프로젝트 타겟을 가지고 있다면 배열 형태이니 다중으로 설정할 수 있습니다.
그리고 해당 인증서 소유자의 애플 ID를 username으로 설정해줍니다.
이 username을 통해 애플 디벨로퍼에서 인증서 생성 및 가져오기를 해줍니다.
3️⃣ match 인증서 생성 및 업로드하기
이제 Matchfile이 설정되었으면 이 Matchfile을 통해 match 인증서를 생성해야 합니다.
사전 작업으로 만약 배포 인증서는 아까 위에서도 말했듯이 갯수 제한이 있기에 기존에 존재한걸 삭제하시고 싶다면 아래 명령어를 통해 삭제하시고 진행해도 무방합니다.
fastlane match nuke distribution
즉, match로 통일화 시켜 앞으로 관리하실거면 한번 기존 인증서를 삭제해놓고 가는것도 좋을것 같습니다.
이제 새 인증서를 생성하기 위해 아래와 같이 프로젝트 디렉토리 터미널에서 명령을 입력해줍니다.
fastlane match development
이렇게 명령을 실행하면 개발용 인증서가 생성이 될것이고 해당 인증서는 우리가 설정해둔 원격 레포에 들어가게 됩니다.
만약 개발용 + 배포용 인증서 모두 들어가야한다면, 한 인증서부터 생성해서 업로드하고 다시 Matchfile에서 type을 변경해서 match를 돌려서 생성 및 업로드하면 됩니다.
어차피 한번만 만들어두면 되니까요!
아..! 이 스텝을 진행하면서 터미널에서 키를 암호화하기 위한 비밀번호 입력을 요구할 수 있는데 기입하면서 해당 값을 다시 볼 순 없으니 어디 메모해두는편이 좋습니다.
추가로, 애플 계정의 로그인을 위해 Apple ID 및 인증 로그인 시도도 시키는대로 따라 해주면 됩니다.
이렇게까지 모두 마쳤다면 아래와 같이 이제 해당 원격 레포에 개발용/배포용 인증서가 업로드되어 있는걸 볼 수 있어요!
이제 팀원들끼리 이 인증서를 사용하는겁니다 😃
더불어서 이렇게 match 인증서가 애플 디벨로퍼 > Profiles에 업로드되있는것도 확인할 수 있습니다.
그럼 이렇게 match를 통해 인증서를 구성 및 생성하여 업로드하는것까지 완료되었으면 팀원들 입장에서 이 인증서를 사용해봐야겠죠?
즉, 공유된 원격 레포에 있는 인증서를 팀원들도 본인의 로컬로 가져와서 심고 배포시에도 이용해볼 수 있어야 합니다.
팀원들 입장에서 공유 인증서 받아오고 사용하기
팀원들은 이제 아래와 같이 읽기 전용으로 개발 및 배포 인증서를 다운로드 해올 수 있습니다.
fastlane match development --readonly fastlane match appstore --readonly
만약 아래와 같은 에러를 만날 수도 있는데요.
즉, 터미널에서 알려주는 친절한 클론 명령어를 입력합니다.
도중에 아래와 같이 UserName과 Password를 물어볼텐데요.
UserName에는 본인의 깃헙 ID를 넣고 Password에는 깃헙에서 발급받은 PAT(Personal Access Token)을 입력합니다.
설정이 완료되었으면 다시 fastlane match를 통해 인증서를 받아옵니다.
여기까지 진행하고 에러가 나지 않았다면 이제 정상적으로 인증서가 다운로드 되었다고 보면 됩니다.
이제 프로젝트에서 앱을 열고 사이닝 부분에 들어가봅니다.
그럼 위와 같이 match 인증서가 잘 들어온것을 확인할 수 있어요!
이제 개발 및 배포시에 팀원들도 해당 인증서를 선택하여 사용하면 됩니다.
이제 하나 더 해볼건데요.
Tuist를 통해 프로젝트 앱 생성 시 오토 사이닝을 풀고 해당 개발용 인증서로 심어주는것과 fastlane에서 앱을 빌드하고 테스트 플라이트에 업로드하는 과정에서 match를 통해 배포용 인증서를 가져와서 사용하는것도 다뤄볼께요!
Tuist를 통해 프로젝트 앱 생성 시 개발용 인증서 설정하기
Tuist edit을 통해 Tuist 구성 편집을 열고 해당 프로젝트 타겟 생성 시 Settings 파라미터에 설정을 담아주면 됩니다.
import ProjectDescription import ProjectDescriptionHelpers let project = Project.make( name: "App", targets: [ .make( name: "Prod-Gabbangzip", product: .app, bundleId: "com.mashup.gabbangzip", infoPlist: .file(path: .relativeToRoot("Projects/App/Info.plist")), sources: ["Sources/**"], resources: ["Resources/**"], dependencies: [ .project(target: .coreKit, projectPath: .core), .project(target: .designSystem, projectPath: .designSystem), .project(target: .appCoordinator, projectPath: .coordinator), .external(externalDependency: .composableArchitecture) ], settings: .settings( base: [ "ASSETCATALOG_COMPILER_APPICON_NAME": "ProdAppIcon", "DEVELOPMENT_TEAM": "KEMFT3K // 변경 😃", "CODE_SIGN_STYLE": "Manual", "PROVISIONING_PROFILE_SPECIFIER": "match Development com.mashup.gabbangzip", "CODE_SIGN_IDENTITY": "Apple Development: green (1KNEF3F) // 변경 😄" ], configurations: [ .release(name: .release, xcconfig: "./xcconfigs/Gabbangzip.release.xcconfig") ] ) ), .make( name: "Dev-Gabbangzip", product: .app, bundleId: "com.mashup.gabbangzip-dev", infoPlist: .file(path: .relativeToRoot("Projects/App/Info.plist")), sources: ["Sources/**"], resources: ["Resources/**"], dependencies: [ .project(target: .coreKit, projectPath: .core), .project(target: .designSystem, projectPath: .designSystem), .project(target: .appCoordinator, projectPath: .coordinator), .external(externalDependency: .composableArchitecture) ], settings: .settings( base: [ "ASSETCATALOG_COMPILER_APPICON_NAME": "DevAppIcon", "DEVELOPMENT_TEAM": "KEMFT3K // 변경 😃", "CODE_SIGN_STYLE": "Manual", "PROVISIONING_PROFILE_SPECIFIER": "match Development com.mashup.gabbangzip-dev", "CODE_SIGN_IDENTITY": "Apple Development: green (1KNEF3F) // 변경 😄" ], configurations: [ .debug(name: .debug, xcconfig: "./xcconfigs/Gabbangzip.debug.xcconfig") ] ) ), ], additionalFiles: [ "./xcconfigs/Gabbangzip.shared.xcconfig" ] )
참고로, make 메서드는 자체적으로 익스텐션해서 만든것으로 그냥 원래 하시는것처럼 Project 및 Target을 초기화 하시면 됩니다.
핵심은 settings를 보시면 CODE_SIGN_STYLE을 Manual로 주어 오토 사이닝을 꺼줬습니다.
그리고 프로비저닝 프로필과 코드 사인 아이덴티티를 우리가 생성한 match 인증서 정보와 소유주의 정보로 변경해서 추가해줘야 합니다.
저기서는 제가 임시로 넣어둔것으로 각자의 정보로 변경하셔야 해요!
이렇게 하고 프로젝트를 생성하면 오토 사이닝이 꺼지고 프로비저닝은 설정한 개발용 인증서로 심어져서 프로젝트가 생성되게 됩니다.
배포용 인증서로 생성하지 않고 개발용 인증서로 생성한 이유는, 배포는 fastlane을 통해 진행할거라 개발중에는 개발용 인증서로만 사용해도 무방하기에 그렇습니다 😃
이제 다음으로, fastlane을 통해서 match를 곁들여 배포하는 과정을 볼까요?
fastlane을 통해 배포하기 (with match)
Fastfile을 통해 배포 스크립트를 구성해야겠죠?
# 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 # update_fastlane() default_platform(:ios) 🙋🏻 Prod + Dev 모두 배포 platform :ios do desc "Push a new beta build to TestFlight" lane :beta do |options| 🙋🏻 Prod 배포 update_and_build_app("Prod") upload_to_testflight( app_identifier: "com.mashup.gabbangzip", api_key_path: "fastlane/key.json", skip_waiting_for_build_processing: true ) 🙋🏻 Dev 배포 update_and_build_app("Dev") upload_to_testflight( app_identifier: "com.mashup.gabbangzip-dev", api_key_path: "fastlane/key.json", skip_waiting_for_build_processing: true ) end end ... 🙋🏻 업데이트 및 앱 빌드 def update_and_build_app(scheme = "") case scheme when "Prod" 😃😃😃😃😃😃 match( type: "appstore", app_identifier: "com.mashup.gabbangzip", force_for_new_devices: true, readonly: true ) build_app( workspace: "Gabbangzip.xcworkspace", output_directory: "./Projects/App/Outputs/Archives/PROD", scheme: "#{scheme}-Gabbangzip", xcargs: "-allowProvisioningUpdates" ) when "Dev" 😃😃😃😃😃😃 match( type: "appstore", app_identifier: "com.mashup.gabbangzip-dev", force_for_new_devices: true, readonly: true ) build_app( workspace: "Gabbangzip.xcworkspace", output_directory: "./Projects/App/Outputs/Archives/DEV", scheme: "#{scheme}-Gabbangzip", xcargs: "-allowProvisioningUpdates" ) else throw end end
빌드 및 마케팅 버전 업데이트 및 설정이라던지, 깃 태그를 생성한다던지, xcconfig를 받아오고 업데이트 하는 등의 코드들은 생략하고 핵심적인 부분만 가져왔습니다.
여기서 먼저 fastlane beta를 돌리면 Prod와 Dev 모두 배포되는 형식인데요.
Prod가 먼저 그리고 Dev가 후에 배포되지만 순서는 같습니다.
가장 먼저, update_and_build_app 메서드를 돕니다.
여기서 match를 이용하고 있어요!
match 시킬 타입은 배포이니 appstore로 담고 app_identifier는 해당 AppID로 담습니다.
그리고 readonly하여야하니 true로 설정해주죠.
만약 새 추가된 장치가 있을때 자동으로 반영하고자 한다면 force_for_new_devices를 true로 설정해줍니다.
그리고 match 후 build_app을 통해 앱을 빌드 시킵니다.
workspace부터 scheme까지 적절히 타겟과 스킴에 맞게 넣어줍니다.
그 후 upload_to_testflight를 통해 해당 앱 스토어 커넥트 사이트에 테플 업로드를 진행해줍니다.
여기서 특이한 부분은 api_key_path가 존재하는데요.
이 설정을 넣은 이유는, 현재 공유된 인증서로 사용하죠.
즉, 소유자가 본인이 아니기에 해당 소유자의 애플 계정 ID와 비밀번호가 필요한데 매번 그럴 수 없잖아요?
그렇기에 해당 앱 스토어 커넥트 사이트의 API를 이용해 이중인증도 스킵하면서 업로드할 수 있습니다.
쉽게 사용해볼 수 있어요.
우선, App Store Connect로 들어갑니다.
그리고 이 사용자 및 액세스 > 통합으로 들어가면 App Store Connect API 탭이 존재해요.
여기서 팀 키를 생성하면 됩니다.
이름과 권한을 주고 키를 생성하면 아래와 같이 키가 생성됩니다.
이렇게 API 사용이 필요한 Issuer ID와 키 ID등을 볼 수 있고, 가장 중요한 프라이빗 키가 생성 시 나타나니 이건 어디 복사하셔야 합니다.
완료되면 Github의 PAT처럼 볼 수 없기때문이죠.
여기까지 되었다면, 이제 다시 프로젝트 디렉토리에서 fastlane 폴더로 갑니다.
거기서, key.json이라는 이름으로 파일을 만들어줘요.
이름은 변경되어도 괜찮습니다!
형식은 아래처럼 파일을 구성합니다.
{ "key_id": "keyID", "issuer_id": "issuerID", "key": "-----BEGIN PRIVATE KEY-----\n프라이빗키\n-----END PRIVATE KEY-----", "duration": 500, "in_house": false }
여기서 key는 위 API 키를 사이트에서 만들고 확인할때 ---- 다음 줄바꿈이 되어서 보여졌을텐데요.
이 적용을 그대로 해줘야하기에 줄바꿈 문자를 넣어준겁니다.
자 이제 해당 파일이 만들어졌으니, 테플 업로드 시 해당 파일의 정보를 api_key_path로 읽어 사용하게 됩니다.
그럼 match부터 배포까지 일원화로 아주 쉽게 진행되는걸 볼 수 있습니다 😃
마무리
인증서 스트레스 받지말고 match로 관리해보시죠! 👍
레퍼런스
'Fastlane' 카테고리의 다른 글
fastlane으로 Firebase App Distribution 자동화 🤖 (61) 2024.01.15 fastlane - IPA & dSYM 파일 경로 변경하기 (9) 2023.05.11 Developer Portal Team ID와 AppStore Connect Team ID 찾기 (4) 2023.04.20 fastlane으로 Debug / Release 빌드 자동 배포하기 (0) 2022.01.23