[G1-Sync] Manual knowledge update
This commit is contained in:
@@ -0,0 +1,347 @@
|
||||
---
|
||||
id: mobile-testflight-distribution
|
||||
title: Beta Distribution — TestFlight / Firebase / internal
|
||||
category: Coding
|
||||
status: draft
|
||||
source_trust_level: B
|
||||
verification_status: conceptual
|
||||
created_at: 2026-05-09
|
||||
updated_at: 2026-05-09
|
||||
tags: [mobile, beta, testflight, vibe-coding]
|
||||
tech_stack: { language: "process", applicable_to: ["Mobile"] }
|
||||
applied_in: []
|
||||
aliases: [TestFlight, Firebase App Distribution, internal beta, external beta, Play Store internal track]
|
||||
---
|
||||
|
||||
# Beta Distribution
|
||||
|
||||
> Production 전에 internal / external beta. **TestFlight (iOS), Play Store internal track + Firebase App Distribution (Android)**. 빠른 iterate + early feedback.
|
||||
|
||||
## 📖 핵심 개념
|
||||
- Internal: 팀 (개발 / QA).
|
||||
- External: 선택 사용자 (beta tester).
|
||||
- Public beta: 모든 사용자 (open).
|
||||
- 매 build = beta → review.
|
||||
|
||||
## 💻 코드 패턴
|
||||
|
||||
### TestFlight (iOS)
|
||||
```
|
||||
1. Xcode → Product → Archive
|
||||
2. Distribute → App Store Connect
|
||||
3. 처리 (5-30 min) → TestFlight
|
||||
4. Internal: 100 테스터 (instant)
|
||||
5. External: 10000 테스터 (Apple review 1-2 days)
|
||||
```
|
||||
|
||||
### TestFlight 그룹
|
||||
```
|
||||
Internal Group:
|
||||
- 매 team member (App Store Connect access)
|
||||
- 즉시 update
|
||||
- 90 days 만료
|
||||
|
||||
External Group:
|
||||
- 외부 사용자 (email + name)
|
||||
- Apple review (첫 build)
|
||||
- Public link 가능
|
||||
```
|
||||
|
||||
### Internal 추가
|
||||
```
|
||||
App Store Connect → Users and Access → Add user.
|
||||
Role: Developer / Marketing / etc.
|
||||
TestFlight access: ON.
|
||||
```
|
||||
|
||||
### External 추가 (email)
|
||||
```
|
||||
TestFlight tab → External Group → Add testers.
|
||||
- Email
|
||||
- 또는 public link (URL 하나)
|
||||
```
|
||||
|
||||
### Public link
|
||||
```
|
||||
- "Join beta" link
|
||||
- 무한 invite (limit 10000)
|
||||
- Limit 가능 (300 user 면 close)
|
||||
- Link 노출 → 누구나 = OK
|
||||
```
|
||||
|
||||
### Build expiration
|
||||
```
|
||||
TestFlight build = 90 days 만료.
|
||||
|
||||
→ 매 90 days 새 build 필요.
|
||||
또는 expiry 전 새 build (더 좋음).
|
||||
```
|
||||
|
||||
### What to test
|
||||
```
|
||||
TestFlight 가 "What to Test" 표시.
|
||||
|
||||
Markdown 가능.
|
||||
- 새 feature
|
||||
- Test 가 focus
|
||||
- Known issue
|
||||
- Feedback 요청
|
||||
|
||||
→ Tester 가 무엇 test 모름.
|
||||
```
|
||||
|
||||
### Feedback (TestFlight)
|
||||
```
|
||||
- Screenshot 캡처 (iOS shake / volume)
|
||||
- 자동 attach + crash log
|
||||
- Email 으로 form
|
||||
- App Store Connect 에 표시
|
||||
```
|
||||
|
||||
→ Email 보다 in-app feedback 친화.
|
||||
|
||||
### Firebase App Distribution (Android / iOS)
|
||||
```bash
|
||||
# Setup
|
||||
firebase login
|
||||
firebase init appdistribution
|
||||
|
||||
# Distribute
|
||||
firebase appdistribution:distribute app.apk \
|
||||
--app 1:1234567890:android:abcdef \
|
||||
--release-notes "Bug fixes" \
|
||||
--groups "qa-team"
|
||||
```
|
||||
|
||||
→ iOS / Android 둘 다. Email + Firebase app.
|
||||
|
||||
### Play Store Internal Track
|
||||
```
|
||||
Google Play Console → Testing → Internal testing.
|
||||
- 100 user limit
|
||||
- 즉시 (review X)
|
||||
- Email 가입
|
||||
```
|
||||
|
||||
### Play Store Closed / Open Testing
|
||||
```
|
||||
Closed: external (1k+ tester)
|
||||
Open: 모두 (Play Store 검색 가능, "Beta" 라벨)
|
||||
|
||||
→ Closed = staging.
|
||||
Open = public beta.
|
||||
```
|
||||
|
||||
### Play Store track
|
||||
```
|
||||
internal → closed → open → production
|
||||
|
||||
매 단계 = 별 release.
|
||||
Promote = 한 번에 다음 track 으로.
|
||||
```
|
||||
|
||||
### Fastlane (자동)
|
||||
```ruby
|
||||
# Fastfile
|
||||
lane :beta do
|
||||
match(type: 'appstore') # cert
|
||||
build_app(scheme: 'MyApp')
|
||||
upload_to_testflight(
|
||||
skip_waiting_for_build_processing: true,
|
||||
changelog: "Beta update",
|
||||
distribute_external: true,
|
||||
groups: ['Beta Testers'],
|
||||
)
|
||||
end
|
||||
```
|
||||
|
||||
```bash
|
||||
fastlane beta
|
||||
```
|
||||
|
||||
→ Local 또는 CI 가 한 번에 archive + upload.
|
||||
|
||||
### Android 자동 (Fastlane)
|
||||
```ruby
|
||||
lane :playstore_internal do
|
||||
gradle(task: 'bundle', build_type: 'Release')
|
||||
upload_to_play_store(
|
||||
track: 'internal',
|
||||
aab: 'app/build/outputs/bundle/release/app-release.aab',
|
||||
)
|
||||
end
|
||||
```
|
||||
|
||||
### CI (GitHub Actions)
|
||||
```yaml
|
||||
- uses: actions/checkout@v4
|
||||
- run: bundle install
|
||||
- run: bundle exec fastlane beta
|
||||
env:
|
||||
APP_STORE_CONNECT_API_KEY: ${{ secrets.APP_STORE_API_KEY }}
|
||||
```
|
||||
|
||||
### Code signing (iOS)
|
||||
```
|
||||
match (Fastlane):
|
||||
- Cert + provisioning profile in private git repo
|
||||
- 모든 dev / CI 가 같은 cert
|
||||
|
||||
→ "code signing 안 됨" 문제 해결.
|
||||
```
|
||||
|
||||
```bash
|
||||
fastlane match appstore
|
||||
```
|
||||
|
||||
### Build number 자동
|
||||
```ruby
|
||||
# Fastfile
|
||||
lane :beta do
|
||||
increment_build_number(xcodeproj: 'MyApp.xcodeproj')
|
||||
build_app
|
||||
upload_to_testflight
|
||||
end
|
||||
```
|
||||
|
||||
→ 매 beta = 새 build number (자동).
|
||||
|
||||
### Versioning
|
||||
```
|
||||
1.2.3 (build 45)
|
||||
|
||||
Major.Minor.Patch + Build.
|
||||
|
||||
Build = 매 upload.
|
||||
Patch = bug fix (1.2.3 → 1.2.4).
|
||||
Minor = 새 feature (1.2.3 → 1.3.0).
|
||||
Major = breaking (1.2.3 → 2.0.0).
|
||||
```
|
||||
|
||||
### Crash 추적 (beta)
|
||||
```swift
|
||||
// Sentry / Crashlytics
|
||||
import Sentry
|
||||
SentrySDK.start { o in
|
||||
o.dsn = "..."
|
||||
o.environment = "beta"
|
||||
o.tracesSampleRate = 1.0
|
||||
}
|
||||
```
|
||||
|
||||
→ Beta crash = critical signal.
|
||||
|
||||
### Phased rollout (production)
|
||||
```
|
||||
App Store: phased release (7 days).
|
||||
- Day 1: 1%
|
||||
- Day 2: 2%
|
||||
- Day 7: 100%
|
||||
|
||||
Play Store: staged rollout (X%).
|
||||
```
|
||||
|
||||
→ Crash 발견 시 halt.
|
||||
|
||||
### Rollback (Play Store 만)
|
||||
```
|
||||
Play Console → 옛 release 다시 publish.
|
||||
→ 새 install 가 옛 version.
|
||||
|
||||
iOS = rollback 안 됨. 새 release 가 fix.
|
||||
```
|
||||
|
||||
### Beta 관리
|
||||
```
|
||||
- Tester 그룹 (segments)
|
||||
- Feedback channel (Slack, Discord, email)
|
||||
- 매 release = 매 변경 list
|
||||
- Critical bug 가 아닌 = 다음 build
|
||||
```
|
||||
|
||||
### TestFlight invite UX
|
||||
```
|
||||
1. User 가 email click
|
||||
2. TestFlight app 다운로드 (없으면)
|
||||
3. 가입 + redeem code
|
||||
4. Beta app install
|
||||
|
||||
→ 3 step 가 pain. Public link 가 더 부드러움.
|
||||
```
|
||||
|
||||
### Demo build (다른 ID)
|
||||
```
|
||||
Build configuration:
|
||||
- Production: com.app
|
||||
- Beta: com.app.beta
|
||||
- Demo: com.app.demo
|
||||
|
||||
→ Tester 가 production 과 beta 동시 install.
|
||||
```
|
||||
|
||||
### LinkedIn / external review
|
||||
```
|
||||
일부 tester:
|
||||
- Power user 가 좋음
|
||||
- Diverse device (구 iPhone, 작은 storage)
|
||||
- 자주 보고
|
||||
|
||||
→ 50명 < 5000 명 (engagement 가 중요).
|
||||
```
|
||||
|
||||
### Play Open testing → production
|
||||
```
|
||||
Open testing 의 user 가 production track 으로 자동 이동.
|
||||
- "Beta" 라벨 사라짐
|
||||
- 같은 update 받음
|
||||
|
||||
→ Soft launch.
|
||||
```
|
||||
|
||||
### 비용
|
||||
```
|
||||
TestFlight: 무료 (Apple Developer $99/year 포함).
|
||||
Firebase App Distribution: 무료 (15k user 까지).
|
||||
Play Console: 무료 ($25 one-time).
|
||||
Fastlane: 무료.
|
||||
```
|
||||
|
||||
### Beta 함정
|
||||
```
|
||||
- Build expiration 간과 (90 days)
|
||||
- "What to test" 안 적음
|
||||
- Crash 무시 (production 에 가져감)
|
||||
- Tester 안 답 (ghost beta)
|
||||
- 너무 잦은 build (test 불가)
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준
|
||||
| 단계 | 추천 |
|
||||
|---|---|
|
||||
| Internal QA | Internal group (TestFlight / Play internal) |
|
||||
| External beta (작음) | Closed group + email |
|
||||
| Public beta | Public link + Open testing |
|
||||
| Crash 추적 | Sentry / Crashlytics |
|
||||
| 자동화 | Fastlane + match |
|
||||
| Multi-platform | Firebase App Distribution |
|
||||
| Phased prod | Phased release / staged rollout |
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **Direct production**: bug 가 모든 사용자.
|
||||
- **Beta tester 0명**: feedback 없음.
|
||||
- **"What to test" 없음**: tester 가 뭐 할지 모름.
|
||||
- **Crash report 무시**: production 가져감.
|
||||
- **Manual upload**: 매번 30 min.
|
||||
- **Build version 가 같음**: TestFlight reject.
|
||||
- **Phased rollout 무시**: 1% 가 100% 가능.
|
||||
|
||||
## 🤖 LLM 활용 힌트
|
||||
- TestFlight (iOS) + Play Internal Track (Android) = baseline.
|
||||
- Fastlane + match = 자동 + 안정.
|
||||
- Firebase App Distribution = cross-platform.
|
||||
- Crash + feedback channel 항상.
|
||||
|
||||
## 🔗 관련 문서
|
||||
- [[Mobile_CI_CD_Fastlane]]
|
||||
- [[Mobile_Crash_Free_SLO]]
|
||||
- [[Mobile_App_Store_Optimization]]
|
||||
Reference in New Issue
Block a user