From 6136ee2a3cf4ecdf9b6162849c4a111a62a39d2a Mon Sep 17 00:00:00 2001 From: eld_master Date: Fri, 7 Feb 2025 18:03:40 +0900 Subject: [PATCH] =?UTF-8?q?=EC=95=A0=ED=94=8C=EB=A1=9C=EA=B7=B8=EC=9D=B8?= =?UTF-8?q?=20=EA=B5=AC=ED=98=84=201=EC=B0=A8=20-=20=ED=9A=8C=EC=9B=90?= =?UTF-8?q?=EA=B0=80=EC=9E=85=EB=A7=8C=20=EC=9A=B0=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- android/app/build.gradle | 9 +- android/app/google-services.json | 12 +- android/app/src/main/AndroidManifest.xml | 16 +- android/app/src/main/res/values/strings.xml | 4 + ios/Runner/Info.plist | 22 +- lib/dialogs/signup_dialog.dart | 398 ++++++++++++++++++ lib/views/login/login_page.dart | 144 ++++--- macos/Flutter/GeneratedPluginRegistrant.swift | 2 + pubspec.lock | 32 ++ pubspec.yaml | 1 + 10 files changed, 570 insertions(+), 70 deletions(-) create mode 100644 android/app/src/main/res/values/strings.xml create mode 100644 lib/dialogs/signup_dialog.dart diff --git a/android/app/build.gradle b/android/app/build.gradle index 82dd9c9..dd342b7 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -63,9 +63,16 @@ flutter { } dependencies { - // 기존 의존성 ... + // 기존 의존성 유지 implementation 'com.google.android.gms:play-services-auth:20.6.0' implementation 'com.google.android.gms:play-services-ads:23.6.0' + + // Firebase BOM + implementation platform('com.google.firebase:firebase-bom:32.7.1') + + // Firebase 제품들은 버전을 지정하지 않아도 됩니다 + implementation 'com.google.firebase:firebase-auth' + implementation 'com.google.firebase:firebase-analytics' } // (Firebase Auth, Crashlytics 등을 사용한다면, 아래 구문이 필요할 수 있습니다.) diff --git a/android/app/google-services.json b/android/app/google-services.json index ea4aa2c..f223e69 100644 --- a/android/app/google-services.json +++ b/android/app/google-services.json @@ -14,6 +14,14 @@ } }, "oauth_client": [ + { + "client_id": "452355332155-jcnodseb4t2bgq2mo1a6h3bn4ncp5o8c.apps.googleusercontent.com", + "client_type": 1, + "android_info": { + "package_name": "com.allscore_app", + "certificate_hash": "0f5c83605937a4aa55d6097253473b285bb18418" + } + }, { "client_id": "452355332155-lqtr6l2qg0pn62vi5nccggldmcm21qdl.apps.googleusercontent.com", "client_type": 1, @@ -48,10 +56,10 @@ "client_type": 3 }, { - "client_id": "452355332155-fo49j1u3qfup1sa3gj33bko6q269pqo4.apps.googleusercontent.com", + "client_id": "452355332155-26g42j6p8kfdeknncqfmt7sitvvj611l.apps.googleusercontent.com", "client_type": 2, "ios_info": { - "bundle_id": "com.example.allscoreApp" + "bundle_id": "com.allscore" } } ] diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index f236ffd..d39165f 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -9,7 +9,8 @@ + android:icon="@mipmap/ic_launcher" + android:usesCleartextTraffic="true"> + + + + + + + + + + + + + 1:452355332155:web:5407f79d500818e713e41e + \ No newline at end of file diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index af11be4..a10d8e9 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -26,12 +26,18 @@ ???? CFBundleURLTypes - - CFBundleURLSchemes - - com.googleusercontent.apps.452355332155-26g42j6p8kfdeknncqfmt7sitvvj611l - - + + CFBundleURLSchemes + + com.googleusercontent.apps.452355332155-26g42j6p8kfdeknncqfmt7sitvvj611l + + + + CFBundleURLSchemes + + com.allscore + + CFBundleVersion $(FLUTTER_BUILD_NUMBER) @@ -79,5 +85,9 @@ UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight + com.apple.developer.applesignin + + Default + diff --git a/lib/dialogs/signup_dialog.dart b/lib/dialogs/signup_dialog.dart new file mode 100644 index 0000000..fe92d02 --- /dev/null +++ b/lib/dialogs/signup_dialog.dart @@ -0,0 +1,398 @@ +import 'package:flutter/material.dart'; +import '../views/login/signup_page.dart'; + +/* 구글 로그인 */ +import 'package:google_sign_in/google_sign_in.dart'; +import 'package:firebase_auth/firebase_auth.dart'; + +/* 애플 로그인 */ +import 'package:sign_in_with_apple/sign_in_with_apple.dart'; +import 'dart:io' show Platform; +import 'dart:math'; +import 'dart:convert'; +import 'package:crypto/crypto.dart'; + +/* 안내 모달창 */ +import 'response_dialog.dart'; + +/* 우리의 Api 모듈 */ +import '../plugins/api.dart'; + +/* 설정 */ +import '../config/config.dart'; + +// 회원가입 방법 선택 모달 위젯 +class SignUpDialog extends StatefulWidget { + const SignUpDialog({Key? key}) : super(key: key); + + @override + State createState() => _SignUpDialogState(); +} + +class _SignUpDialogState extends State { + // 구글 로그인 객체 + final GoogleSignIn _googleSignIn = GoogleSignIn(scopes: ['email']); + + // 로딩 상태 관리 + bool _isLoading = false; + + @override + Widget build(BuildContext context) { + return Stack( + children: [ + Dialog( + backgroundColor: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16), + ), + child: Container( + padding: const EdgeInsets.all(20), + width: 300, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + // 제목 + const Text( + 'Sign Up Method', + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + color: Colors.black, + ), + ), + const SizedBox(height: 24), + + // 이메일 회원가입 버튼 + SizedBox( + width: double.infinity, + child: ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: Colors.white, + foregroundColor: Colors.black, + side: const BorderSide(color: Colors.black), + padding: const EdgeInsets.symmetric(vertical: 12), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), + ), + onPressed: () { + Navigator.pop(context); + Navigator.pushAndRemoveUntil( + context, + MaterialPageRoute(builder: (_) => const SignUpPage()), + (route) => false, + ); + }, + child: const Text( + 'Sign up with Email', + style: TextStyle(fontSize: 16), + ), + ), + ), + const SizedBox(height: 12), + + // 구글 회원가입 버튼 + SizedBox( + width: double.infinity, + child: ElevatedButton.icon( + icon: Container( + width: 24, + height: 24, + decoration: const BoxDecoration( + image: DecorationImage( + image: AssetImage('assets/images/icons8-google-logo-48.png'), + fit: BoxFit.contain, + ), + ), + ), + label: const Text( + 'Sign up with Google', + style: TextStyle(fontSize: 16), + ), + style: ElevatedButton.styleFrom( + backgroundColor: Colors.white, + foregroundColor: Colors.black, + side: const BorderSide(color: Colors.black), + padding: const EdgeInsets.symmetric(vertical: 12), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), + ), + onPressed: _googleSignUp, + ), + ), + const SizedBox(height: 12), + + // 애플 회원가입 버튼 - iOS에서만 표시 + if (!Platform.isAndroid) + SizedBox( + width: double.infinity, + child: ElevatedButton.icon( + icon: const Icon( + Icons.apple, + size: 24, + color: Colors.black, + ), + label: const Text( + 'Sign up with Apple', + style: TextStyle(fontSize: 16), + ), + style: ElevatedButton.styleFrom( + backgroundColor: Colors.white, + foregroundColor: Colors.black, + side: const BorderSide(color: Colors.black), + padding: const EdgeInsets.symmetric(vertical: 12), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), + ), + onPressed: () { + _appleSignUp(); + }, + ), + ), + ], + ), + ), + ), + // 로딩 인디케이터 + if (_isLoading) + Container( + color: Colors.black54, + alignment: Alignment.center, + child: const CircularProgressIndicator(color: Colors.white), + ), + ], + ); + } + + + // ───────────────────────────────────────── + // (D3) 구글 회원가입 + // ───────────────────────────────────────── + Future _googleSignUp() async { + setState(() => _isLoading = true); + + final agreed = await _showTermsModal(); + if (agreed != true) { + setState(() => _isLoading = false); + return; + } + + try { + // (2) 구글 계정 선택 + final GoogleSignInAccount? googleUser = await _googleSignIn.signIn(); + if (googleUser == null) { + // 사용자가 회원가입 창에서 취소 + return; + } + + // (3) 구글 인증 정보 + final GoogleSignInAuthentication googleAuth = await googleUser.authentication; + + // (4) FirebaseAuth Credential + final AuthCredential credential = GoogleAuthProvider.credential( + accessToken: googleAuth.accessToken, + idToken: googleAuth.idToken, + ); + + // (5) FirebaseAuth로 "회원가입" 시도 + final UserCredential userCredential = await FirebaseAuth.instance.signInWithCredential(credential); + final User? user = userCredential.user; + if (user == null) { + showResponseDialog(context, 'Error' /* 오류 */, 'Google account authentication failed.' + /* 구글계정 인증에 실패했습니다. */); + return; + } + + // (6) idToken 추출 후, 서버에 회원가입 요청 + final idToken = await user.getIdToken(); + final requestBody = { + 'id_token': idToken, + }; + + final response = await Api.serverRequest(uri: '/user/google/signup', body: requestBody); + if (response['result'] == 'OK') { + final resp = response['response'] ?? {}; + if (resp['result'] == 'OK') { + // 회원가입 성공 안내 + showResponseDialog(context, 'Sign-up Complete' /* 회원가입 완료 */, 'Google sign-up has been completed.' + /* 구글 회원가입이 완료되었습니다. */); + } else { + // 실패 시 + final msgTitle = resp['response_info']?['msg_title'] ?? 'Error' /* 오류 */; + final msgContent = resp['response_info']?['msg_content'] ?? 'Failed to sign up.' + /* 회원가입에 실패했습니다. */; + showResponseDialog(context, msgTitle, msgContent); + } + } else { + showResponseDialog(context, 'Error' /* 오류 */, 'Google sign-up request failed.' + /* 구글 회원가입 요청 실패 */); + } + } catch (e) { + showResponseDialog(context, 'Error' /* 오류 */, 'An error occurred during Google sign-up.\n$e' + /* 구글 회원가입 중 오류가 발생했습니다.\n$e */); + } finally { + setState(() => _isLoading = false); + } + } + + + // ───────────────────────────────────────── + // (D4) 애플 회원가입 + // ───────────────────────────────────────── + Future _appleSignUp() async { + // 안드로이드 기기 체크 + if (Platform.isAndroid) { + showResponseDialog( + context, + '사용 불가', // 제목 + '애플 회원가입은 안드로이드 기기에서 제공되지 않습니다.', // 내용 + ); + return; + } + + setState(() => _isLoading = true); + + final agreed = await _showTermsModal(); + if (agreed != true) { + setState(() => _isLoading = false); + return; + } + + try { + // 1. 애플 로그인 credential 획득 + final rawNonce = generateNonce(); + final nonce = sha256ofString(rawNonce); + + final appleCredential = await SignInWithApple.getAppleIDCredential( + scopes: [ + AppleIDAuthorizationScopes.email, + AppleIDAuthorizationScopes.fullName, + ], + ); + print('appleCredential: $appleCredential'); + + // 2. Firebase credential 생성 + final oauthProvider = OAuthProvider('apple.com'); + print('oauthProvider: $oauthProvider'); + final credential = oauthProvider.credential( + idToken: appleCredential.identityToken, + accessToken: appleCredential.authorizationCode, + ); + print('credential: $credential'); + + // 3. Firebase 인증 + final userCredential = await FirebaseAuth.instance.signInWithCredential(credential); + print('userCredential: $userCredential'); + final user = userCredential.user; + print('user: $user'); + + if (user == null) { + showResponseDialog(context, 'Error', 'Apple account authentication failed.'); + return; + } + + // 4. 서버에 회원가입 요청 + final idToken = await user.getIdToken(); + final requestBody = { + 'id_token': idToken, + }; + + final response = await Api.serverRequest(uri: '/user/apple/signup', body: requestBody); + if (response['result'] == 'OK') { + final resp = response['response'] ?? {}; + if (resp['result'] == 'OK') { + showResponseDialog( + context, + 'Sign-up Complete', + 'Apple sign-up has been completed.' + ); + } else { + final msgTitle = resp['response_info']?['msg_title'] ?? 'Error'; + final msgContent = resp['response_info']?['msg_content'] ?? 'Failed to sign up.'; + showResponseDialog(context, msgTitle, msgContent); + } + } else { + showResponseDialog( + context, + 'Error', + 'Apple sign-up request failed.' + ); + } + } catch (e) { + showResponseDialog( + context, + 'Error', + 'An error occurred during Apple sign-up.\n$e' + ); + } finally { + setState(() => _isLoading = false); + } + } + + // nonce 생성 유틸리티 함수들 추가 + String generateNonce([int length = 32]) { + const charset = '0123456789ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvwxyz-._'; + final random = Random.secure(); + return List.generate(length, (_) => charset[random.nextInt(charset.length)]).join(); + } + + String sha256ofString(String input) { + final bytes = utf8.encode(input); + final digest = sha256.convert(bytes); + return digest.toString(); + } + + + // ───────────────────────────────────────── + // (E) 약관 모달 (개인정보 수집 동의) + // ───────────────────────────────────────── + Future _showTermsModal() async { + return showDialog( + context: context, + barrierDismissible: false, + builder: (ctx) { + return AlertDialog( + backgroundColor: Colors.white, + title: const Text( + 'Privacy Collection and Usage Agreement' + /* 개인정보 수집 및 이용 동의서 */, + style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), + ), + content: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: const [ + Text( + Config.termsOfService, + style: const TextStyle(fontSize: 14), + ), + ], + ), + ), + actions: [ + TextButton( + style: TextButton.styleFrom( + backgroundColor: Colors.black, + foregroundColor: Colors.white, + ), + onPressed: () => Navigator.pop(ctx, false), + child: Text('Disagree' + /* 거부 */), + ), + TextButton( + style: TextButton.styleFrom( + backgroundColor: Colors.black, + foregroundColor: Colors.white, + ), + onPressed: () => Navigator.pop(ctx, true), + child: Text('Agree' + /* 동의 */), + ), + ], + ); + }, + ); + } +} \ No newline at end of file diff --git a/lib/views/login/login_page.dart b/lib/views/login/login_page.dart index c5bfeb6..0f94cfd 100644 --- a/lib/views/login/login_page.dart +++ b/lib/views/login/login_page.dart @@ -4,6 +4,9 @@ import 'dart:convert' show utf8, jsonEncode; import 'package:crypto/crypto.dart'; import 'package:shared_preferences/shared_preferences.dart'; +// 회원가입 모달창 +import '../../dialogs/signup_dialog.dart'; + /* 우리의 Api 모듈 */ import '../../plugins/api.dart'; @@ -18,6 +21,7 @@ import 'signup_page.dart'; /* 회원가입 페이지 임포트 */ /* 구글 로그인 */ import 'package:google_sign_in/google_sign_in.dart'; import 'package:firebase_auth/firebase_auth.dart'; +import 'dart:io' show Platform; /* 광고 */ import 'package:google_mobile_ads/google_mobile_ads.dart'; @@ -140,7 +144,7 @@ class _LoginPageState extends State { if (resp['result'] == 'OK') { /* 로그인 성공 */ final prefs = await SharedPreferences.getInstance(); - await prefs.setString('oauth_type', 'idpw'); // /* google_user_yn = N 대신 */ + await prefs.setString('oauth_type', 'idpw'); await prefs.setBool('auto_login', true); await prefs.setString('jwt_token', resp['auth']['token'].toString()); await prefs.setInt('my_user_seq', resp['auth']['user_seq']); @@ -208,7 +212,7 @@ class _LoginPageState extends State { final resp = response['response'] ?? {}; if (resp['result'] == 'OK') { final prefs = await SharedPreferences.getInstance(); - await prefs.setString('oauth_type', 'google'); // /* google_user_yn = Y 대체 */ + await prefs.setString('oauth_type', 'google'); await prefs.setBool('auto_login', true); await prefs.setString('jwt_token', resp['auth']['token'].toString()); await prefs.setInt('my_user_seq', resp['auth']['user_seq']); @@ -221,10 +225,6 @@ class _LoginPageState extends State { showResponseDialog(context, 'Error' /* 오류 */, 'Google login request failed.' /* 구글 로그인 요청 실패 */); } - - // (optional) SharedPreferences에 google_user_yn = 'Y' 저장 등 - final prefs = await SharedPreferences.getInstance(); - await prefs.setString('google_user_yn', 'Y'); } catch (e) { _showAlert('Error' /* 오류 */, 'An error occurred during Google login.\n$e' /* 구글 로그인 중 오류가 발생했습니다.\n$e */); @@ -233,6 +233,22 @@ class _LoginPageState extends State { } } + + // ───────────────────────────────────────── + // (D4) 애플 로그인 (임시) + // ───────────────────────────────────────── + Future _appleLogin() async { + setState(() => _isLoading = true); + try { + // TODO: 애플 로그인 구현 + showResponseDialog(context, 'Notice', 'Apple login will be implemented soon.'); + } catch (e) { + showResponseDialog(context, 'Error', 'An error occurred during Apple login.\n$e'); + } finally { + setState(() => _isLoading = false); + } + } + // ───────────────────────────────────────── // (D3) 구글 회원가입 // ───────────────────────────────────────── @@ -529,13 +545,18 @@ class _LoginPageState extends State { ), TextButton( onPressed: () { - Navigator.push(context, MaterialPageRoute(builder: (_) => const SignUpPage())); + // Navigator.push(context, MaterialPageRoute(builder: (_) => const SignUpPage())); + showDialog( + context: context, + builder: (_) => const SignUpDialog(), + ); }, child: const Text( 'Sign Up' /* 회원가입 */, style: TextStyle(color: Colors.black), ), + ), const SizedBox(height: 24), @@ -546,71 +567,74 @@ class _LoginPageState extends State { // 2. 구글 로그인 / 회원가입 // ───────────────────────────────────────── const Text( - 'Google Account' + 'Social Login' /* 구글 계정 */, style: TextStyle(fontSize: 20, color: Colors.black, fontWeight: FontWeight.bold), ), const SizedBox(height: 16), // (a) 구글 로그인 - SizedBox( - width: 300, - child: ElevatedButton.icon( - icon: Container( - width: 24, - height: 24, - decoration: const BoxDecoration( - image: DecorationImage( - image: AssetImage('assets/images/icons8-google-logo-48.png'), - fit: BoxFit.contain, + // 소셜 로그인 버튼들을 Row로 배치 + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + // 구글 로그인 버튼 + Container( + width: 140, + margin: const EdgeInsets.symmetric(horizontal: 5), + child: ElevatedButton.icon( + icon: Container( + width: 24, + height: 24, + decoration: const BoxDecoration( + image: DecorationImage( + image: AssetImage('assets/images/icons8-google-logo-48.png'), + fit: BoxFit.contain, + ), + ), ), + label: const Text( + 'Google', + style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), + ), + style: ElevatedButton.styleFrom( + backgroundColor: Colors.white, + foregroundColor: Colors.black, + side: const BorderSide(color: Colors.black), + padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16), + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)), + ), + onPressed: _googleLogin, ), ), - label: const Text( - 'Google Login' - /* Google 로그인 */, - style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), - ), - style: ElevatedButton.styleFrom( - backgroundColor: Colors.white, - foregroundColor: Colors.black, - side: const BorderSide(color: Colors.black), - padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 24), - shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)), - ), - onPressed: _googleLogin, - ), - ), - const SizedBox(height: 12), - // (b) 구글 회원가입 - SizedBox( - width: 300, - child: ElevatedButton.icon( - icon: Container( - width: 24, - height: 24, - decoration: const BoxDecoration( - image: DecorationImage( - image: AssetImage('assets/images/icons8-google-logo-48.png'), - fit: BoxFit.contain, + // 애플 로그인 버튼 - 아이폰에서만 활성화 + if (Platform.isIOS) + Container( + width: 140, + margin: const EdgeInsets.symmetric(horizontal: 5), + child: ElevatedButton.icon( + + icon: const Icon( + Icons.apple, + size: 24, + color: Colors.black, + ), + label: const Text( + 'Apple', + style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), + ), + style: ElevatedButton.styleFrom( + backgroundColor: Colors.white, + foregroundColor: Colors.black, + side: const BorderSide(color: Colors.black), + padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16), + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)), + ), + onPressed: _appleLogin, ), - ), ), - label: const Text( - 'Google Sign Up' - /* Google 회원가입 */, - style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), - ), - style: ElevatedButton.styleFrom( - backgroundColor: Colors.white, - foregroundColor: Colors.black, - side: const BorderSide(color: Colors.black), - padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 24), - shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)), - ), - onPressed: _googleSignUp, - ), + ], ), ], ), diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 3c6371d..da96522 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -11,6 +11,7 @@ import firebase_core import firebase_database import google_sign_in_ios import shared_preferences_foundation +import sign_in_with_apple import webview_flutter_wkwebview func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { @@ -20,5 +21,6 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { FLTFirebaseDatabasePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseDatabasePlugin")) FLTGoogleSignInPlugin.register(with: registry.registrar(forPlugin: "FLTGoogleSignInPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) + SignInWithApplePlugin.register(with: registry.registrar(forPlugin: "SignInWithApplePlugin")) FLTWebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "FLTWebViewFlutterPlugin")) } diff --git a/pubspec.lock b/pubspec.lock index 2137351..897faea 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -464,6 +464,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.2.1+1" + js: + dependency: transitive + description: + name: js + sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 + url: "https://pub.dev" + source: hosted + version: "0.6.7" json_annotation: dependency: transitive description: @@ -656,6 +664,30 @@ packages: url: "https://pub.dev" source: hosted version: "2.4.1" + sign_in_with_apple: + dependency: "direct main" + description: + name: sign_in_with_apple + sha256: "0975c23b9f8b30a80e27d5659a75993a093d4cb5f4eb7d23a9ccc586fea634e0" + url: "https://pub.dev" + source: hosted + version: "5.0.0" + sign_in_with_apple_platform_interface: + dependency: transitive + description: + name: sign_in_with_apple_platform_interface + sha256: c2ef2ce6273fce0c61acd7e9ff5be7181e33d7aa2b66508b39418b786cca2119 + url: "https://pub.dev" + source: hosted + version: "1.1.0" + sign_in_with_apple_web: + dependency: transitive + description: + name: sign_in_with_apple_web + sha256: "44b66528f576e77847c14999d5e881e17e7223b7b0625a185417829e5306f47a" + url: "https://pub.dev" + source: hosted + version: "1.0.1" sky_engine: dependency: transitive description: flutter diff --git a/pubspec.yaml b/pubspec.yaml index 2450dba..29df35d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -23,6 +23,7 @@ dependencies: firebase_auth: ^4.15.3 firebase_database: ^10.2.3 google_sign_in: ^6.1.6 + sign_in_with_apple: ^5.0.0 cupertino_icons: ^1.0.8 fluttertoast: ^8.0.9 flutter_launcher_icons: ^0.12.0