[CI/CD] Github Actions 를 이용한 TestFlight 업로드 자동화

release branch로 push 하면 TestFlight 업로드하기

naljin
29 min readSep 23, 2021

9월의 목표는 github action 과 관련된 아래 두가지 자동화 방법을 포스팅하는거였어요

  1. develop 브랜치로 push 하면 👉🏻 build & test 실행
  2. release 브랜치로 push 하면 👉🏻 테스트 플라이트 자동 등록

이전 포스팅에서는 1. develop 브랜치로 push 하면 👉🏻 build & test 실행까지 마쳤죠?

오늘 목표는 2. release 브랜치로 push 하면 👉🏻 테스트 플라이트 자동 등록 입니다. 바로 시작하죠 ㄱㄱ!

release 브랜치로 push 하면 👉🏻 테스트 플라이트 자동 등록

깃헙 레포의 .github/workflowsdeploy_on_release.yml 이란 파일을 만들어 줄거예요!

만약에 기존에 등록된 github action 이 없어서 해당 경로에 아무런 파일도 없다면, github 레포 -> 상단 탭 Actions -> Set up this workflow 를 챡챡 클릭해서 deploy_on_release.yml 이란 이름으로 새 파일을 생성하면 됩니다.

제 레포에는 우리가 1탄에서 만든 test_on_develop 라는 workflow 로 인해서 경로는 이미 있는 상태니까, 우측의 Add file 을 통해 추가를 해줄게요

이제 안에 들어갈 내용을 작성해야하는데,,,! 냅다 전체 코드 던져버리기!

이제 하나씩 살펴보면서 여러분의 환경에 맞게 설정하는 방법들을 알아보도록 합시다.

1. workflow 이름 지정

name: deploy

처음으로 workflow의 이름을 지정해줬는데요, 이를 통해 Actions 탭에서 workflow 가 트리거 될때 어떤 workflow 가 trigger 될 수 있느냐를 구분 할 수 있습니다.

2. workflow trigger 조건 설정

on:
push:
branches: [ release/* ]

workflow trigger 조건을 설정합니다. 저는 release/ 로 시작하는 branch 가 push 되었을 때로 설정했어요! 더 많은 트리거 조건 설정 방법은 Events that trigger workflows에서 확인할 수 있습니다.

3. job 생성

jobs:
deploy:

workflow의 실행은 하나 이상의 job으로 구성 됩니다.

여기서 workflow 는 “deploy” 라는 single job 으로 구성된다고 설정한건데요, trigger 된 workflow 를 클릭하면 이 job 을 확인 할 수 있어요

4. job이 실행될 os 설정

runs-on: macos-latest

job이 실행될 환경으로 최신 mac os 를 설정해주었습니다.

5. job 에서 쓰일 환경 변수 설정

    env:
XC_WORKSPACE: ${{ 'HappyChuseok/HappyChuseok.xcworkspace' }}
XC_SCHEME: ${{ 'HappyChuseok' }}
XC_ARCHIVE: ${{ 'HappyChuseok.xcarchive' }}

# certificate
ENCRYPTED_CERT_FILE_PATH: ${{ '.github/secrets/certification.p12.gpg' }}
DECRYPTED_CERT_FILE_PATH: ${{ '.github/secrets/certification.p12' }}
CERT_ENCRYPTION_KEY: ${{ secrets.CERTS_ENCRYPTION_PWD }} # gpg로 파일 암호화할 때 사용한 암호

# provisioning
ENCRYPTED_PROVISION_FILE_PATH: ${{ '.github/secrets/HappyChuseok_GithubActions.mobileprovision.gpg' }}
DECRYPTED_PROVISION_FILE_PATH: ${{ '.github/secrets/HappyChuseok_GithubActions.mobileprovision' }}
PROVISIONING_ENCRYPTION_KEY: ${{ secrets.PROVISION_ENCRYPTION_PWD }} # gpg로 파일 암호화할 때 사용한 암호
# certification export key
CERT_EXPORT_KEY: ${{ secrets.CERT_EXPORT_PWD }}
KEYCHAIN: ${{ 'test.keychain' }}

으악 길다 길어.. 아니 진짜 미디엄 코드 삽입 언제 개선할거냐???

하 각각 환경 변수가 의미하는 바와 설정 법을 알아봐야겠져? 여기가 가장 정신 없는 파트가 될테니 심호흡 한번 하시고 ◠‿◠ ,,

먼저 환경 변수를 아래처럼 설정해두면 나중에 $USER_NAME 과 같이 $ 표시를 앞에 붙여 사용할 수 있다는 것 배경 지식으로 가져갑시다

    env:
USER_NAME: naljin

app archive 및 export 에 쓰일 환경 변수 설정

      XC_WORKSPACE: ${{ 'HappyChuseok/HappyChuseok.xcodeproj' }}
XC_SCHEME: ${{ 'HappyChuseok' }}
XC_ARCHIVE: ${{ 'HappyChuseok.xcarchive' }}

자신의 프로젝트 이름에 맞는걸로 적절히 변경해줍시다.

만약 프로젝트가 workspace 가 아니라면, 확장자로 xcworkspace 대신 xcodeproj 를 사용하면 되겠죠?

ipa의 생성을 위한 환경 변수 설정

이제 부터 설명할 환경 변수는 모두 ipa 생성과 관련된 것들입니다.

ipa 생성distribution certificate (인증서) 을 이용한 code signing (코드 서명) provisioning profiles을 요구하기 때문에 단순히 앱을 빌드하고 테스트하는 것보다 조금 더 복잡합니다.

GitHub이 매번 가상 머신의 새로운 인스턴스에서 워크플로를 실행한다는 것은, 각 빌드에서 Apple 계정으로 Xcode에 로그인하지 않을 것이기 때문에 Xcode의 자동 코드 서명 및 프로비저닝의 용이성에 의존할 수 없다는 것을 의미합니다.

따라서 우리는 수동 코드 서명을 해야하고, 이를 위한 몇가지 설정이 필요합니다.

첫 번째 단계는 Apple 개발자 포털 에 로그인 하고 앱에 대한 Distribution certificateDistribution Provisioning 을 수동으로 설정하고 다운받아야합니다.

잉? 그게 몬데 ㅋ 어떻게 하는건데 ㅋ

우선 Distribution certificate 을 받기 위해 Keychain에 가서 disbribution 을 검색해봅시다

그리고 Apple Distribution에 해당하는 개인키와 인증서를 같이 우클릭하여 내보내기를 눌러줍니다. 이때 이름은 적당한걸로 알아서 설정하시고 파일 포맷은 p12 타입 을 선택합니다.

저장을 누르면 암호를 입력하라고 하는데, 이렇게 certificate 를 export 할때 사용한 비밀번호를 기억해둡시다.

아 여기서 만약 나는 keychain 에 distribution 용 인증서 없다?? 하는 분들이면 여기에서 Distribution용 Certificate를 만들어야죠 머

저기 클릭해서 인증서 생성해야하는데,, certificate 생성 내용까지 담기는 귀찮으니까 모르시는 분들은 요렇게 순서대로 참고하시길 바랍니다요

  1. [iOS 앱 배포] 1–1. CSR (Certificate Signing Request : 인증서 서명 요청) 발급받기
  2. [iOS 앱 배포] 1–2. Certificates (인증서) 생성하기

이제 Distribution Provisioning 받아야죠!! 이것도 따로 생성을 해줘야하는디, 중간에 이렇게 App ID 를 선택하는 과정이 있습니다.

따라서 Identifiers 쪽에서 APP ID 를 먼저 등록해줍시다.

요것도 내용을 담기는 귀찮으니까 [iOS 앱 배포] 2. Identifiers (식별자) App ID 등록하기 를 참고하도록 하죠!

만약 Widget 같은것도 있으면 위젯용도 따로 만들어줘야하는거 알져?! 번들 아이디가 엄연히 다른 친구니까여 ㅜ

후 이제 진짜 Distribution Provisioning 을 만들어봐요

https://developer.apple.com/account/resources/profiles/list 여기로 들어가서 + 를 클릭하고

앱 스토어 배포용을 선택한 다음

아까 Identifier 쪽에서 등록을 마친 App ID 를 선택하고 쭉쭉 진행해줍시다.

그럼 마지막으로HappyChuseok_GithubActions.mobileprovision 같은 .mobileprovision 을 다운받을 수 있습니다!!

아악!!!!! 드디어 다 얻었다!!!! certificate (.p12) & provisioning (.mobileprovision) !!

지금까지 과정은 뭘 위한거였다!?!?! 위에서 말했져?! ipa 를 만드려면 code signing (using certificate) 과 provisioning 이 필요하다고!!!

🤔 내 로컬에서 archive 해서 ipa 파일 만들때 이딴 프로세스 필요 없었는데?!!?!?!? 👉🏻 Apple 계정으로 Xcode에 로그인한 상태 👉🏻 자동 코드 서명프로비저닝 ssap possible

하지만 github 에서 돌아가는 가상 환경? 👉🏻 Apple 계정으로 Xcode에 로그인하지 않은 상태 👉🏻 자동 코드 서명 및 프로비저닝 불가하기 때문에 certificate 와 provisioning 제공해준 후 이것들로 서명 및 프로비저닝 하게 해야함!

하 이제 certificate 와 provisioning 을 우리 깃헙 레포에 올려줍시다?! 아 근데 올리기 전에 할거 하나 더 있음;;; 바로 파일 암호화;

아 보안 개나 줘버리던가~ 할거 아니면 잠자코 certificate와 provisioning을 암호화 해봅시다… ◠‿◠ 뭘로? gnupg2 라는 암호화 툴로!

우선 터미널로 깔아주고요?

brew install gnupg2

각각의 명령어를 통해 p12인증서와 provisioning 를 암호화해줍시다.

gpg -c certification.p12gpg -c HappyChuseok_GithubActions.mobileprovision

당연히 암호화에 필요한 암호를 입력하게 되는게 이걸 잘 기억해둡시다 ㅋ 왜냐? 복호화할때 필요하니까 ㅋ

좋아 찐으로 이제 올릴 준비 됐다.

깃헙 레포에 올릴건데 .github > secrets 라는 custom 으로 생성한 경로에 넣어줄게요

우리가 이렇게 올린 파일은 나중에 아래와 같이 복호화 됩니다.

gpg -d -o "$DECRYPTED_CERT_FILE_PATH" --pinentry-mode=loopback --passphrase "$CERT_ENCRYPTION_KEY" "$ENCRYPTED_CERT_FILE_PATH"

필요한 것들을 찬찬히 살펴보면 아래와 같죠?

  1. $ENCRYPTED_CERT_FILE_PATH : 암호화된 파일
  2. $CERT_ENCRYPTION_KEY : 암호화 할 때 사용한 key
  3. $DECRYPTED_CERT_FILE_PATH : 파일 복호화시 저장될 위치

certificate, provisiong 두가지 파일이 암호화 되었으니, 각각을 복호화하기 위한 환경 변수를 선언해준겁ㄴㅣ다

      # certificate 
ENCRYPTED_CERT_FILE_PATH: ${{ '.github/secrets/certification.p12.gpg' }}
DECRYPTED_CERT_FILE_PATH: ${{ '.github/secrets/certification.p12' }}
CERT_ENCRYPTION_KEY: ${{ secrets.CERTS_ENCRYPTION_PWD }} # gpg로 파일 암호화할 때 사용한 암호

# provisioning
ENCRYPTED_PROVISION_FILE_PATH: ${{ '.github/secrets/HappyChuseok_GithubActions.mobileprovision.gpg' }}
DECRYPTED_PROVISION_FILE_PATH: ${{ '.github/secrets/HappyChuseok_GithubActions.mobileprovision' }}
PROVISIONING_ENCRYPTION_KEY: ${{ secrets.PROVISION_ENCRYPTION_PWD }} # gpg로 파일 암호화할 때 사용한 암호

certificate 케이스만 자세히 뜯어보자면

      # certificate 
ENCRYPTED_CERT_FILE_PATH: ${{ '.github/secrets/certification.p12.gpg' }}
DECRYPTED_CERT_FILE_PATH: ${{ '.github/secrets/certification.p12' }}
CERT_ENCRYPTION_KEY: ${{ secrets.CERTS_ENCRYPTION_PWD }} # gpg로 파일 암호화할 때 사용한 암호

ENCRYPTED_CERT_FILE_PATH 는 내가 .gpg 파일을 github/secrets/ 에다 저장했으니까 그거에 맞는 경로 써준거고 ㅇㅇ

DECRYPTED_CERT_FILE_PATH 는 복호화될 파일 저장 경로 내가 알아서 설정해준거고 ㅇㅇ

CERT_ENCRYPTION_KEY 는? 아까 gpg 로 암호화 된 파일 생성할때 설정한 암호 ㅇㅇ 근데 secrets.CERTS_ENCRYPTION_PWD 에서 불러오는데?? 이거 어디서 값 불러오는거냐?

이게 바로 이제 깃헙에 가서 정의해줘야하는 부분이죠 ㅋ

Settings > Secrets > New repository secret 으로 가서 변수를 설정해줍시다

CERTS_ENCRYPTION_PWD 라는 이름으로 아까 certification 을 암호화할때 사용한 비번 입력해줌여. 그럼 저쪽에서 secrets.CERTS_ENCRYPTION_PWD 처럼 사용할 수 있는거 ㅇㅇ

우리 provisioning 도 암호화했자나여. 그때 쓴 암호도 PROVISIONING_ENCRYPTION_KEY 이름의 변수로 만들어줌여!

좋아 그 다음 환경 변수를 볼까!

# certification export key
CERT_EXPORT_KEY: ${{ secrets.CERT_EXPORT_PWD }}

아촤촤~~ 님덜 기억해두라고 한 암호 한개 더 있었던거 생각남여?? 바로바로 certification export 할때 사용했던거!!!!!!! 이것도 secrets 내에 값으로 만들어줘야해요. 왜냐?? 이 값으로 나중에 임시 키체인으로 인증서를 가져올 때 필요하기 때문이죠. 이건 밑에서 좀 더 설명하기로하고!

튼 이것까지 CERT_EXPORT_PWD 로 만들어줍시다.

좋아 찐 마지막 환경 변수를 설명해봅시다!!!!!!

KEYCHAIN: ${{ 'test.keychain' }}

얘는 인증서를 설치하기에 앞서, 키체인을 새로 생성하고 초기화 하는데 사용 됩니다. 즉 임시 키 체인을 만들때 필요!! 굳이 변수로 안빼줘도 되는것 같다는데.. 제가 참고한 링크는 다들 쓰고 있으니까 일단 저도 넣을래여

6. steps 설정

steps:

후 이제 환경 변수 설정도 끝났으니 실제로 수행할 일들을 명시해봅시다.

Steps 하위에 job의 일부로 실행될 일련의 task들을 설정할 수 있는데요, 이때 -name 으로 task 의 이름을 구분할 수 있습니다.

요런 식으로 task 를 설정해주면

- name: Select latest Xcode  run: "sudo xcode-select -s /Applications/Xcode.app"

actions 에서 어떤 이름의 task가 실행됐는지 단계별로 구분 가능!

이제 아래 섹션부터는 이 step 들을 어떤 task 로 구성했는지를 살펴보는 내용이 될겁니다.

7. Select latest Xcode

- name: Select latest Xcode
run: "sudo xcode-select -s /Applications/Xcode.app"

shell 이용해서 하나의 command 수행할 수 있습니다. 이 해당 command는 최신 Xcode 를 선택하는 명령입니다.

8. Checkout project

- name: Checkout project
uses: actions/checkout@v2

uses key로 명령이 입력되어있다면 Github Actions에서 기본으로 제공하는 액션을 사용한다는 것입니다. 해당 액션은 repository 에 체크아웃하는 것입니다.

9. Configure Keychain

      - name: Configure 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

임시 키체인을 새로 생성합니다. 밑에서 인증서를 가져올때 임시 키체인이 사용됩니다.

10. Configure Code Signing

      - name : Configure Code Signing
run: |
gpg -d -o "$DECRYPTED_CERT_FILE_PATH" --pinentry-mode=loopback --passphrase "$CERT_ENCRYPTION_KEY" "$ENCRYPTED_CERT_FILE_PATH"
gpg -d -o "$DECRYPTED_PROVISION_FILE_PATH" --pinentry-mode=loopback --passphrase "$PROVISIONING_ENCRYPTION_KEY" "$ENCRYPTED_PROVISION_FILE_PATH"
security import "$DECRYPTED_CERT_FILE_PATH" -k "$KEYCHAIN" -P "$CERT_EXPORT_KEY" -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_CERT_FILE_PATH" --pinentry-mode=loopback --passphrase "$CERT_ENCRYPTION_KEY" "$ENCRYPTED_CERT_FILE_PATH"gpg -d -o "$DECRYPTED_PROVISION_FILE_PATH" --pinentry-mode=loopback --passphrase "$PROVISIONING_ENCRYPTION_KEY" "$ENCRYPTED_PROVISION_FILE_PATH"

gpg 를 이용해 우선 certificate랑 provisioning 파일을 복호화해서 빼냅니다.

security import "$DECRYPTED_CERT_FILE_PATH" -k "$KEYCHAIN" -P "$CERT_EXPORT_KEY" -Asecurity set-key-partition-list -S apple-tool:,apple: -s -k "" "$KEYCHAIN"

security를 사용하여 인증서와 개인 키를 새로 만든 키 체인으로 가져옵니다. certification (.p12) 을 만들때 인증서와 개인 키를 같이 묶어서 export 했으므로, certification과 certification을 export 할때 사용했던 암호를 제공하면 역으로 인증서와 개인키를 추출할 수 있습니다.

mkdir -p "$HOME/Library/MobileDevice/Provisioning Profiles"

Xcode에서 찾을 수 있는 프로비저닝 프로필 설치하기 위해 우선 프로비저닝 디렉토리를 생성합니다

echo `ls .github/secrets/*.mobileprovision`

echo는 중간에 디버깅 용으로 넣어뒀다고 제드님 참고 링크에 써있었는데, 실제로 저도 디버깅할때 도움이 됐어서 냅뒀습니다.

for PROVISION in `ls .github/secrets/*.mobileprovision`doUUID=`/usr/libexec/PlistBuddy -c 'Print :UUID' /dev/stdin <<< $(security cms -D -i ./$PROVISION)`cp "./$PROVISION" "$HOME/Library/MobileDevice/Provisioning Profiles/$UUID.mobileprovision"done

그런 다음 로컬에서와 똑같이 모든 프로비저닝 프로파일을 rename 하고 해당 위치로 복사하는 과정입니다.

11. Archive app

      - name: Archive app
run: |
pod install --repo-update --clean-install --project-directory=HappyChuseok/
xcodebuild clean archive -workspace $XC_WORKSPACE -scheme $XC_SCHEME -configuration release -archivePath $XC_ARCHIVE

Xcode 커맨드로 앱을 아카이브 합니다.

저는 pod 파일로 라이브러리를 관리하고 있기 때문에 pod install 명령어도 써줬고, archive 하는 프로젝트도 -workspace 로 설정해주었습니다.

하지만 상황에 맞게 pod install 쪽을 삭제하고 -workspace $XC_WORKSPACE 대신 -project HappyChuseok.xcodeproj 으로 변경하시면 됩니다.

12. Export app

      - name: Export app
run: |
xcodebuild -exportArchive -archivePath $XC_ARCHIVE -exportOptionsPlist ExportOptions.plist -exportPath . -allowProvisioningUpdates

archive 후에 마지막 단계로 ipa 파일을 빼내기 위해서는 export 과정을 거치는데요..!!! 이때 target 별로 distribution certificateprovisioning profile 이 필요합니다 ㅋ 이걸 제공해주려고 우리가 위에서 ㄱㅐ고생했죠 ㅋ

이러한 정보는 property list 를 통해 xcodebuild로 전달됩니다. 위에 명령어에서도 해당하는 파일( ExportOptions.plist)이 보이죠?

엥? ExportOptions.plist 뭐냐..? 걍 초면인데요;; 어케 얻는거임??? 👉🏻 이 plist 파일을 얻는 가장 쉬운 방법은 Xcode를 통해 한 번 export 하는 것입니다 ㅋ.. 진짜 가지가지맨~~

하 우선 엑코 targets > signing & capabilities > release 를 들어가봅시다

automatically manage signing 을 체크 해제하고 import profile 을 통해 우리가 아까 profile 에서 다운 받았던 ~~~.mobileprovision 을 import 해줍니다

선택 완료! 근데 밑에 status 에 경고로 provisioning profile ~~ doesn’t include 어쩌구 저쩌구 뜨잖아요?? 저건 provisitiong profile 한번 더 선택해줬더니 사라지더라구용 ㅇ0ㅇ

이제 Product archive 를 해봅시다요

Distribute App 선택하고

앱 스토어 커넥트

그리고 Export!!!!!!!!

그렇게 계속 next 를 주구장창 누르다가 우리가 만든 distribution certificates 와 provisioning profiles 를 선택합니다

마지막으로 export 된 폴더안에는 요런식으로 파일들이 들어있는데, 이 중 ExportOptions.plist

깃헙 레포에 업로드합니다!!!

13. Upload app to TestFlight

      - name: Upload app to TestFlight
uses: apple-actions/upload-testflight-build@v1
with:
app-path: 'HappyChuseok.ipa'
issuer-id: ${{ secrets.APPSTORE_ISSUER_ID }}
api-key-id: ${{ secrets.APPSTORE_API_KEY_ID }}
api-private-key: ${{ secrets.APPSTORE_API_PRIVATE_KEY }}

아까 위에서 uses key로 명령이 입력되어있다면 Github Actions에서 기본으로 제공하는 액션을 사용하는 거라고 했져? 해당 액션은 testflight 에 업로드하는 것인데, app-path / issuer-id / api-key-id / api-private-key 네가지 값이 추가로 필요합니다.

app-path : ipa 경로

나머지 세개는.. 우선 https://appstoreconnect.apple.com/access/api 에 들어가 봅시다.

사용자 및 액세스 > keys > + 를 누르면 api 키를 생성할 수 있는데

이렇게 생성하면 issuer-idapi-key-id 에 해당하는 값을 확인 할 수 있습니다.

그럼 나머지 api-private-key 는 무ㅓ냐.. 하면 저기 우측에 API 키 다운로드 보이져? 저걸 눌러보아요

그럼 이렇게 살짝 무서운 경고 문구와 함께 다운로드를 누르면 .p8 파일이 받아집니다. 그 파일을 열면 나오는 값!!!!!!

후,, 각각의 값들을 확인했으니까 깃헙 레포 Settings > Secrets > New repository secret 으로 가서 변수로 설정해줍시다. 그래야 secrets.APPSTORE_ISSUER_ID 처럼 사용할 수 있을 테니까요 ㅠ

두둥

자 이제 release/ 브랜치 만들어서 여기로 push ㅎㅐ보자!!!!!!!!!!

77ㅑ앙아아아아아아아아ㅏㅇ아아아ㅏ아아아아아아아아아ㅏ아아앙ㄱ!!!!!!!!!!!!!

사실 처음에 경로 잘못써서 빌드 한번에 성공 못하긴 했음 ㅋ,, 그래도 여러분도 당황하지 말고 에러로그를 잘 보도록 합시다 ◠‿◠

으휴 지규와 지규와!!!

추가 정보

  • 이 글 작성하기 전에 다른 프로젝트에서 github actions 를 적용한적이 있음 (그럼 이 글에서는 두번째로 적용해본건데 왜 이렇게 오래걸린걸까? 🤔 ㅋ..)
  • 그때는 이런 에러가 뜨면서 github action 아카이브가 안됐음

Found an unexpected Mach-O header code: 0x72613c21

LOGFILE="${ARCHIVE_PATH}/static-frameworks.log"
echo "Removing static frameworks from ${WRAPPER_NAME} archive" > $LOGFILE
find "${ARCHIVE_PRODUCTS_PATH}/Applications/${WRAPPER_NAME}" -name '*.framework' -print0 | while IFS= read -r -d '' fm; do
name=$(basename "${fm}" .framework)
target="${fm}/${name}"
echo "Checking: ${fm}" >> $LOGFILE
if file "${target}" | grep -q "current ar archive"; then
rm -rf "${fm}"
echo "Removed static framework: ${fm}" >> $LOGFILE
fi
done
  • 이 이슈 해결하는데 너무 오래걸렸어서 짤막하게나마 첨부함

참고

--

--