Expo + Expo Router + GitHub Actions CI/CD + App Store & Play Store 배포.
앱을 만들고, push로 배포하세요.
English | 한국어
Starter Series — 매번 AI한테 CI/CD 설명하지 마세요. clone하고 바로 시작하세요.
Docker Deploy · Discord Bot · Telegram Bot · Browser Extension · Electron App · npm Package · React Native · VS Code Extension · MCP Server · Python MCP Server · Cloudflare Pages
create-starter 사용 (권장):
gh repo create my-app --template starter-series/react-native-starter --clone
cd my-app
npm install
npm run check:expo
npm start또는 직접 clone:
git clone https://github.com/starter-series/react-native-starter my-app
cd my-app
npm install
npm run check:expo
npm start그런 다음 Expo Go로 QR 코드를 스캔하세요 (또는 a로 Android / i로 iOS).
├── app/ # Expo Router 앱 디렉토리
│ ├── _layout.js # 루트 레이아웃 — 전체를 <AuthProvider>로 감쌈
│ ├── (app)/ # 인증 필요 그룹 (로그아웃 시 /login 리다이렉트)
│ │ ├── _layout.js # 가드 레이아웃
│ │ ├── index.js # 홈 화면
│ │ ├── about.js # 예시 두 번째 화면
│ │ └── profile.js # 로그인 유저 정보 + 로그아웃
│ └── (auth)/
│ ├── _layout.js # 이미 로그인 상태면 / 로 리다이렉트
│ └── login.js # "Continue with Google" 화면
├── lib/
│ ├── auth-context.js # AuthProvider + useAuth + handleAuthResult
│ └── env.js # EXPO_PUBLIC_GOOGLE_* 클라이언트 ID 로드
├── assets/ # 앱 아이콘, 스플래시, 어댑티브 아이콘
├── tests/ # Jest 테스트 (auth-context, screens, 구조)
├── .env.example # Google OAuth 클라이언트 ID 예시
├── .github/
│ ├── workflows/
│ │ ├── ci.yml # 린트, 테스트, 감사
│ │ ├── cd-android.yml # EAS로 Play Store 빌드 + 제출
│ │ ├── cd-ios.yml # EAS로 App Store 빌드 + 제출
│ │ └── setup.yml # 첫 사용 시 자동 설정 체크리스트
│ └── PULL_REQUEST_TEMPLATE.md
├── docs/
│ ├── EXPO_SETUP.md # Expo 계정 + EAS 설정
│ ├── APP_STORE_SETUP.md # Apple Developer + App Store Connect
│ ├── PLAY_STORE_SETUP.md # Google Play Console 설정
│ └── PRIVACY_MANIFEST.md # iOS PrivacyInfo.xcprivacy + Android 포토 피커 권한
├── scripts/
│ └── bump-version.js # app.json + package.json 버전 업
├── eas-hooks/
│ └── eas-build-pre-install.sh # EAS Build 훅 예시
├── eslint.config.js # ESLint v9 flat config
├── app.json # Expo 설정
├── eas.json # EAS Build 프로필
└── package.json
- Expo + Expo Router -- 파일 기반 라우팅, 로컬에 네이티브 툴체인 불필요
- CI 파이프라인 -- 모든 push와 PR에서 보안 감사, 린트, 테스트 실행
- CD 파이프라인 -- EAS Build를 통한 원클릭 App Store / Play Store 배포
- 클라우드 빌드 -- EAS가 클라우드에서 네이티브 바이너리 컴파일 (로컬 Xcode/Android Studio 불필요)
- 버전 관리 --
npm run version:patch/minor/major로app.json버전 업 - 스타터 코드 -- 홈 + About + Profile 화면 + Google OAuth 로그인 연결 완료
- 스토어 설정 가이드 -- Apple Developer, Google Play Console, EAS 단계별 문서
- 템플릿 셋업 -- 첫 사용 시 설정 체크리스트 이슈 자동 생성
| 단계 | 역할 |
|---|---|
| 보안 감사 | npm audit --audit-level=high로 의존성 취약점 확인 |
| Expo 체크 | npm run check:expo로 Expo 호환 의존성 버전 확인 |
| 린트 | ESLint로 앱 및 컴포넌트 코드 검사 |
| 테스트 | Jest + React Native Testing Library |
| 빌드 검증 | npm run build로 web bundle export |
| 워크플로우 | 역할 |
|---|---|
CodeQL (codeql.yml) |
보안 취약점 정적 분석 (push/PR + 주간) |
Maintenance (maintenance.yml) |
주간 CI 헬스 체크 — 실패 시 이슈 자동 생성 |
Stale (stale.yml) |
비활성 이슈/PR 30일 후 라벨링, 7일 후 자동 종료 |
CHANGELOG (update-changelog.yml) |
머지된 PR 항목을 CHANGELOG.md에 자동으로 추가 |
| 단계 | 역할 |
|---|---|
| CI | 전체 CI 먼저 실행 |
| 스토어 준비 preflight | app.json에 기본 앱 이름, scheme, 번들 ID, 패키지가 남아 있으면 실패 |
| 버전 가드 | 해당 버전의 git 태그가 이미 있으면 실패 |
| EAS Build | eas build --platform android --profile production |
| EAS Submit | AAB를 Play Store에 업로드 (internal 트랙) |
| GitHub Release | 태그된 릴리즈 자동 생성 |
| 단계 | 역할 |
|---|---|
| CI | 전체 CI 먼저 실행 |
| 스토어 준비 preflight | app.json에 기본 앱 이름, scheme, 번들 ID, 패키지가 남아 있으면 실패 |
| 버전 가드 | 해당 버전의 git 태그가 이미 있으면 실패 |
| EAS Build | eas build --platform ios --profile production |
| EAS Submit | App Store Connect에 업로드 |
| GitHub Release | 태그된 릴리즈 자동 생성 |
배포 방법:
EXPO_TOKEN시크릿 설정 (아래 참조)- 스토어 계정 설정 (docs/ 참조)
eas submit:configure를 한 번 실행해 Apple/Google 자격 증명에 맞는 로컬submit블록 추가- 버전 업:
npm run version:patch - Actions 탭 -> Deploy to Play Store 또는 Deploy to App Store -> Run workflow
| Secret | 설명 |
|---|---|
EXPO_TOKEN |
EAS CLI 인증을 위한 Expo 액세스 토큰 |
토큰 생성 방법은 **docs/EXPO_SETUP.md**를 참고하세요.
스토어 자격 증명은 eas.json과 eas credentials로 설정합니다 (GitHub Secrets가 아님):
- docs/APP_STORE_SETUP.md - iOS
- docs/PLAY_STORE_SETUP.md - Android
EAS Build 생명주기 중간에 커스텀 스크립트를 실행합니다. eas-hooks/<이름>.sh 위치의 스크립트는 EAS CLI가 자동 감지합니다 — eas.json 설정 불필요. 시작할 수 있게 eas-build-pre-install.sh 예시가 포함되어 있습니다.
| 훅 | 실행 시점 | 용도 |
|---|---|---|
eas-build-pre-install.sh |
npm install 전 |
환경 변수 주입, 필수 시크릿 검증, .env 파일 생성 |
eas-build-post-install.sh |
npm install 후, prebuild 전 |
patch-package, 네이티브 모듈 설정, Ruby/CocoaPods 조정 |
eas-build-on-success.sh |
빌드 성공 후 | 알림, 추가 아티팩트 업로드 |
eas-build-on-error.sh |
빌드 실패 시 | 에러 리포팅, 디버깅 출력 |
eas-build-on-cancel.sh |
빌드 취소 시 | 정리 작업 |
스크립트는 실행 가능해야 하며 (chmod +x), 실행 비트가 설정된 상태로 커밋해야 합니다. 훅에 시크릿을 노출하려면 eas secret:create를 사용하세요.
문서: Run custom scripts with npm hooks
# 개발 서버 시작
npm start
# 특정 플랫폼에서 실행
npm run android
npm run ios
# Expo 호환 의존성 버전 확인
npm run check:expo
# CI 빌드 검증에서 사용하는 web bundle export
npm run build
# app.json에 starter 식별자가 남아 있으면 스토어 배포 preflight 실패
npm run check:store-ready
# 버전 업 (app.json + package.json 자동 업데이트)
npm run version:patch # 1.0.0 -> 1.0.1
npm run version:minor # 1.0.0 -> 1.1.0
npm run version:major # 1.0.0 -> 2.0.0
# 린트 & 테스트
npm run lint
npm test| 이 템플릿 | 처음부터 직접 | |
|---|---|---|
| CI/CD | 풀 파이프라인 포함 | 직접 설정 |
| EAS 설정 | 빌드 프로필 사전 구성 | 문서 읽고 시행착오 |
| 스토어 배포 | GitHub Actions에서 원클릭 | 매번 수동 eas build + eas submit |
| 버전 관리 | npm run version:patch 자동 범프 |
app.json 직접 수정 |
| 설정 가이드 | 단계별 문서 포함 | Expo, Apple, Google 문서 여기저기 |
| AI/바이브코딩 | LLM이 깔끔한 Expo 코드 생성 | LLM이 커스텀 설정을 이해해야 함 |
| 첫 배포까지 | 수 분 (스토어 계정 설정 후) | 설정에 수 시간 |
핵심: EAS가 클라우드에서 네이티브 빌드를 처리합니다 -- CI/CD에 로컬 Xcode나 Android Studio가 필요 없습니다. 이 템플릿은 그것을 GitHub Actions에 연결해서 첫날부터 원클릭 배포를 제공합니다.
Google 로그인이 expo-auth-session + expo-secure-store 조합으로 이미 연결되어 있습니다. app/(app)/ 아래 라우트는 인증 필수이며, 로그아웃 상태면 /login으로 자동 리다이렉트됩니다. 토큰은 iOS Keychain / Android Keystore에 저장되며, AsyncStorage는 사용하지 않습니다.
설정:
- Google Cloud Console → 사용자 인증 정보 → OAuth 클라이언트 ID 만들기. 세 개 생성:
- 웹 애플리케이션 (필수 — 개발 시 Expo AuthSession 프록시가 사용)
- iOS — 번들 ID =
app.json의ios.bundleIdentifier - Android — 패키지 =
android.package, 키스토어의 SHA-1 (eas credentials로 확인 가능)
cp .env.example .env후 클라이언트 ID 붙여넣기:EXPO_PUBLIC_GOOGLE_WEB_CLIENT_ID=... EXPO_PUBLIC_GOOGLE_IOS_CLIENT_ID=... EXPO_PUBLIC_GOOGLE_ANDROID_CLIENT_ID=...npx expo start실행 후 Continue with Google 탭.
클라이언트 ID가 없으면 로그인 버튼이 크래시 없이 명확한 에러 메시지를 표시합니다. 다른 provider로 바꾸려면 lib/auth-context.js에서 expo-auth-session/providers/google만 교체하면 됩니다.
문서: Expo Google 인증 가이드.
이 템플릿은 가볍게 유지하기 위해 JavaScript를 사용합니다. TypeScript가 필요하면:
devDependencies에typescript와@types/react추가tsconfig.json추가.js파일을.tsx로 변경
Expo는 TypeScript를 기본 지원합니다 -- 추가 설정 불필요.
- 클라우드 빌드 우선. EAS가 기기 외부에서 네이티브 바이너리를 컴파일하므로, 로컬 Xcode/Android Studio 없이도 CI/CD가 동작합니다.
- 라우트 그룹 기반 인증.
app/(app)/이 보호 영역입니다 — 화면마다 "인증 확인" 코드를 흩뿌리지 않습니다. - OS 키체인에 시크릿 저장. 토큰은
expo-secure-store를 통해 iOS Keychain / Android Keystore로 들어가며,AsyncStorage에는 절대 저장되지 않습니다. - 모든 push에서 lint·test·Expo check·build·audit. 공급망 하드닝(
--ignore-scripts, high-severity audit gate, pinned gitleaks, CodeQL)이 기본 활성화 — 사후 작업이 아닙니다.
- TypeScript 기본. 템플릿을 가볍게 유지하기 위해 JS로 시작합니다. 위 안내에 따라 선택적으로 전환할 수 있습니다.
- 커스텀 네이티브 모듈.
expo prebuild+ 네이티브 코드가 필요한 경우는 범위 밖입니다. bare workflow를 사용하세요. - 백엔드. 클라이언트만 포함됩니다. 별도 API 레포와 조합하세요.
- 상태 관리 라이브러리. Redux/Zustand 등을 포함하지 않습니다 — 인증 컨텍스트가 유일한 전역 상태입니다.
PR 환영합니다. PR 템플릿을 사용해 주세요.