From b66863a149078f49597ef54ea8abda4acd37820e Mon Sep 17 00:00:00 2001 From: Sn-Kinos Date: Thu, 8 Oct 2026 15:44:49 +0900 Subject: [PATCH] =?UTF-8?q?Android=20Apple=20=EB=A1=9C=EA=B7=B8=EC=9D=B8?= =?UTF-8?q?=EC=9D=84=20Firebase=20=EC=9B=B9=20=ED=9D=90=EB=A6=84(apple.com?= =?UTF-8?q?=20=EC=A0=9C=EA=B3=B5=EC=9E=90)=EC=9C=BC=EB=A1=9C=20=EC=97=B0?= =?UTF-8?q?=EA=B2=B0=20=C2=B7=20=EC=84=A4=EC=A0=95=20=EC=95=88=EB=82=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/BUILD.md | 14 ++++++++++++++ app/README.md | 2 +- app/lib/features/auth/auth_repository.dart | 13 ++++++++++--- app/lib/features/auth/social_providers.dart | 19 ------------------- app/test/auth_oidc_test.dart | 18 ++++++++++++++++++ 5 files changed, 43 insertions(+), 23 deletions(-) diff --git a/app/BUILD.md b/app/BUILD.md index 97624c9..b40ff73 100644 --- a/app/BUILD.md +++ b/app/BUILD.md @@ -73,6 +73,20 @@ fvm flutter build apk --release --dart-define-from-file=config/kakao.env `https://<프로젝트 ID>.firebaseapp.com/__/auth/handler` 를 넣는다. 콘솔에서 켜지 않았으면 로그인이 E-AUTH-11 로 끝난다. +## Android Apple 로그인 — 앱에 넣을 값 없음 + +Android 는 Apple SDK 가 없어 Firebase 웹 흐름(`apple.com` 제공자 · `signInWithProvider`)으로 로그인한다. +값은 모두 콘솔에 둔다 — 빌드 옵션은 없다. + +1. Apple 개발자 계정 「Identifiers → Services IDs」에 서비스 ID 를 만들고 「Sign in with Apple」을 켠다. + - Domains: `<프로젝트 ID>.firebaseapp.com` + - Return URLs: `https://<프로젝트 ID>.firebaseapp.com/__/auth/handler` +2. 「Keys」에서 Sign in with Apple 키를 만들고 .p8 를 받는다(키 ID · 팀 ID 기록). 키 파일은 저장소에 넣지 않는다. +3. Firebase 콘솔 Authentication → 로그인 방법 → Apple 에 서비스 ID · 팀 ID · 키 ID · 비공개 키를 넣는다. +4. 확인: Android 첫 화면 Apple → 브라우저 탭에서 Apple 로그인 → 앱 HOME. + +iOS 는 지금처럼 Apple SDK(`AppleSignInProvider`)로 로그인한다. + ## 서명 `android/key.properties` 가 없으면 **릴리스 빌드가 의도적으로 실패**한다 diff --git a/app/README.md b/app/README.md index a06319a..12d980d 100644 --- a/app/README.md +++ b/app/README.md @@ -144,7 +144,7 @@ bool get isMockSessionAvailable => !FirebaseBoot.isLive && !_releaseMode; | 제공자 | 상태 | 구현 | 막고 있는 것 | |---|---|---|---| | Google | 실 코드 경로 | `GoogleSignInProvider` | **Firebase 콘솔에서 Google 제공자 미활성** + Android OAuth 클라이언트(SHA-1) 미등록 | -| Apple | 실 코드 경로 | `AppleSignInProvider` | Apple 개발자 키 + Xcode Capability + Android Service ID/redirect URI | +| Apple | 실 코드 경로 | iOS `AppleSignInProvider`(Apple SDK) · Android `OidcSignInProvider`(Firebase 웹 흐름 `apple.com`) | iOS Xcode Capability · Android 는 Firebase 콘솔 Apple 제공자에 서비스 ID · 키 등록(`BUILD.md` 「Android Apple 로그인」) | | 카카오 | 실 코드 경로 | `KakaoSignInProvider` — 카카오 SDK 로그인 + 서버 `fnAuthKakao` 커스텀 토큰 | 카카오 네이티브 앱 키(`config/kakao.env`) · 서버 `KAKAO_APP_ID` | | LINE | 실 코드 경로 | `OidcSignInProvider` — Firebase OIDC `oidc.line` | Firebase 콘솔 LINE 제공자 등록 | diff --git a/app/lib/features/auth/auth_repository.dart b/app/lib/features/auth/auth_repository.dart index ad09900..a25591f 100644 --- a/app/lib/features/auth/auth_repository.dart +++ b/app/lib/features/auth/auth_repository.dart @@ -50,9 +50,16 @@ class AuthRepository extends ChangeNotifier { /// 돌려준다. static List _defaultProviders() => [ const GoogleSignInProvider(), - AppleSignInProvider( - webAuthenticationOptions: appleWebAuthenticationOptionsFromEnvironment(), - ), + // Android 는 Apple SDK 가 없어 Firebase 웹 흐름(`apple.com` 제공자)으로 간다 — + // 서비스 ID · 키는 Firebase 콘솔 Apple 제공자 설정에 두고 앱에는 값이 없다. + if (!kIsWeb && defaultTargetPlatform == TargetPlatform.android) + const OidcSignInProvider( + AuthProviderKind.apple, + providerId: 'apple.com', + scopes: ['email', 'name'], + ) + else + const AppleSignInProvider(), // 동의 항목은 카카오 콘솔 설정을 따른다(지금은 닉네임). 이메일(account_email)은 비즈 앱 // 전환 후 콘솔에서 켜면 서버가 동의·인증된 값만 받는다. KakaoSignInProvider(), diff --git a/app/lib/features/auth/social_providers.dart b/app/lib/features/auth/social_providers.dart index 7ab2b18..445b647 100644 --- a/app/lib/features/auth/social_providers.dart +++ b/app/lib/features/auth/social_providers.dart @@ -482,25 +482,6 @@ Future untilAbandoned( }); } -/// Apple Service ID와 callback URL은 비밀값이 아니지만 환경별 값이다. -/// 저장소에 임시 상수를 박지 않고 빌드 시 `--dart-define`으로만 받는다. -apple.WebAuthenticationOptions? appleWebAuthenticationOptionsFromEnvironment() { - const clientId = String.fromEnvironment('FANUZU_APPLE_SERVICE_ID'); - const redirect = String.fromEnvironment('FANUZU_APPLE_REDIRECT_URI'); - if (clientId.isEmpty || redirect.isEmpty) return null; - - final redirectUri = Uri.tryParse(redirect); - if (redirectUri == null || - !redirectUri.hasScheme || - !redirectUri.hasAuthority) { - return null; - } - return apple.WebAuthenticationOptions( - clientId: clientId, - redirectUri: redirectUri, - ); -} - AuthAccount _toAccount(fb.User? user, SocialProvider provider) => AuthAccount( uid: user?.uid ?? '', provider: provider, diff --git a/app/test/auth_oidc_test.dart b/app/test/auth_oidc_test.dart index 6c4fc23..4c9117f 100644 --- a/app/test/auth_oidc_test.dart +++ b/app/test/auth_oidc_test.dart @@ -42,6 +42,24 @@ void main() { expect(providers[AuthProviderKind.kakao], isA()); }); + test('Apple: Android 는 Firebase 웹 흐름(apple.com) · iOS 는 Apple SDK', () { + final android = AuthRepository().providers.firstWhere( + (p) => p.provider == AuthProviderKind.apple, + ); + expect(android, isA()); + expect( + (android as OidcSignInProvider).authProvider.providerId, + 'apple.com', + ); + expect(android.missingConfig, isEmpty); + debugDefaultTargetPlatformOverride = TargetPlatform.iOS; + addTearDown(() => debugDefaultTargetPlatformOverride = null); + final ios = AuthRepository().providers.firstWhere( + (p) => p.provider == AuthProviderKind.apple, + ); + expect(ios, isA()); + }); + test('Firebase 설정이 없으면 SDK 를 부르지 않고 미설정으로 닫는다', () async { FirebaseBoot.debugSetMode(FirebaseMode.mock, reason: '설정 없음'); final outcome = await line(_ThrowingAuth('should-not-call')).signIn();