26년 반기를 돌아보면서
Google Sign-In 릴리스 설정 수정 PR
요약
이번 작업은 Flutter 클라이언트의 Android 릴리스 빌드에서 Google Sign-In이 PlatformException(sign_in_failed)로 실패하던 문제를 조사하고 수정한 내용입니다.
핵심 수정은 다음과 같습니다.
- Dart 소스에 하드코딩되어 있던 Google OAuth
serverClientId제거 - Android에서는
android/app/google-services.json에서 생성되는default_web_client_id를 사용하도록 변경 - Firebase 설정에 릴리스 서명 SHA-1 기반 Android OAuth 클라이언트 추가
- Google Sign-In 실패 시 원인을 더 명확히 알 수 있도록 예외 메시지 개선
- 재발 방지를 위한 테스트와 README 문서 추가
커밋:
2a2f7d7 Fix Google Sign-In release config
문제 상황
릴리스 실행 명령으로 앱을 실행했을 때 Google 로그인 단계에서 다음 문제가 발생했습니다.
PlatformException(sign_in_failed)
초기 상태에서 확인한 내용은 다음과 같습니다.
- Firebase SHA-1 / SHA-256 등록은 이미 진행했다고 알려져 있었음
android/app/google-services.json은 Firebase에서 다시 다운로드해 교체한 상태였음GrpcAuthRemoteDataSource안에 Google OAuth client ID가 하드코딩되어 있었음- Android 릴리스 빌드가 실제로 어떤 서명 키로 설치되는지와 Firebase JSON 안의 Android OAuth client가 일치하는지 확인이 필요했음
조사한 항목
저장소 전체에서 다음 키워드와 설정을 확인했습니다.
serverClientIdclientIdGoogleSignIndefault_web_client_idapps.googleusercontent.comgoogle-services.json- Android Gradle Google Services plugin 적용 여부
- Android package name
- Firebase project id / project number
- iOS Google Sign-In plist 설정
- 인증 gRPC 흐름
- Google ID token 전달 경로
- 로그와 예외 처리 방식
확인한 주요 파일:
flutter_client/lib/features/auth/data/auth_remote_data_source.dart
flutter_client/lib/features/auth/data/auth_repository.dart
flutter_client/lib/features/auth/providers/auth_repository_provider.dart
flutter_client/lib/main.dart
flutter_client/lib/features/auth/data/grpc_gen/auth/v1/auth.pb.dart
flutter_client/android/app/google-services.json
flutter_client/android/app/build.gradle.kts
flutter_client/android/settings.gradle.kts
flutter_client/pubspec.yaml
flutter_client/pubspec.lock
flutter_client/ios/Runner/Info.plist
flutter_client/ios/Runner/GoogleService-Info.plist
flutter_client/README.md
원인
하드코딩되어 있던 값 자체는 Android OAuth client가 아니라 Web OAuth client였습니다.
즉, 아래 값은 serverClientId로 쓰면 안 되는 Android client가 아니라, client_type: 3인 Web client였습니다.
44649239380-2pqbv44f0hb68vu90t7f7bl2vqltl5pq.apps.googleusercontent.com
하지만 Android에서는 이 값을 Dart에 직접 하드코딩할 필요가 없습니다. 현재 사용하는 google_sign_in Android 구현은 Google Services Gradle plugin이 생성하는 default_web_client_id를 자동으로 읽을 수 있습니다.
실제 로그인 실패의 더 중요한 원인은 google-services.json의 Android OAuth client가 릴리스 서명 키와 일치하지 않았던 점입니다.
초기 google-services.json에는 debug SHA-1 기반 Android OAuth client만 있었습니다.
debug SHA-1:
9E:8A:83:07:FD:6F:9E:D0:52:07:4D:B7:D1:5F:38:E7:6D:C6:42:81
하지만 flutter run --release는 릴리스 키로 앱을 설치합니다.
release SHA-1:
A4:AC:9F:60:F4:C4:7C:CF:13:B7:9C:61:91:FD:B2:B2:BE:C4:72:EC
따라서 Firebase / Google Cloud OAuth 설정에 릴리스 SHA-1 기반 Android OAuth client가 없으면 릴리스 빌드에서 Google Sign-In이 실패합니다.
수정 내용
1. Dart 하드코딩 제거
변경 파일:
flutter_client/lib/features/auth/data/auth_remote_data_source.dart
기존에는 다음처럼 Web OAuth client ID가 Dart 소스에 직접 들어가 있었습니다.
final googleSignIn = GoogleSignIn(serverClientId: serverClientId);
수정 후에는 플랫폼 설정을 사용하도록 변경했습니다.
static GoogleSignIn createGoogleSignIn() => GoogleSignIn();
Android에서는 google-services.json -> Google Services Gradle plugin -> default_web_client_id 흐름을 사용합니다.
2. Google Sign-In 예외 메시지 개선
Google Sign-In 실패가 단순한 Exception으로 처리되지 않도록 GoogleAuthException을 추가했습니다.
이제 다음 상황에서 더 명확한 메시지를 제공합니다.
- 사용자가 계정 선택을 취소한 경우
- Google Sign-In platform call 자체가 실패한 경우
- ID token이 반환되지 않은 경우
- Android package / SHA fingerprint /
default_web_client_id설정 문제가 의심되는 경우
토큰이나 전체 인증 정보는 로그에 출력하지 않습니다.
3. Android Firebase 설정 갱신
변경 파일:
flutter_client/android/app/google-services.json
새 파일에는 Android OAuth client가 두 개 있습니다.
debug Android OAuth client
SHA-1: 9e8a8307fd6f9ed052074db7d15f38e76dc64281
release Android OAuth client
client_id: 44649239380-e08vigdh9hig86v6bk4iip1lijtej6re.apps.googleusercontent.com
SHA-1: a4ac9f60f4c47ccf13b79c6191fdb2b2bec472ec
Web OAuth client도 유지되어 있습니다.
client_type: 3
client_id: 44649239380-2pqbv44f0hb68vu90t7f7bl2vqltl5pq.apps.googleusercontent.com
이 Web client는 Android에서 default_web_client_id로 생성됩니다.
4. 테스트 추가
변경 파일:
flutter_client/test/auth_remote_data_source_test.dart
추가한 테스트는 GrpcAuthRemoteDataSource가 Google Sign-In을 생성할 때 clientId와 serverClientId를 직접 지정하지 않는지 확인합니다.
expect(googleSignIn.clientId, isNull);
expect(googleSignIn.serverClientId, isNull);
5. README 문서 추가
변경 파일:
flutter_client/README.md
추가한 내용:
- Android Google Sign-In 설정의 source of truth는
android/app/google-services.json - Dart에 OAuth client ID를 하드코딩하지 않는 이유
default_web_client_id생성 확인 명령- 릴리스 빌드에서는
signingReport와 Firebase JSON의 SHA-1 / SHA-256을 비교해야 한다는 점 - 릴리스 실행 시 필요한 auth gRPC dart-define 예시
검증 결과
Google Services resource 생성
실행:
cd flutter_client/android
./gradlew :app:processReleaseGoogleServices
결과:
BUILD SUCCESSFUL
생성된 resource 확인:
grep -R "default_web_client_id" ../build/app/generated -n
결과:
../build/app/generated/res/processReleaseGoogleServices/values/values.xml:3:
<string name="default_web_client_id" translatable="false">44649239380-2pqbv44f0hb68vu90t7f7bl2vqltl5pq.apps.googleusercontent.com</string>
릴리스 서명 확인
실행:
cd flutter_client/android
./gradlew :app:signingReport
확인한 릴리스 서명:
Variant: release
Store: android/app/upload-keystore.jks
Alias: upload
SHA1: A4:AC:9F:60:F4:C4:7C:CF:13:B7:9C:61:91:FD:B2:B2:BE:C4:72:EC
SHA-256: 4E:DD:0A:0C:3A:86:70:11:91:9A:B8:0C:D7:9E:A5:CF:F4:BA:73:BC:86:4C:57:EF:69:99:9A:A6:B7:30:47:22
현재 google-services.json에는 위 릴리스 SHA-1에 대응하는 Android OAuth client가 포함되어 있습니다.
Flutter 검증
실행:
flutter clean
flutter pub get
flutter test test/auth_remote_data_source_test.dart
flutter test test/widget_test.dart
결과:
auth_remote_data_source_test.dart: passed
widget_test.dart: passed
flutter analyze도 실행했습니다.
결과는 인증 변경과 무관한 기존 info issue 2개가 남아 있습니다.
lib/features/profile/user_page_screen.dart:4:8
unnecessary_import
lib/features/profile/user_page_screen.dart:85:11
deprecated_member_use: cacheExtent
이번 PR에 포함된 파일
flutter_client/README.md
flutter_client/android/app/google-services.json
flutter_client/lib/features/auth/data/auth_remote_data_source.dart
flutter_client/test/auth_remote_data_source_test.dart
이번 PR에서 제외한 로컬 변경
다음 파일들은 현재 작업 트리에 남아 있지만 이번 Google Sign-In PR 커밋에는 포함하지 않았습니다.
flutter_client/android/app/build.gradle.kts
flutter_client/android/gradle.properties
flutter_client/ios/Runner.xcodeproj/project.pbxproj
flutter_client/pubspec.yaml
flutter_client/android/app/build.gradle.kts.debug-signing.backup
flutter_client/android/key.properties.example
flutter_client/assets/on-the-block-white Medium.jpeg
flutter_client/ios/Flutter/Profile.xcconfig
이유:
- Android release signing Gradle 변경은 팀원 릴리스 빌드 방식에 영향을 줄 수 있음
key.properties.example은 별도 release signing 문서/정책으로 다루는 편이 안전함- iOS project / Profile.xcconfig 변경은 이번 Android Google Sign-In 수정과 직접 관련 없음
pubspec.yamlversion bump는 인증 수정과 별도 릴리스 관리 이슈임- 이미지 asset 추가는 이번 인증 PR 범위 밖임
클라이언트 개발 진행 상황 메모
이번 작업 기준으로 클라이언트는 다음 방향으로 정리되고 있습니다.
- 인증 흐름은
AuthRemoteDataSource-> gRPCAuthService로 연결되어 있음 - Google Sign-In은 모바일 플랫폼 설정을 사용하고, 앱은 Google ID token만 backend authorization service로 전달함
- backend authorization protocol은 변경하지 않았음
- Android package name은
com.ontheblockand.app그대로 유지함 - Firebase project는
on-the-block-2026그대로 유지함 - gRPC endpoint 설정은
--dart-define기반으로 유지함 - gateway, chat, survey, board, map service endpoint는 실행 명령에서 환경별로 주입하는 구조를 유지함
릴리스 실행 예시
아래 명령은 현재 사용 중인 staging / Cloud Run endpoint 조합으로 릴리스 실행할 때 사용한 형태입니다.
flutter run --release \
--dart-define=GATEWAY_BASE_URL=https://gateway-service-44649239380.asia-northeast3.run.app \
--dart-define=APP_GATEWAY_GRPC_HOST=gateway-service-44649239380.asia-northeast3.run.app \
--dart-define=APP_GATEWAY_GRPC_PORT=443 \
--dart-define=APP_GATEWAY_GRPC_TLS=true \
--dart-define=AUTH_GRPC_HOST=authorization-service-vcuepibcwq-du.a.run.app \
--dart-define=AUTH_GRPC_PORT=443 \
--dart-define=AUTH_GRPC_TLS=true \
--dart-define=CHAT_GRPC_HOST=chat-service-staging-44649239380.asia-northeast3.run.app \
--dart-define=CHAT_GRPC_PORT=443 \
--dart-define=CHAT_GRPC_TLS=true \
--dart-define=SURVEY_GRPC_HOST=survey-service-44649239380.asia-northeast3.run.app \
--dart-define=SURVEY_GRPC_PORT=443 \
--dart-define=SURVEY_GRPC_TLS=true \
--dart-define=BOARD_GRPC_HOST=gateway-service-44649239380.asia-northeast3.run.app \
--dart-define=BOARD_GRPC_PORT=443 \
--dart-define=BOARD_GRPC_TLS=true \
--dart-define=MAP_API_BASE_URL=https://map-service-44649239380.asia-northeast3.run.app/ \
--dart-define=KAKAO_MAP_API_KEY=<local-key> \
--dart-define=KAKAO_REST_API_KEY=<local-key>
주의:
- Kakao key 값은 실제 값을 문서나 PR에 노출하지 않습니다.
- Google OAuth client ID는 설정 파일에 포함되는 값이지만 auth token은 절대 로그나 문서에 남기지 않습니다.
리뷰어 확인 포인트
auth_remote_data_source.dart에서 OAuth client ID 하드코딩이 제거되었는지google-services.json에 debug / release Android OAuth client가 모두 있는지default_web_client_id가 Web OAuth client로 생성되는지- backend
GoogleLoginRequest.idToken프로토콜이 변경되지 않았는지 - 이번 PR에 release signing Gradle 변경 같은 팀원 영향 큰 변경이 섞이지 않았는지
후속 작업
- 실제 Android 기기에서
flutter run --release로 Google Sign-In 재확인 - Google Play 배포를 시작할 경우 Play Console의 App Signing certificate SHA-1 / SHA-256도 Firebase에 등록
flutter analyze의 기존 profile 화면 info issue 정리- release signing Gradle 변경은 별도 PR로 분리 검토
댓글