iOS Setup
Barbelic iOS 앱은 원격 React 앱을 여는 Capacitor/WKWebView 셸이며 Kakao, Google, Apple 로그인에 공통 Supabase PKCE 흐름을 사용한다.
준비 및 실행
- macOS에 Xcode 정식 앱을 설치하고 라이선스와 추가 컴포넌트 설치를 완료한다.
- iPhone을 연결하고 기기 신뢰를 허용한다.
npm ci
npm run build
npm run ios:sync
npm run ios:openXcode의 barbelic shared scheme과 App target에서 Team을 선택하고 Bundle Identifier com.dekerd.barbelic를 확인한 뒤 실기기에서 실행한다. scheme 이름과 Barbelic.app 산출물은 Capacitor CLI 실행 경로에도 동일하게 사용된다. TestFlight/App Store 배포에는 Apple Developer Program이 필요하다.
Build configuration
Debug/Release xcconfig는 다음 값을 Info.plist로 주입한다.
BARBELIC_SERVER_ORIGIN: WebView가 여는 정규 originhttps://www.barbelic.com.BARBELIC_SUPABASE_AUTH_ORIGIN: authorize URL을 허용할 정확한 Supabase originBARBELIC_CALLBACK_SCHEME: 새 앱의 custom URL scheme인barbelic
barbelic://auth/callback은 Xcode URL Types에 등록되어 있어야 한다. Supabase Dashboard의 Redirect URLs에도 barbelic://auth/callback**을 등록한다.
App Store 제출 준비물 (심사 #665 Phase 8, 2026-09-02)
App/PrivacyInfo.xcprivacy— 앱 타깃의 privacy manifest. Apple은 2024-05-01부터 "사유 필요 API"(UserDefaults 등)를 쓰면서 이 파일이 없는 앱을 App Store Connect 업로드 단계에서 거부한다(ITMS-91053). Capacitor 프레임워크는 자기 manifest를 갖지만 앱 코드의 UserDefaults 사용은 앱 몫이다. 수집 데이터 유형 목록은 App Store Connect의 App Privacy 라벨과 같아야 한다 — 라벨을 바꾸면 이 파일도 같이 바꾼다. 트래킹 없음.Info.plist권한 문구 3종 —NSCameraUsageDescription·NSPhotoLibraryUsageDescription(프로필 사진 변경의 웹 파일 선택기가 "사진 찍기 / 사진 보관함"을 띄운다 — 문구가 없으면 카메라 선택 시 시스템이 앱을 강제 종료한다, 2026-09-03 재점검) ·NSPhotoLibraryAddUsageDescription(세션 이미지 저장).Info.plist의ITSAppUsesNonExemptEncryption = false— 표준 HTTPS만 쓰므로 수출 규정 예외. 없으면 빌드 업로드마다 암호화 질문에 답해야 한다.- 오프라인 안내 페이지 —
capacitor.config.json의server.errorPath(offline.html)가 번들public/의offline.html(저장소public/offline.html,npm run build→npm run ios:sync로 복사)을 가리킨다. 서버 연결 실패 시 검은 화면 대신 이 페이지가 뜬다. 동작 계약은contracts/native-bridge.md의 Offline page. - 데이터 내보내기 — 앱에서는 다운로드 링크 대신
shareFile브리지로 iOS 공유 창을 연다 (같은 문서의 Share file).
Windows에서는 Swift를 컴파일할 수 없으므로 위 항목 중 Swift 변경(로드 실패 처리·공유 창)은 macOS Xcode 빌드에서 컴파일이 확인된다. 파일 등록·plist 키·config 값은 tests/react/iosStoreSubmissionContract.test.mjs가 단언한다.
Social login flow
- 웹이 선택한 provider로 로그인은 Supabase
signInWithOAuth, 계정 연결은linkIdentity를 호출하고 PKCE verifier와 32-byte transaction ID를 만든다. verifier는 전체 session과 분리해 iOS Keychain에 최대 10분만 저장한다. - iOS는
startSocialLogin메시지의 action/provider/transaction을 바인딩한다. 로그인 URL은 Supabase origin·S256 challenge·custom redirect를, 연결 URL은 provider별 공식 authorize endpoint와 정확한 Supabase callback을 검증한다. - iOS가 authorize URL을
ASWebAuthenticationSession으로 연다. 단 Apple 로그인 (actionsign-in, providerapple)은 시스템 시트(ASAuthorizationController)를 띄우고, 돌려받은 identity token과 원문 nonce를barbelic:native-authdetail{ provider, idToken, nonce }로 넘긴다 — 웹이signInWithIdToken으로 세션을 만들므로 4~6단계의 callback URL 교환은 없다. Sign in with Apple capability (App/App.entitlements)와 Supabase Apple Client IDs의 번들 ID가 전제다. - provider 인증 후 Supabase가
barbelic://auth/callback?auth_action=...&provider=...&transaction_id=...&code=...로 돌려보낸다. - iOS가 pending action/provider/transaction/10분 TTL을 검증하고 1회 소비한다.
- 웹이 Keychain의 verifier를 복구해 code를 Supabase session으로 교환하고 verifier를 삭제한다. refresh session은 별도 Keychain item에 보관한다.
자세한 메시지 형식은 contracts/native-bridge.md, provider 설정은 social-auth.md를 따른다.
실기기 확인
- rollout gate를 연 뒤 로그인 화면에 Kakao, Google, Apple 세 버튼이 모두 보이는가
- 각 버튼이 WebView 내부 이동이 아니라 외부 인증 세션을 여는가 (Apple 로그인만 시스템 시트 — Face ID/암호 — 가 뜨고, Apple 계정 연결은 여전히 웹 시트인가)
- 취소하거나 provider 오류가 발생하면 버튼 pending 상태가 해제되는가
- 성공 callback에는 code만 있고 access/refresh/ID token이 없는가
- 로그인 뒤 홈, 세션, 종목, 내 정보 탭과 운동 시작 화면이 정상인가
- 앱을 종료 후 다시 열어도 Keychain session으로 로그인이 복원되는가
- provider callback 직전에 WebView 또는 앱이 재시작돼도 로그인이 완료되는가
- iframe 또는 다른 origin에서 native bridge 호출 시 무시되는가
- 로그인된 사용자가 내 정보에서 사용하지 않은 provider를 연결하고, 재로그인 후에도 같은
auth.users.id와 기존 데이터를 유지하는가
Windows에서는 Swift를 컴파일할 수 없으므로 이 변경의 최종 검증에는 macOS Xcode build와 위 실기기 시나리오가 필수다.