-
[Github action IOS] CI/CD Testflight 자동화 배포 하기개발/Swift 2022. 5. 19. 12:44
테스트플라이트 배포까지 여러 정보들을 필요로한다.
- Certification & Provisioning profile 암호화 파일
- Certification & Provisioning profile 암호 비밀번호
- Certification 비밀번호
- ExportOptions.plist
- Appstore issuer id
- Appstore api key
- Appstore api 프라이빗키
하나하나 준비하여 세팅해보도록 하자.
Certification & Provisioning profile 암호화 파일 , Certification 비밀번호, Certification & Provisioning profile 암호 비밀번호
Certification 은 키체인에서 찾아 내보내기해야한다. 내보내기 위해서 login - My Certificates로 가준다.
내보내기를 할때 Certification 비밀번호를 입력하게 될것이다.
해당 비밀번호를 저장해두자
Provisioning profile 은 developer.apple.com 에가서
해당 앱이 사용중인 profile을 다운 받으면 된다.
이렇게 Certification & Provisioning profile 두개가 준비되었다.
이 두개를 암호화 해서 git 을통해 원격으로 보낼것이다.
암호화를 하기 위해서는 gnupg라는것을 사용하게 된다.
brew 를 통해 인스톨 한다
brew install gnupg2
인스톨이후에 암호화를 하려면
gpg -c certification파일명.p12 gpg -c profile파일명.mobileprovision
을통해 암호화를 하게 된다. 그러면 passphrase를 입력하게 되는데 (Certification & Provisioning profile 암호 풀 비밀번호) 추후에 필요하므로 그것을 저장해두자.
암호화가 끝나면 .gpg로 끝나는 파일이 각각 생성된다.
certification파일명.p12.gpg
profile파일명.mobileprovision.gpg
이 두 파일을 프로젝트폴더/.github/secrets/ 안에 넣어준 후 git push 를 하여 저장소에 넣어줘야한다.
이렇게 Certification & Provisioning profile 암호화 파일 , Certification 비밀번호, Certification & Provisioning profile 암호 비밀번호 세가지가 준비되었다.
ExportOptions.plist
해당 파일은 archive 파일을 가지고 ipa 파일을 만들때 사용된다.
ipa파일은 testflight 배포를 위해 필요하다.
ExportOptions.plist 파일을 얻기 위해서는 수동으로 한번 작업을 해야한다.
xcode를 통해 아카이브를 한후 window→organizer→DistributeApp 을 누른후
App store connect → Export 를 누르면 ExportOptions.plist 파일이 생성된다.
해당 파일을 git 을통해 push 하여 올려주면 된다. 경로는 프로젝트 루트경로(workspace와 동일path)에 넣어준다.
Appstore issuer id , Appstore api key , Appstore api 프라이빗키
앱스토어 관련 정보는 마지막 testflight배포를 하기 위해 필요하다. 위 정보를 얻기위해
appstoreconnect로 간다.
사용자및 액세스 → 키로 이동하면 키를 만들수있다.
원하는 이름과 액세스를 지정해준다
그러면 private key를 단 한번 볼수있다. 이떄 이 private 키를 저장해두자.
그리고 issuer id 와 api key 를 볼수있다.
Secrets
이렇게 모든 정보들이 준비가 되었다. 이 정보들중 몇가지들을 repository(배포할) secrets 에 넣어줘야한다.
secrests 은 repository setting → Secrets → actions 에가서 Newrepository secret 을 눌러 생성해준다.
원하는 키값을 넣어주고 값을 넣어준다.
이렇게 총 6가지가 나오는데 PERSONAL_ACCESS_TOKEN 은 내 프로젝트에서 private pod 을 의존하고 있기 때문에 필요하다. private pod 을 install 하기위해서는 PAT가 필요하다. 만약 private repo를 쓰고 있지 않다면 필요없다.
Workflow 작성
이제 마지막으로 workflow를 작성해보자.
workflow는 action - new workflow에서 생성 가능하다.
on: push: branches: [ release ]
처음으로 브랜치 설정을 해주는데 위와 같이 지정해주면
release 브랜치로 push 되는 순간 action이 발생된다. 할 작업이 testflight 배포이므로
release 브랜치로 지정해줬다.
jobs: build: runs-on: macos-latest env: XC_PROJECT: ${{ '프로젝트명.xcworkspace' }} XC_SCHEME: ${{ '프로젝트명' }} XC_CONFIGURATION: ${{ 'Automation' }} XC_ARCHIVE_PATH: ${{ '프로젝트명.xcarchive' }} XC_EXPORT_PATH: ${{ './artifacts' }} KEYCHAIN: ${{ 'temp.keychain' }} ENCRYPTED_CERTS_FILE_PATH: ${{ '.github/secrets/Certification.p12.gpg' }} DECRYPTED_CERTS_FILE_PATH: ${{ '.github/secrets/Certification.p12' }} ENCRYPTED_PROVISION_FILE_PATH: ${{ '.github/secrets/Profile명.mobileprovision.gpg' }} DECRYPTED_PROVISION_FILE_PATH: ${{ '.github/secrets/Profile명.mobileprovision' }} SIGNING_DECODE_PWD: ${{ secrets.SIGNING_DECODE_PWD }} CERTS_PWD: ${{ secrets.CERTS_PWD }} PERSONAL_ACCESS_TOKEN : ${{ secrets.PERSONAL_ACCESS_TOKEN }}
env 설정을 해주자. 아까 secrets에서 적었던 것들을 여기에 지정해주면 된다.
SIGNING_DECODE_PWD: ${{ secrets.SIGNING_DECODE_PWD }} CERTS_PWD: ${{ secrets.CERTS_PWD }} PERSONAL_ACCESS_TOKEN : ${{ secrets.PERSONAL_ACCESS_TOKEN }}
간단히 secrets.KEY 를 통해 아까 지정한 secrets value를 받아올수 있다.
XC_PROJECT: ${{ '프로젝트명.xcworkspace' }} XC_SCHEME: ${{ '프로젝트명' }} XC_CONFIGURATION: ${{ 'release' }} XC_ARCHIVE_PATH: ${{ '프로젝트명.xcarchive' }}
본인 프로젝트 명에 맞게 지정해준다. 의존하는 pod 이 있다면 project가 아닌 workspace를 써야한다
XC_CONFIGURATION 은 아카이브할때 build configuration을 의미한다. release 를 지정해주면 된다.
KEYCHAIN: ${{ 'temp.keychain' }} ENCRYPTED_CERTS_FILE_PATH: ${{ '.github/secrets/Certification.p12.gpg' }} DECRYPTED_CERTS_FILE_PATH: ${{ '.github/secrets/Certification.p12' }} ENCRYPTED_PROVISION_FILE_PATH: ${{ '.github/secrets/Profile명.mobileprovision.gpg' }} DECRYPTED_PROVISION_FILE_PATH: ${{ '.github/secrets/Profile명.mobileprovision' }}
아카이브 전에 git action 이 돌고있는 가상환경 안에서 키체인 설정을 해줘야 하는데 그때 사용될 키 체인이 필요하다. 이름은 자유롭게 지어도 된다.
아까 암호화하여 git에 올려주었던 Certificate & Profile 파일들의 경로를 ENCRYPTED_CERTS_FILE_PATH , ENCRYPTED_PROVISION_FILE_PATH 에 넣어줬다.
그리고 복호화 될때 파일명을 미리 적어두었다
DECRYPTED_CERTS_FILE_PATH , DECRYPTED_PROVISION_FILE_PATH
앱스토어 관련한 secrets는 env 세팅없이 직접사용해줄것이다.
steps에서는 이제 실제 작업할 내용들을 적어두게 된다.
단계별로
- checkout
- credential setup
- pod install
- create keychain
- code signing
- archive
- export
- testflight
로 나뉘어진다.
checkout & credential setup & pod install
steps: - name: "Checkout" uses: actions/checkout@v3 - name: :"Credentials setup" run: | git config --global url."".insteadOf "<https://github.com/>" - name: "Pod install" run: | pod install --repo-update --clean-install
actions/checkout@v3 브랜치로 checkout을 한다. 이것은 디폴트로 지정되있는것을 쓰면 될것이다.
Credentials setup 에서는 url 세팅을 해줬는데
pod install 을 할때 private repo 를 의존하는경우 접근 권한이 필요 하지만 git action 이 돌아가는 환경에서는 내 git 계정의 정보가 저장되어있지 않기 때문에 접근이 불가능 하다
이를 해결하기 위해서는 PAT를 주소에 넣어주는방법이 있다
따라서 podfile 에서 지정된 private repo url이 https://github.com/PrivateRepo.git 이라면
나중에 pod install 이 될때 해당 주소를
https://PERSONAL_ACCESS_TOKEN@github.com/PrivateRepo.git 으로 변경해주는 설정을 넣어 둔것이다.
Keychain
- name: "Keychain" run: | security create-keychain -p "" "$KEYCHAIN" security list-keychains -s "$KEYCHAIN" security default-keychain -s "$KEYCHAIN" security unlock-keychain -p "" "$KEYCHAIN" security set-keychain-settings -lut 1200 security list-keychains
여기서는 keychain을 아까 지정한 이름대로 만들어준다.
여기서 주의할점이 하나있는데 바로 unlock 이다.
security unlock-keychain -p "" "$KEYCHAIN"
keychain이 unlock 이 되어있어야 이후 아카이브할때
코드사이닝을 성공할수있다. 만약 lock이 되어있다면 Archive 가 끝나지 않고 계속 돌게된다.
기본적으로 unlock을 하면 300초를 유지시켜주고 이후에는 다시 lock이 걸린다.
만약 unlock 이후에 300초가 지났다면 lock이 걸리고 그 이후에는 아카이브에 실패할것이다.
그래서 만약 archive 작업이 오래걸린다면 unlock 유지 시간을 늘려야한다
security set-keychain-settings -lut 1200
위와 같이 지정해줘서 원하는 유지시간으로 늘릴수 있다.
code signing
- name: "Configure Code Signing" run: | gpg -d -o "$DECRYPTED_CERTS_FILE_PATH" --pinentry-mode=loopback --passphrase "$SIGNING_DECODE_PWD" "$ENCRYPTED_CERTS_FILE_PATH" gpg -d -o "$DECRYPTED_PROVISION_FILE_PATH" --pinentry-mode=loopback --passphrase "$SIGNING_DECODE_PWD" "$ENCRYPTED_PROVISION_FILE_PATH" security import "$DECRYPTED_CERTS_FILE_PATH" -k "$KEYCHAIN" -P "$CERTS_PWD" -A security set-key-partition-list -S apple-tool:,apple: -s -k "" "$KEYCHAIN" mkdir -p "$HOME/Library/MobileDevice/Provisioning Profiles" echo `ls .github/secrets/*.mobileprovision` for PROVISION in `ls .github/secrets/*.mobileprovision` do UUID=`/usr/libexec/PlistBuddy -c 'Print :UUID' /dev/stdin <<< $(security cms -D -i ./$PROVISION)` cp "./$PROVISION" "$HOME/Library/MobileDevice/Provisioning Profiles/$UUID.mobileprovision" done
가장먼저 암호화 해둔 파일들을 가져와서 복호하 하는 작업을한다.
gpg -d -o "$DECRYPTED_CERTS_FILE_PATH" --pinentry-mode=loopback --passphrase "$SIGNING_DECODE_PWD" "$ENCRYPTED_CERTS_FILE_PATH" gpg -d -o "$DECRYPTED_PROVISION_FILE_PATH" --pinentry-mode=loopback --passphrase "$SIGNING_DECODE_PWD" "$ENCRYPTED_PROVISION_FILE_PATH"
이후에는 Certification을 키체인에 import 한다. set-key-partion-list 를 하게되면 접근권한 허용 dialog가 뜨지 않게하기위해 필요하다 한다.
security import "$DECRYPTED_CERTS_FILE_PATH" -k "$KEYCHAIN" -P "$CERTS_PWD" -A security set-key-partition-list -S apple-tool:,apple: -s -k "" "$KEYCHAIN"
mkdir -p "$HOME/Library/MobileDevice/Provisioning Profiles" echo `ls .github/secrets/*.mobileprovision` for PROVISION in `ls .github/secrets/*.mobileprovision` do UUID=`/usr/libexec/PlistBuddy -c 'Print :UUID' /dev/stdin <<< $(security cms -D -i ./$PROVISION)` cp "./$PROVISION" "$HOME/Library/MobileDevice/Provisioning Profiles/$UUID.mobileprovision" done
마지막으로 Profile 을 가져온후 파일명에 UUID를 넣어주는 작업을 한다.
usr/Libarary/MobileDevice/ProvisioningProfiles 폴더 경로에 가보면
실제로 이런 파일이 생성 되고있었음을 확인할수 있었다.
Archive & Export
- name: "Archive" run: | xcodebuild clean archive -workspace "$XC_PROJECT" -scheme "$XC_SCHEME" -configuration "$XC_CONFIGURATION" -archivePath "$XC_ARCHIVE_PATH" "OTHER_CODE_SIGN_FLAGS=--keychain '$KEYCHAIN'" mkdir artifacts - name: "EXPORT" run: | xcodebuild -exportArchive -archivePath "$XC_ARCHIVE_PATH" -exportOptionsPlist ExportOptions.plist -exportPath "$XC_EXPORT_PATH"
이제 아카이브를 실행하면된다. archive 가 완료되면 artifacts라는 폴더를 만들게 했고
이후 export 에서 생성되는 파일들을 artifacts 폴더에 넣을것이다
위에 env 에서 생략했지만 해당 경로를 XC_EXPORT_PATH 에 넣어줬다
XC_EXPORT_PATH: ${{ './artifacts' }}
archive가 완료 되면 루트 경로에 프로젝트명.xcarchive 파일이 생성된다.
이파일과 ExportOptions.plist 두개를 사용해서 export 를 진행하게 된다.
export 후에는 /artifacts/프로젝트명.ipa 파일이 생성된다. 이 ipa 파일을 testflight 에 업로드 하기만 하면된다
Upload testflight
- name: "TestFlight" uses: apple-actions/upload-testflight-build@v1 with: app-path: ./artifacts/프로젝트명.ipa issuer-id: ${{ secrets.APPSTORE_ISSUER_ID }} api-key-id: ${{ secrets.APPSTORE_API_KEY_ID }} api-private-key: ${{ secrets.APPSTORE_PRIVATE_KEY }}
upload testflight 브랜치를 사용하면 알아서 업로드를 해준다
이때 with에 ipa 파일과
secrets에 저장 해두었던 appstore 정보를 넣어주었다.
키 값에 문제가 없다면 성공적으로 업로드가 될것이다.
버전같은경우는 project.pbxproj 파일에 명시된 버전으로 올라간다.
따라서 release 푸쉬 하기전 버전세팅을 해두고 푸시하면 될것이다.
전체 코드
name: Release on: push: branches: [ release/* ] jobs: build: runs-on: macos-latest env: PERSONAL_ACCESS_TOKEN : ${{ secrets.PERSONAL_ACCESS_TOKEN }} XC_PROJECT: ${{ '프로젝트명.xcworkspace' }} XC_SCHEME: ${{ '프로젝트명' }} XC_CONFIGURATION: ${{ 'release' }} XC_ARCHIVE_PATH: ${{ '프로젝트명.xcarchive' }} XC_EXPORT_PATH: ${{ './artifacts' }} KEYCHAIN: ${{ 'temp.keychain' }} ENCRYPTED_CERTS_FILE_PATH: ${{ '.github/secrets/certs.p12.gpg' }} DECRYPTED_CERTS_FILE_PATH: ${{ '.github/secrets/certs.p12' }} ENCRYPTED_PROVISION_FILE_PATH: ${{ '.github/secrets/Distribution.mobileprovision.gpg' }} DECRYPTED_PROVISION_FILE_PATH: ${{ '.github/secrets/Distribution.mobileprovision' }} SIGNING_DECODE_PWD: ${{ secrets.SIGNING_DECODE_PWD }} CERTS_PWD: ${{ secrets.CERTS_PWD }} steps: - name: "Checkout" uses: actions/checkout@v3 - name: :"Credentials setup" run: | git config --global url."".insteadOf "<https://github.com/>" - name: "Pod install" run: | pod install --repo-update --clean-install - name: "Keychain" run: | security create-keychain -p "" "$KEYCHAIN" security list-keychains -s "$KEYCHAIN" security default-keychain -s "$KEYCHAIN" security unlock-keychain -p "" "$KEYCHAIN" security set-keychain-settings -lut 1200 security list-keychains - name: "Configure Code Signing" run: | gpg -d -o "$DECRYPTED_CERTS_FILE_PATH" --pinentry-mode=loopback --passphrase "$SIGNING_DECODE_PWD" "$ENCRYPTED_CERTS_FILE_PATH" gpg -d -o "$DECRYPTED_PROVISION_FILE_PATH" --pinentry-mode=loopback --passphrase "$SIGNING_DECODE_PWD" "$ENCRYPTED_PROVISION_FILE_PATH" security import "$DECRYPTED_CERTS_FILE_PATH" -k "$KEYCHAIN" -P "$CERTS_PWD" -A security set-key-partition-list -S apple-tool:,apple: -s -k "" "$KEYCHAIN" mkdir -p "$HOME/Library/MobileDevice/Provisioning Profiles" echo `ls .github/secrets/*.mobileprovision` for PROVISION in `ls .github/secrets/*.mobileprovision` do UUID=`/usr/libexec/PlistBuddy -c 'Print :UUID' /dev/stdin <<< $(security cms -D -i ./$PROVISION)` cp "./$PROVISION" "$HOME/Library/MobileDevice/Provisioning Profiles/$UUID.mobileprovision" done - name: "Archive" run: | ls xcodebuild clean archive -workspace "$XC_PROJECT" -scheme "$XC_SCHEME" -configuration "$XC_CONFIGURATION" -archivePath "$XC_ARCHIVE_PATH" "OTHER_CODE_SIGN_FLAGS=--keychain '$KEYCHAIN'" mkdir artifacts - name: "EXPORT" run: | xcodebuild -exportArchive -archivePath "$XC_ARCHIVE_PATH" -exportOptionsPlist ExportOptions.plist -exportPath "$XC_EXPORT_PATH" pwd - name: "TestFlight" uses: apple-actions/upload-testflight-build@v1 with: app-path: ./artifacts/프로젝트명.ipa issuer-id: ${{ secrets.APPSTORE_ISSUER_ID }} api-key-id: ${{ secrets.APPSTORE_API_KEY_ID }} api-private-key: ${{ secrets.APPSTORE_PRIVATE_KEY }}
'개발 > Swift' 카테고리의 다른 글
[TIL] 라이브러리 배포시 주의사항 (접근제한자, 리소스관리) (0) 2022.07.08 [TIL] Cell highlighted UI변경, removeFromSuperview 안되는 경우 (0) 2022.07.08 [Github Action IOS] Pod install 할때 private repo(pod) 권한 관련 에러 (0) 2022.05.16 [Swift] AssociatedType 추상클래스에서의 사용 (0) 2022.05.05 [Swift] Drag&Drop Interaction CustomValue 전달 (0) 2022.05.02