iOS 배포 구성 — 서명 팀 · Firebase 설정 번들 · 업로드 스크립트

This commit is contained in:
Sn-Kinos
2026-10-04 01:43:10 +09:00
parent 613798b863
commit e255973a8d
8 changed files with 349 additions and 37 deletions
+58
View File
@@ -0,0 +1,58 @@
#!/usr/bin/env python3
"""GoogleService-Info.plist 의 REVERSED_CLIENT_ID 를 Xcode 빌드 설정에 넣는다.
**왜 스크립트인가.** Google 로그인 콜백 스킴은 Firebase 프로젝트마다 다르고,
Info.plist 에 손으로 옮기면 오타 한 글자에 로그인이 **조용히** 실패한다.
오류도 뜨지 않고 콜백만 돌아오지 않아 원인을 찾는 데 한나절이 든다.
설정 파일이 투입될 때 한 번 돌리면 `ios/config/Google.xcconfig` 가 만들어지고,
Info.plist 의 `$(GOOGLE_REVERSED_CLIENT_ID)` 가 그 값으로 치환된다.
실행: python3 tools/ios/inject_url_scheme.py
"""
from __future__ import annotations
import plistlib
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parents[2]
SOURCE = ROOT / "ios/Runner/GoogleService-Info.plist"
OUT = ROOT / "ios/config/Google.xcconfig"
def main() -> int:
if not SOURCE.exists():
print(
f"설정 파일이 아직 없습니다: {SOURCE.relative_to(ROOT)}\n"
"Firebase 프로젝트를 연 뒤 firebase/setup-project.sh 를 돌리십시오.",
file=sys.stderr,
)
return 1
with SOURCE.open("rb") as f:
data = plistlib.load(f)
reversed_id = data.get("REVERSED_CLIENT_ID")
if not reversed_id:
# Firebase 콘솔에서 Google 로그인을 켜지 않으면 이 키가 빠진 채로 나온다.
print(
"REVERSED_CLIENT_ID 가 없습니다. Firebase 콘솔에서 "
"Authentication → Google 제공자를 켠 뒤 설정 파일을 다시 받으십시오.",
file=sys.stderr,
)
return 1
OUT.parent.mkdir(parents=True, exist_ok=True)
OUT.write_text(
"// 자동 생성 — tools/ios/inject_url_scheme.py\n"
"// GoogleService-Info.plist 가 바뀌면 다시 돌리십시오.\n"
f"GOOGLE_REVERSED_CLIENT_ID = {reversed_id}\n",
encoding="utf-8",
)
print(f"기록: {OUT.relative_to(ROOT)}")
return 0
if __name__ == "__main__":
raise SystemExit(main())
+66
View File
@@ -0,0 +1,66 @@
#!/usr/bin/env bash
# iOS 아카이브 → TestFlight 업로드.
#
# **계정이 열린 날 이 스크립트 하나로 끝나게 하는 것이 목적**이다. 별첨 2 가
# 3주차부터 매주 TestFlight 제출을 요구했고 그것을 지키지 못했으므로(미이행 F-2),
# 계정이 열리면 지체 없이 재개되어야 한다.
#
# 사전 조건
# 1. ios/Runner/GoogleService-Info.plist 배치 · tools/ios/inject_url_scheme.py 실행
# 2. Xcode 정식판을 `xcode-select` 로 지정 (베타 SDK 빌드는 업로드가 거부된다)
# 3. App Store Connect API 키 (환경변수 3종)
#
# 실행:
# export ASC_KEY_ID=... ASC_ISSUER_ID=... ASC_KEY_PATH=~/private_keys/AuthKey_XXX.p8
# bash tools/ios/upload_testflight.sh
set -euo pipefail
ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
APP="$ROOT"
ARCHIVE="$APP/build/ios/Runner.xcarchive"
EXPORT_DIR="$APP/build/ios/ipa"
OPTIONS="$APP/ios/ExportOptions.plist"
if grep -q REPLACE_WITH_TEAM_ID "$OPTIONS"; then
echo "ExportOptions.plist 의 teamID 를 먼저 채우십시오." >&2
exit 1
fi
for var in ASC_KEY_ID ASC_ISSUER_ID ASC_KEY_PATH; do
if [ -z "${!var:-}" ]; then
echo "환경변수 $var 이 없습니다." >&2
exit 1
fi
done
echo "▸ 아카이브"
cd "$APP"
flutter build ipa --release --export-options-plist="$OPTIONS"
# flutter build ipa 가 아카이브와 내보내기를 함께 한다. 실패했을 때만 손으로 나눈다.
IPA="$(find "$EXPORT_DIR" -name '*.ipa' -maxdepth 1 | head -1)"
if [ -z "$IPA" ]; then
echo "IPA 를 찾지 못했습니다. 아카이브만 따로 시도합니다." >&2
xcodebuild -workspace ios/Runner.xcworkspace -scheme Runner \
-configuration Release -archivePath "$ARCHIVE" archive
xcodebuild -exportArchive -archivePath "$ARCHIVE" \
-exportOptionsPlist "$OPTIONS" -exportPath "$EXPORT_DIR"
IPA="$(find "$EXPORT_DIR" -name '*.ipa' -maxdepth 1 | head -1)"
fi
echo "▸ 검증"
xcrun altool --validate-app -f "$IPA" -t ios \
--apiKey "$ASC_KEY_ID" --apiIssuer "$ASC_ISSUER_ID"
echo "▸ 업로드"
xcrun altool --upload-app -f "$IPA" -t ios \
--apiKey "$ASC_KEY_ID" --apiIssuer "$ASC_ISSUER_ID"
cat <<'DONE'
업로드했습니다. 남은 것 둘.
1. App Store Connect 에서 처리가 끝나면(보통 10~30분) TestFlight 탭에 뜹니다.
2. 발주사 담당자 이메일을 외부 테스터로 초대하십시오.
수출 규정 응답은 Info.plist 의 ITSAppUsesNonExemptEncryption 이 대신합니다.
DONE