Xcode 26 Provisioning Profile Capability 검증 실패 — 손상된 캐시가 원인
Expo + EAS Build로 iOS 프로덕션 빌드를 돌렸더니 이런 에러가 떴다.
Provisioning profile "..." doesn't include the Sign In with Apple capability. Provisioning profile "..." doesn't include the Push Notifications capability.
Apple Sign In을 사용하고, expo-notifications로 로컬 알림을 처리하는 React Native 앱이다.
실제로 Push Notifications(APNs)를 쓰는 건 아닌데, expo-notifications 패키지가 빌드 시 aps-environment entitlement을 자동으로 주입한다.
Xcode 입장에서는 이 entitlement이 있으니 Push Notifications capability가 필요하다고 판단한 거다.
Xcode 26.3으로 업데이트한 직후부터 발생했다.
환경
| 항목 | 버전 |
|---|---|
| macOS | Sequoia 15.4 |
| Xcode | 26.3 (Build version 17C529) |
| Expo SDK | 52 |
| EAS CLI | 16.1.2 |
| React Native | 0.76.7 |
진단 — profile은 정상인가?
에러 메시지만 보면 provisioning profile에 capability가 빠진 것 같다. 먼저 profile을 직접 까서 확인한다.
security cms -D -i profile.mobileprovision출력에서 Entitlements 딕셔너리를 찾으면:
<key>com.apple.developer.applesignin</key>
<array>
<string>Default</string>
</array>
<key>aps-environment</key>
<string>production</string>com.apple.developer.applesignin과 aps-environment 모두 존재한다.
profile에는 문제가 없다.
여기서 profile을 재생성하거나 수동으로 만들어봐야 시간 낭비다. 검증하는 쪽, 즉 Xcode를 의심해야 한다.
원인 — Xcode의 Capability 캐시 손상
Xcode 26은 provisioning profile의 capability를 검증할 때 로컬 캐시 파일을 참조한다.
~/Library/Developer/Xcode/UserData/Capabilities/capabilities-26.3-{TeamID}-bundle.json
Xcode가 capability 목록을 가져오는 흐름:
- 네트워크 — Apple Developer Portal API에서 팀별 capability 목록 fetch
- 파일 캐시 —
~/Library/Developer/Xcode/UserData/Capabilities/에 저장 - Xcode 번들 fallback — 위 두 소스 실패 시
/Applications/Xcode.app/.../DVTPortalCachedPortalCapabilities.json(80개+ 전체 목록) 사용
문제는 2번 파일 캐시가 불완전하게 저장된 거다.
전체 80개 이상의 capability 중 11개만 캐시되어 있었고, APPLE_SIGN_IN과 PUSH_NOTIFICATIONS가 목록에서 빠져 있었다.
Xcode는 profile의 entitlement을 이 캐시된 목록과 대조하는데, 목록에 없는 capability는 profile에 포함되어 있어도 "없다"고 판단한다. 3번 fallback이 동작했어야 하는데, 불완전하더라도 캐시 파일이 존재하니까 fallback을 건너뛴 거다.
왜 11개만 캐시됐나?
정확한 원인은 확인하기 어렵지만, Xcode 26 업데이트 직후 첫 빌드에서 Apple Developer Portal API 호출이 중간에 끊겼을 가능성이 높다. 네트워크 불안정이나 Apple API 타임아웃으로 응답이 불완전하게 왔는데, Xcode가 부분 응답을 그대로 캐시에 저장한 것으로 추정된다. 한 번 캐시 파일이 만들어지면 이후 빌드에서는 네트워크 요청 없이 캐시를 재사용하니까, 손상된 상태가 계속 유지된다.
해결 — 캐시 삭제 한 줄
rm -rf ~/Library/Developer/Xcode/UserData/Capabilities/삭제 후 Xcode가 전체 capability 목록을 다시 로드하면서 빌드 즉시 성공.
이 디렉토리는 삭제해도 안전하다. Xcode가 다음 빌드에서 자동으로 재생성한다.
다만 재생성 시점에 다시 네트워크 문제가 있으면 또 불완전하게 캐시될 수 있다. 재발하면 같은 방법으로 삭제하면 된다.
시도했지만 효과 없었던 것들
| 시도 | 결과 |
|---|---|
| Apple Developer Portal에서 profile 삭제 후 재생성 | 실패 — profile이 아니라 Xcode 캐시 문제 |
| EAS credentials에서 profile 삭제/재생성 | 실패 |
| Apple Developer Portal에서 수동으로 profile 생성 후 업로드 | 실패 |
expo-notifications plugins 배열 추가/제거 | 실패 |
expo-notifications 소스 패치로 aps-environment 제거 | Push 에러만 해결, Sign In with Apple 에러 잔존 |
Xcode 프로젝트에 SystemCapabilities 추가 | 실패 |
CODE_SIGN_STYLE = Manual 강제 설정 | 실패 |
| DerivedData 삭제 | 실패 |
ENABLE_PROVISIONING_PROFILE_CAPABILITIES_VALIDATION=NO xcargs 전달 | 실패 — 존재하지 않는 빌드 설정 |
-allowProvisioningUpdates xcargs 전달 | 실패 |
10가지 시도가 전부 실패했다. profile 자체를 아무리 갈아치워봐야, 검증하는 쪽(Xcode 캐시)이 깨져있으면 소용없다.
같은 문제인지 진단하는 법
1단계: profile 확인
security cms -D -i profile.mobileprovisionEntitlements에 해당 capability의 entitlement이 있는지 확인한다.
있는데 Xcode가 거부하면 2단계로.
2단계: Xcode 캐시 확인
cat ~/Library/Developer/Xcode/UserData/Capabilities/*.json \
| python3 -c "import json,sys; d=json.load(sys.stdin); print(len(d.get('data',[])))"정상이면 80개 이상이 나온다.
11개 같은 적은 수가 나오면 캐시가 손상된 거다.
rm -rf ~/Library/Developer/Xcode/UserData/Capabilities/로 삭제하고 다시 빌드하면 된다.
핵심 정리
- Provisioning profile과 entitlement이 모두 정상인데 capability 에러가 나면, Xcode의 capability 캐시 손상을 의심할 것.
- Xcode 메이저 업데이트 후 캐시가 불완전하게 마이그레이션될 수 있다.
~/Library/Developer/Xcode/UserData/Capabilities/삭제는 안전하며, Xcode가 자동으로 재생성한다.- DerivedData 삭제로 안 풀리면, 다른 캐시 경로도 살펴봐야 한다.
expo-notifications는 로컬 알림만 써도aps-environmententitlement을 자동 주입한다는 점을 기억할 것.
댓글
불러오는 중...