164 lines
7.0 KiB
Markdown
164 lines
7.0 KiB
Markdown
# 빌드 환경 — 실측 기록 (2026-08-31)
|
|
|
|
이 조합으로 **릴리스 APK·AAB 가 실제로 나오는 것을 확인**했다. 버전 조합이 어긋나면
|
|
Gradle 이 조용히 실패하지 않고 명확히 죽으므로 아래를 그대로 맞춘다.
|
|
|
|
| 구성 | 값 | 비고 |
|
|
|---|---|---|
|
|
| Flutter | **3.47.2** | `fvm` 으로 고정 — `app/.fvmrc` |
|
|
| JDK | **Temurin 17** | `~/.jdks/jdk-17.0.20.1+1/Contents/Home` |
|
|
| Gradle | 8.14 | `android/gradle/wrapper/gradle-wrapper.properties` |
|
|
| AGP | 8.11.1 | `android/settings.gradle.kts` |
|
|
| Android SDK | `/opt/homebrew/share/android-commandlinetools` | `brew install --cask android-commandlinetools` |
|
|
| build-tools | 35.0.1 | |
|
|
| platform | android-34 · android-36 | 빌드가 34 를 추가로 받는다 |
|
|
|
|
## JDK 를 17 로 못 박은 이유
|
|
|
|
Android Studio 번들 JBR 은 **JDK 25** 이고 **Gradle 8.14 와 비호환**이다. 그대로 빌드하면
|
|
`Gradle build failed due to Java/Gradle incompatibility` 로 죽는다. Gradle 을 9.1+ 로
|
|
올리는 선택지도 있으나 AGP 8.11.1 과의 조합을 다시 검증해야 하므로, Flutter 권장인
|
|
JDK 17 을 쓰는 쪽을 택했다.
|
|
|
|
```bash
|
|
fvm flutter config --jdk-dir ~/.jdks/jdk-17.0.20.1+1/Contents/Home
|
|
```
|
|
|
|
`brew install --cask temurin@17` 은 sudo 를 요구한다. sudo 없이 쓰려면 Adoptium
|
|
tar.gz 를 `~/.jdks/` 에 풀면 된다.
|
|
|
|
## 테스트
|
|
|
|
```bash
|
|
export ANDROID_HOME=/opt/homebrew/share/android-commandlinetools
|
|
fvm flutter analyze
|
|
FANUZU_DESIGN_DIR=/path/to/p-fancake/design fvm flutter test
|
|
```
|
|
|
|
`FANUZU_DESIGN_DIR` 은 5탭 계약 대조용이다. 스모크 테스트가
|
|
`craft-allowlist.yaml` 의 `APP_TABS` 를 직접 읽어 앱의 `appTabs` 와 정확 일치를 검증한다.
|
|
**정본은 상위 저장소 `p-fancake/design/craft-allowlist.yaml`** 이고 이 저장소는 분리돼
|
|
있으므로, 같은 파일의 사본을 `design/craft-allowlist.yaml` 로 두었다. 탐색 순서는 아래와 같다.
|
|
|
|
1. `$FANUZU_DESIGN_DIR/craft-allowlist.yaml` — 정본을 직접 가리킬 때 쓴다.
|
|
2. `design/craft-allowlist.yaml` — 이 저장소의 사본.
|
|
3. `../design/craft-allowlist.yaml` · `../p-fancake/design/craft-allowlist.yaml` — p-fancake 와
|
|
형제로 둔 체크아웃.
|
|
|
|
사본이 있으므로 **git worktree 에서도 변수 없이 통과한다.** 그래도 못 찾으면 통과가 아니라
|
|
실패한다 — 계약 대조가 조용히 사라지면 안 된다.
|
|
|
|
사본은 정본과 갈리면 저장소마다 다른 답을 내므로, **정본을 고칠 때 사본에도 함께 복사한다.**
|
|
파일 머리에 같은 문장을 적어 두었다.
|
|
|
|
```bash
|
|
cp /path/to/p-fancake/design/craft-allowlist.yaml design/craft-allowlist.yaml
|
|
# 머리 주석 5줄은 사본에만 있으니 지우지 말고 APP_TABS·CAPS_OK 만 맞춘다.
|
|
```
|
|
|
|
## 빌드
|
|
|
|
```bash
|
|
export ANDROID_HOME=/opt/homebrew/share/android-commandlinetools
|
|
cd app
|
|
fvm flutter build apk --release # build/app/outputs/flutter-apk/app-release.apk
|
|
fvm flutter build appbundle --release # build/app/outputs/bundle/release/app-release.aab
|
|
```
|
|
|
|
## 서명
|
|
|
|
`android/key.properties` 가 없으면 **릴리스 빌드가 의도적으로 실패**한다
|
|
(`android/app/build.gradle.kts`). 디버그 키로 조용히 서명된 산출물이 Play 에서
|
|
거부되는 것을 막기 위한 것이다.
|
|
|
|
키스토어는 `~/.fanuzu-signing/fanuzu-upload.p12` (PKCS12 · 별칭 `fanuzu-upload`).
|
|
**저장소에 넣지 않는다** — `android/.gitignore` 가 `key.properties` 를,
|
|
루트 `.gitignore` 가 `*.p12` `*.jks` 를 막는다.
|
|
|
|
서명 확인:
|
|
|
|
```bash
|
|
apksigner verify --print-certs build/app/outputs/flutter-apk/app-release.apk
|
|
# Signer #1 certificate DN: CN=FANUZU, OU=Development, O=Sweech Co Ltd, L=Daegu, C=KR
|
|
# Signer #1 certificate SHA-256 digest: 5e83f4c9cd35357b11561a5b82c47d300af8c31e33d80d94bc32a4f10f46dee7
|
|
```
|
|
|
|
## 알려진 어긋남 — minSdk
|
|
|
|
문서(`2주차_플러그인_선검증리포트` · 별첨 1)는 **Android 10(API 29)** 을 하한으로 적었으나
|
|
현재 빌드는 **API 24** 로 나간다. 하한을 29 로 올리는 것은 위치 퀘스트의
|
|
`geofence_foreground_service` 인데 아직 넣지 않았다. **6주차 위치 퀘스트 구현 시점에
|
|
29 로 올라간다.** 그때 기준 단말 2종 충족을 다시 확인해 빌드 노트에 적는다.
|
|
|
|
---
|
|
|
|
## iOS
|
|
|
|
**2026-08-31 실증** — `flutter build ios --release --no-codesign` 통과.
|
|
|
|
| 구성 | 값 |
|
|
|---|---|
|
|
| Xcode | **27.0** (`~/Downloads/Xcode-beta.app`) |
|
|
| CocoaPods | 1.17.0 (`brew install cocoapods`) |
|
|
| 산출물 | `build/ios/iphoneos/Runner.app` · 21.7MB · arm64 |
|
|
| bundle id | `kr.co.fanuzu.app` · 0.1.0(1) · label FANUZU |
|
|
| **MinimumOSVersion** | **15.0** — 문서(별첨 1 · 2주차 선검증)와 **일치** |
|
|
|
|
`xcode-select --switch` 는 sudo 를 요구하므로 **`DEVELOPER_DIR` 로 우회**한다.
|
|
|
|
```bash
|
|
export DEVELOPER_DIR=~/Downloads/Xcode-beta.app/Contents/Developer
|
|
fvm flutter build ios --release --no-codesign
|
|
```
|
|
|
|
**서명은 Apple Developer 계정이 있어야 한다.** 계정 없이 여기까지는 확인되므로,
|
|
TestFlight 제출에 남은 것은 **서명과 업로드뿐**이다.
|
|
|
|
### 정리해야 할 것 — CocoaPods / SwiftPM 이중 상태
|
|
|
|
빌드 중 Flutter 가 경고한다.
|
|
|
|
> All plugins found for ios are Swift Packages, but your project still has CocoaPods
|
|
> integration. … Removing CocoaPods integration will improve the project's build time.
|
|
|
|
iOS 플러그인이 전부 Swift Package 로 옮겨졌는데 프로젝트에 CocoaPods 통합이 남아 있다.
|
|
동작에는 지장이 없으나 빌드 시간이 늘고 구성이 이중이다. `pod deintegrate` 와
|
|
`Debug.xcconfig` · `Release.xcconfig` 의 Pods include 제거가 필요하다.
|
|
**11주차 최적화 구간에서 정리한다.**
|
|
|
|
## 서버 없이 로그인을 돌려 보기
|
|
|
|
실 Firebase 프로젝트는 계정 명의가 확정되어야 열 수 있다.
|
|
그 전까지는 **에뮬레이터를 물려 실제 왕복을 돈다.** 설정 파일 대신 에뮬레이터를 붙이는
|
|
것이라, 이 절차가 통과하면 설정 파일이 들어오는 날 코드 수정 없이 동작한다.
|
|
|
|
### 1. 에뮬레이터 기동
|
|
|
|
```
|
|
cd app/firebase
|
|
firebase emulators:start --only auth --project demo-fanuzu
|
|
```
|
|
|
|
**JDK 21 이상이 필요하다.** firebase-tools 15 가 그 아래를 거부한다. Gradle 은 Temurin 17 을
|
|
쓰므로 둘이 다르며, 에뮬레이터를 띄울 때만 `JAVA_HOME` 을 21+ 로 바꾼다.
|
|
|
|
### 2. 앱을 에뮬레이터에 붙이기
|
|
|
|
```
|
|
flutter run --dart-define=FANUZU_EMULATOR_HOST=10.0.2.2 # Android 에뮬레이터
|
|
flutter run --dart-define=FANUZU_EMULATOR_HOST=127.0.0.1 # iOS 시뮬레이터
|
|
```
|
|
|
|
`10.0.2.2` 는 Android 에뮬레이터가 보는 호스트 PC 주소다.
|
|
|
|
### 평문 HTTP 예외에 대하여
|
|
|
|
에뮬레이터는 평문 HTTP 로 뜨는데 Android 9 부터 평문이 기본 차단이다. 예외를
|
|
`android/app/src/{debug,profile}/` 에만 두었으므로 **릴리스 빌드에는 들어가지 않는다.**
|
|
확인:
|
|
|
|
```
|
|
unzip -p build/app/outputs/flutter-apk/app-release.apk AndroidManifest.xml \
|
|
| strings | grep -c networkSecurityConfig # 0 이어야 한다
|
|
```
|