diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 6f6b4774..8d3cbd8d 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,8 +1,12 @@ + + 2.4) - audio_session (0.0.1): - Flutter - - Firebase/Analytics (11.15.0): - - Firebase/Core - - Firebase/Auth (11.15.0): + - Firebase/Auth (12.4.0): - Firebase/CoreOnly - - FirebaseAuth (~> 11.15.0) - - Firebase/Core (11.15.0): + - FirebaseAuth (~> 12.4.0) + - Firebase/CoreOnly (12.4.0): + - FirebaseCore (~> 12.4.0) + - Firebase/Messaging (12.4.0): - Firebase/CoreOnly - - FirebaseAnalytics (~> 11.15.0) - - Firebase/CoreOnly (11.15.0): - - FirebaseCore (~> 11.15.0) - - firebase_analytics (11.5.2): - - Firebase/Analytics (= 11.15.0) + - FirebaseMessaging (~> 12.4.0) + - firebase_analytics (12.0.3): - firebase_core + - FirebaseAnalytics (= 12.4.0) - Flutter - - firebase_auth (5.6.2): - - Firebase/Auth (= 11.15.0) + - firebase_auth (6.1.1): + - Firebase/Auth (= 12.4.0) - firebase_core - Flutter - - firebase_core (3.15.1): - - Firebase/CoreOnly (= 11.15.0) + - firebase_core (4.2.0): + - Firebase/CoreOnly (= 12.4.0) - Flutter - - FirebaseAnalytics (11.15.0): - - FirebaseAnalytics/Default (= 11.15.0) - - FirebaseCore (~> 11.15.0) - - FirebaseInstallations (~> 11.0) + - firebase_messaging (16.0.3): + - Firebase/Messaging (= 12.4.0) + - firebase_core + - Flutter + - FirebaseAnalytics (12.4.0): + - FirebaseAnalytics/Default (= 12.4.0) + - FirebaseCore (~> 12.4.0) + - FirebaseInstallations (~> 12.4.0) - GoogleUtilities/AppDelegateSwizzler (~> 8.1) - GoogleUtilities/MethodSwizzler (~> 8.1) - GoogleUtilities/Network (~> 8.1) - "GoogleUtilities/NSData+zlib (~> 8.1)" - nanopb (~> 3.30910.0) - - FirebaseAnalytics/Default (11.15.0): - - FirebaseCore (~> 11.15.0) - - FirebaseInstallations (~> 11.0) - - GoogleAppMeasurement/Default (= 11.15.0) + - FirebaseAnalytics/Default (12.4.0): + - FirebaseCore (~> 12.4.0) + - FirebaseInstallations (~> 12.4.0) + - GoogleAppMeasurement/Default (= 12.4.0) - GoogleUtilities/AppDelegateSwizzler (~> 8.1) - GoogleUtilities/MethodSwizzler (~> 8.1) - GoogleUtilities/Network (~> 8.1) - "GoogleUtilities/NSData+zlib (~> 8.1)" - nanopb (~> 3.30910.0) - - FirebaseAppCheckInterop (11.15.0) - - FirebaseAuth (11.15.0): - - FirebaseAppCheckInterop (~> 11.0) - - FirebaseAuthInterop (~> 11.0) - - FirebaseCore (~> 11.15.0) - - FirebaseCoreExtension (~> 11.15.0) + - FirebaseAppCheckInterop (12.4.0) + - FirebaseAuth (12.4.0): + - FirebaseAppCheckInterop (~> 12.4.0) + - FirebaseAuthInterop (~> 12.4.0) + - FirebaseCore (~> 12.4.0) + - FirebaseCoreExtension (~> 12.4.0) - GoogleUtilities/AppDelegateSwizzler (~> 8.1) - GoogleUtilities/Environment (~> 8.1) - - GTMSessionFetcher/Core (< 5.0, >= 3.4) + - GTMSessionFetcher/Core (< 6.0, >= 3.4) - RecaptchaInterop (~> 101.0) - - FirebaseAuthInterop (11.15.0) - - FirebaseCore (11.15.0): - - FirebaseCoreInternal (~> 11.15.0) + - FirebaseAuthInterop (12.4.0) + - FirebaseCore (12.4.0): + - FirebaseCoreInternal (~> 12.4.0) - GoogleUtilities/Environment (~> 8.1) - GoogleUtilities/Logger (~> 8.1) - - FirebaseCoreExtension (11.15.0): - - FirebaseCore (~> 11.15.0) - - FirebaseCoreInternal (11.15.0): + - FirebaseCoreExtension (12.4.0): + - FirebaseCore (~> 12.4.0) + - FirebaseCoreInternal (12.4.0): - "GoogleUtilities/NSData+zlib (~> 8.1)" - - FirebaseInstallations (11.15.0): - - FirebaseCore (~> 11.15.0) + - FirebaseInstallations (12.4.0): + - FirebaseCore (~> 12.4.0) - GoogleUtilities/Environment (~> 8.1) - GoogleUtilities/UserDefaults (~> 8.1) - PromisesObjC (~> 2.4) + - FirebaseMessaging (12.4.0): + - FirebaseCore (~> 12.4.0) + - FirebaseInstallations (~> 12.4.0) + - GoogleDataTransport (~> 10.1) + - GoogleUtilities/AppDelegateSwizzler (~> 8.1) + - GoogleUtilities/Environment (~> 8.1) + - GoogleUtilities/Reachability (~> 8.1) + - GoogleUtilities/UserDefaults (~> 8.1) + - nanopb (~> 3.30910.0) - Flutter (1.0.0) + - flutter_local_notifications (0.0.1): + - Flutter - flutter_secure_storage (6.0.0): - Flutter - gal (1.0.0): @@ -94,32 +107,36 @@ PODS: - FlutterMacOS - GoogleSignIn (~> 8.0) - GTMSessionFetcher (>= 3.4.0) - - GoogleAdsOnDeviceConversion (2.1.0): + - GoogleAdsOnDeviceConversion (3.1.0): + - GoogleUtilities/Environment (~> 8.1) - GoogleUtilities/Logger (~> 8.1) - GoogleUtilities/Network (~> 8.1) - nanopb (~> 3.30910.0) - - GoogleAppMeasurement/Core (11.15.0): + - GoogleAppMeasurement/Core (12.4.0): - GoogleUtilities/AppDelegateSwizzler (~> 8.1) - GoogleUtilities/MethodSwizzler (~> 8.1) - GoogleUtilities/Network (~> 8.1) - "GoogleUtilities/NSData+zlib (~> 8.1)" - nanopb (~> 3.30910.0) - - GoogleAppMeasurement/Default (11.15.0): - - GoogleAdsOnDeviceConversion (= 2.1.0) - - GoogleAppMeasurement/Core (= 11.15.0) - - GoogleAppMeasurement/IdentitySupport (= 11.15.0) + - GoogleAppMeasurement/Default (12.4.0): + - GoogleAdsOnDeviceConversion (~> 3.1.0) + - GoogleAppMeasurement/Core (= 12.4.0) + - GoogleAppMeasurement/IdentitySupport (= 12.4.0) - GoogleUtilities/AppDelegateSwizzler (~> 8.1) - GoogleUtilities/MethodSwizzler (~> 8.1) - GoogleUtilities/Network (~> 8.1) - "GoogleUtilities/NSData+zlib (~> 8.1)" - nanopb (~> 3.30910.0) - - GoogleAppMeasurement/IdentitySupport (11.15.0): - - GoogleAppMeasurement/Core (= 11.15.0) + - GoogleAppMeasurement/IdentitySupport (12.4.0): + - GoogleAppMeasurement/Core (= 12.4.0) - GoogleUtilities/AppDelegateSwizzler (~> 8.1) - GoogleUtilities/MethodSwizzler (~> 8.1) - GoogleUtilities/Network (~> 8.1) - "GoogleUtilities/NSData+zlib (~> 8.1)" - nanopb (~> 3.30910.0) + - GoogleDataTransport (10.1.0): + - nanopb (~> 3.30910.0) + - PromisesObjC (~> 2.4) - GoogleSignIn (8.0.0): - AppAuth (< 2.0, >= 1.7.3) - AppCheckCore (~> 11.0) @@ -207,7 +224,9 @@ DEPENDENCIES: - firebase_analytics (from `.symlinks/plugins/firebase_analytics/ios`) - firebase_auth (from `.symlinks/plugins/firebase_auth/ios`) - firebase_core (from `.symlinks/plugins/firebase_core/ios`) + - firebase_messaging (from `.symlinks/plugins/firebase_messaging/ios`) - Flutter (from `Flutter`) + - flutter_local_notifications (from `.symlinks/plugins/flutter_local_notifications/ios`) - flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`) - gal (from `.symlinks/plugins/gal/darwin`) - google_sign_in_ios (from `.symlinks/plugins/google_sign_in_ios/darwin`) @@ -239,8 +258,10 @@ SPEC REPOS: - FirebaseCoreExtension - FirebaseCoreInternal - FirebaseInstallations + - FirebaseMessaging - GoogleAdsOnDeviceConversion - GoogleAppMeasurement + - GoogleDataTransport - GoogleSignIn - GoogleUtilities - GTMAppAuth @@ -263,8 +284,12 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/firebase_auth/ios" firebase_core: :path: ".symlinks/plugins/firebase_core/ios" + firebase_messaging: + :path: ".symlinks/plugins/firebase_messaging/ios" Flutter: :path: Flutter + flutter_local_notifications: + :path: ".symlinks/plugins/flutter_local_notifications/ios" flutter_secure_storage: :path: ".symlinks/plugins/flutter_secure_storage/ios" gal: @@ -298,24 +323,28 @@ SPEC CHECKSUMS: AppAuth: d4f13a8fe0baf391b2108511793e4b479691fb73 AppCheckCore: cc8fd0a3a230ddd401f326489c99990b013f0c4f audio_session: 19e9480dbdd4e5f6c4543826b2e8b0e4ab6145fe - Firebase: d99ac19b909cd2c548339c2241ecd0d1599ab02e - firebase_analytics: bceda3c1d0f70368de04b2dfdde58e00e37ad4e4 - firebase_auth: b8ed959bf77eca5cf0312b5e29708fe8311a0ddf - firebase_core: cf4d42a8ac915e51c0c2dc103442f3036d941a2d - FirebaseAnalytics: 6433dfd311ba78084fc93bdfc145e8cb75740eae - FirebaseAppCheckInterop: 06fe5a3799278ae4667e6c432edd86b1030fa3df - FirebaseAuth: a6575e5fbf46b046c58dc211a28a5fbdd8d4c83b - FirebaseAuthInterop: 7087d7a4ee4bc4de019b2d0c240974ed5d89e2fd - FirebaseCore: efb3893e5b94f32b86e331e3bd6dadf18b66568e - FirebaseCoreExtension: edbd30474b5ccf04e5f001470bdf6ea616af2435 - FirebaseCoreInternal: 9afa45b1159304c963da48addb78275ef701c6b4 - FirebaseInstallations: 317270fec08a5d418fdbc8429282238cab3ac843 + Firebase: f07b15ae5a6ec0f93713e30b923d9970d144af3e + firebase_analytics: 9499a36a28423125016f8383ee785143ea9e61e4 + firebase_auth: c338c3a796a1fe8a161cb6f522b06461c5992c5c + firebase_core: 49ffe9d2c7a2659f6e9e8d4a406e966bc084268e + firebase_messaging: 42938d0635a4ec080de4cca24216d8a428ab0398 + FirebaseAnalytics: 0fc2b20091f0ddd21bf73397cf8f0eb5346dc24f + FirebaseAppCheckInterop: f734c802f21fe1da0837708f0f9a27218c8a4ed0 + FirebaseAuth: 4a2aed737c84114a9d9b33d11ae1b147d6b94889 + FirebaseAuthInterop: 858e6b754966e70740a4370dd1503dfffe6dbb49 + FirebaseCore: bb595f3114953664e3c1dc032f008a244147cfd3 + FirebaseCoreExtension: 7e1f7118ee970e001a8013719fb90950ee5e0018 + FirebaseCoreInternal: d7f5a043c2cd01a08103ab586587c1468047bca6 + FirebaseInstallations: ae9f4902cb5bf1d0c5eaa31ec1f4e5495a0714e2 + FirebaseMessaging: d33971b7bb252745ea6cd31ab190d1a1df4b8ed5 Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 + flutter_local_notifications: ff50f8405aaa0ccdc7dcfb9022ca192e8ad9688f flutter_secure_storage: d33dac7ae2ea08509be337e775f6b59f1ff45f12 gal: 6a522c75909f1244732d4596d11d6a2f86ff37a5 google_sign_in_ios: 7411fab6948df90490dc4620ecbcabdc3ca04017 - GoogleAdsOnDeviceConversion: 2be6297a4f048459e0ae17fad9bfd2844e10cf64 - GoogleAppMeasurement: 700dce7541804bec33db590a5c496b663fbe2539 + GoogleAdsOnDeviceConversion: e03a386840803ea7eef3fd22a061930142c039c1 + GoogleAppMeasurement: 1e718274b7e015cefd846ac1fcf7820c70dc017d + GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7 GoogleSignIn: ce8c89bb9b37fb624b92e7514cc67335d1e277e4 GoogleUtilities: 00c88b9a86066ef77f0da2fab05f65d7768ed8e1 GTMAppAuth: f69bd07d68cd3b766125f7e072c45d7340dea0de diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index e4fb3066..aca86c21 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -515,7 +515,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = 2Q52PTW5ZT; + DEVELOPMENT_TEAM = 8Z2GR346YM; ENABLE_BITCODE = NO; FLUTTER_BUILD_NAME = 1.0.6; FLUTTER_BUILD_NUMBER = 100; diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index cb4fece7..3a0bfe57 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -47,8 +47,22 @@ LSRequiresIPhoneOS + NSCameraUsageDescription + 프로필 및 다이어리 사진 등록을 위해 카메라에 접근합니다. + NSMicrophoneUsageDescription + 동영상 촬영을 위해 마이크에 접근합니다. + NSPhotoLibraryAddUsageDescription + 스크린샷을 저장하기 위해 앨범에 접근합니다. + NSPhotoLibraryUsageDescription + 프로필 및 다이어리 사진 등록을 위해 앨범에 접근합니다. UIApplicationSupportsIndirectInputEvents + UIBackgroundModes + + fetch + processing + remote-notification + UILaunchStoryboardName LaunchScreen UIMainStoryboardFile @@ -66,13 +80,5 @@ UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight - NSCameraUsageDescription - 프로필 및 다이어리 사진 등록을 위해 카메라에 접근합니다. - NSPhotoLibraryUsageDescription - 프로필 및 다이어리 사진 등록을 위해 앨범에 접근합니다. - NSMicrophoneUsageDescription - 동영상 촬영을 위해 마이크에 접근합니다. - NSPhotoLibraryAddUsageDescription - 스크린샷을 저장하기 위해 앨범에 접근합니다. diff --git a/ios/Runner/Runner.entitlements b/ios/Runner/Runner.entitlements index a812db50..80b5221d 100644 --- a/ios/Runner/Runner.entitlements +++ b/ios/Runner/Runner.entitlements @@ -2,6 +2,8 @@ + aps-environment + development com.apple.developer.applesignin Default diff --git a/lib/common/models/image_request.freezed.dart b/lib/common/models/image_request.freezed.dart index 07846782..1fd0d4bd 100644 --- a/lib/common/models/image_request.freezed.dart +++ b/lib/common/models/image_request.freezed.dart @@ -246,7 +246,7 @@ extension ImageRequestPatterns on ImageRequest { /// @nodoc @JsonSerializable() class _ImageRequest implements ImageRequest { - const _ImageRequest({this.imageUrl = "", this.sequence = 0}); + const _ImageRequest({this.imageUrl = "", this.sequence = 1}); factory _ImageRequest.fromJson(Map json) => _$ImageRequestFromJson(json); diff --git a/lib/common/models/image_request.g.dart b/lib/common/models/image_request.g.dart index 08fd7669..da4adb15 100644 --- a/lib/common/models/image_request.g.dart +++ b/lib/common/models/image_request.g.dart @@ -9,7 +9,7 @@ part of 'image_request.dart'; _ImageRequest _$ImageRequestFromJson(Map json) => _ImageRequest( imageUrl: json['imageUrl'] as String? ?? "", - sequence: (json['sequence'] as num?)?.toInt() ?? 0, + sequence: (json['sequence'] as num?)?.toInt() ?? 1, ); Map _$ImageRequestToJson(_ImageRequest instance) => diff --git a/lib/common/service/fcm_service.dart b/lib/common/service/fcm_service.dart new file mode 100644 index 00000000..e9d46e9a --- /dev/null +++ b/lib/common/service/fcm_service.dart @@ -0,0 +1,180 @@ +import 'dart:convert'; + +import 'package:firebase_messaging/firebase_messaging.dart'; +import 'package:flutter_local_notifications/flutter_local_notifications.dart'; + +/// 백그라운드 메시지 핸들러 (top-level 함수여야 함) +@pragma('vm:entry-point') +Future _firebaseMessagingBackgroundHandler(RemoteMessage message) async { + print("_firebaseMessagingBackgroundHandler: ${message.notification?.title}"); + FCMService.showNotification(message); +} + +/// Firebase Cloud Messaging(FCM) 서비스 +/// +/// FCM 토큰 관리, 푸시 알림 수신/표시, 알림 클릭 처리를 담당합니다._firebaseMessagingBackgroundHandler +class FCMService { + /// FCM 토큰 (서버로 전송하여 푸시 알림을 받을 수 있음) + static String? fcmToken; + + /// 로컬 알림 플러그인 인스턴스 + static final FlutterLocalNotificationsPlugin _localNotifications = + FlutterLocalNotificationsPlugin(); + + /// Android 알림 채널 ID + static const String _channelId = 'high_importance_channel'; + + /// Android 알림 채널 이름 + static const String _channelName = 'High Importance Notifications'; + + /// Android 알림 채널 설명 + static const String _channelDescription = + 'This channel is used for important notifications.'; + + /// FCM 서비스 초기화 (앱 시작 시 호출) + /// + /// 알림 권한 요청, FCM 토큰 발급, 메시지 핸들러 등록을 수행합니다. + static Future initialize() async { + final FirebaseMessaging firebaseMessaging = FirebaseMessaging.instance; + + await _initializeLocalNotifications(); + + final NotificationSettings settings = + await firebaseMessaging.requestPermission( + alert: true, + badge: true, + sound: true, + ); + + if (settings.authorizationStatus == AuthorizationStatus.authorized) { + await _setupFCMToken(firebaseMessaging); + _registerMessageHandlers(firebaseMessaging); + } + } + + /// FCM 토큰 설정 및 갱신 리스너 등록 + static Future _setupFCMToken(FirebaseMessaging messaging) async { + final String? token = await messaging.getToken(); + if (token != null) { + fcmToken = token; + } + + messaging.onTokenRefresh.listen((newToken) { + fcmToken = newToken; + }); + } + + /// 메시지 핸들러 등록 (포그라운드, 백그라운드, 알림 탭) + static void _registerMessageHandlers(FirebaseMessaging messaging) { + // 포그라운드 메시지 핸들러 (앱이 실행 중일 때) + FirebaseMessaging.onMessage.listen(showNotification); + + // 백그라운드 메시지 핸들러 (앱이 백그라운드 또는 종료 상태일 때) + FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler); + + // 알림 탭으로 앱 실행 시 처리 + FirebaseMessaging.onMessageOpenedApp.listen(clickNotification); + } + + /// 로컬 알림 플러그인 초기화 + static Future _initializeLocalNotifications() async { + const AndroidInitializationSettings initializationSettingsAndroid = + AndroidInitializationSettings('@mipmap/ic_launcher'); + + const DarwinInitializationSettings initializationSettingsiOS = + DarwinInitializationSettings( + requestAlertPermission: false, + requestBadgePermission: false, + requestSoundPermission: false, + ); + + const InitializationSettings initializationSettings = + InitializationSettings( + android: initializationSettingsAndroid, + iOS: initializationSettingsiOS, + ); + + await _localNotifications.initialize( + initializationSettings, + onDidReceiveNotificationResponse: _onNotificationTapped, + ); + + await _createAndroidNotificationChannel(); + } + + /// Android 알림 채널 생성 + static Future _createAndroidNotificationChannel() async { + const AndroidNotificationChannel channel = AndroidNotificationChannel( + _channelId, + _channelName, + description: _channelDescription, + importance: Importance.high, + ); + + await _localNotifications + .resolvePlatformSpecificImplementation< + AndroidFlutterLocalNotificationsPlugin>() + ?.createNotificationChannel(channel); + } + + /// 로컬 알림 탭 시 동작 (포그라운드에서 표시된 알림) + static void _onNotificationTapped(NotificationResponse response) { + if (response.payload != null) { + final data = jsonDecode(response.payload!) as Map; + _handleNotificationTap(data); + } + } + + /// 알림 표시 + static Future showNotification(RemoteMessage message) async { + print("showNotification: ${message.notification?.title}"); + const AndroidNotificationDetails androidDetails = + AndroidNotificationDetails( + _channelId, + _channelName, + channelDescription: _channelDescription, + importance: Importance.high, + priority: Priority.high, + showWhen: true, + ); + + const DarwinNotificationDetails iosDetails = DarwinNotificationDetails( + presentAlert: true, + presentBadge: true, + presentSound: true, + ); + + const NotificationDetails notificationDetails = NotificationDetails( + android: androidDetails, + iOS: iosDetails, + ); + + await _localNotifications.show( + message.hashCode, + message.notification?.title ?? '새 알림', + message.notification?.body ?? '', + notificationDetails, + payload: jsonEncode(message.data), + ); + } + + /// 알림 클릭 시 처리 (백그라운드/종료 상태에서 FCM 알림 탭) + static void clickNotification(RemoteMessage message) { + _handleNotificationTap(message.data); + } + + /// 알림 탭 공통 처리 함수 + /// + /// [data]: 알림 데이터 (페이지 이동 정보 등) + static void _handleNotificationTap(Map data) { + print("_handleNotificationTap: $data"); + // TODO: 페이지 이동 처리 (예: GoRouter 사용) + // 예시: + // final String? type = data['type'] as String?; + // if (type == 'chat') { + // router.push('/chat/${data['chatId']}'); + // } else if (type == 'book') { + // router.push('/book/${data['bookId']}'); + // } + } +} diff --git a/lib/modules/auth/view_model/auth_view_model.dart b/lib/modules/auth/view_model/auth_view_model.dart index c16e567a..c5adcc38 100644 --- a/lib/modules/auth/view_model/auth_view_model.dart +++ b/lib/modules/auth/view_model/auth_view_model.dart @@ -1,9 +1,11 @@ import 'dart:async'; +import 'package:bookstar/common/service/fcm_service.dart'; import 'package:bookstar/modules/auth/model/policy.dart'; import 'package:bookstar/modules/auth/repository/policy_repository.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; +import '../../../infra/network/dio_client.dart'; import '../../../infra/storage/secure_storage.dart'; import '../model/auth_response.dart'; import '../model/login_request.dart'; @@ -65,14 +67,27 @@ class AuthViewModel extends _$AuthViewModel { refreshToken: authData.refreshToken, ); - return AuthSuccess( - memberId: authData.memberId, - nickName: authData.nickName, - profileImage: authData.profileImage, - providerType: authData.providerType, - email: authData.email, - memberRole: authData.memberRole, + await FCMService.initialize(); + final fcmToken = FCMService.fcmToken; + if (fcmToken != null && fcmToken.isNotEmpty) { + final dio = ref.read(dioClientProvider); + await dio.post( + '/api/v2/notifications/fcmToken', + data: { + 'userId': authData.memberId, + 'fcmToken': fcmToken, + }, ); + } + + return AuthSuccess( + memberId: authData.memberId, + nickName: authData.nickName, + profileImage: authData.profileImage, + providerType: authData.providerType, + email: authData.email, + memberRole: authData.memberRole, + ); }); } @@ -156,6 +171,19 @@ class AuthViewModel extends _$AuthViewModel { final providerType = authData.providerType.isNotEmpty ? authData.providerType : '연동 상태'; + await FCMService.initialize(); + final fcmToken = FCMService.fcmToken; + if (fcmToken != null && fcmToken.isNotEmpty) { + final dio = ref.read(dioClientProvider); + await dio.post( + '/api/v2/notifications/fcmToken', + data: { + 'userId': authData.memberId, + 'fcmToken': fcmToken, + }, + ); + } + state = AsyncData( AuthSuccess( memberId: authData.memberId, diff --git a/lib/modules/auth/view_model/auth_view_model.g.dart b/lib/modules/auth/view_model/auth_view_model.g.dart index c029d158..8038f82c 100644 --- a/lib/modules/auth/view_model/auth_view_model.g.dart +++ b/lib/modules/auth/view_model/auth_view_model.g.dart @@ -6,7 +6,7 @@ part of 'auth_view_model.dart'; // RiverpodGenerator // ************************************************************************** -String _$authViewModelHash() => r'9f688c9ad1d35503d17ba1d137454e0780190ff7'; +String _$authViewModelHash() => r'cc2bb74d942a78bfaee0ab616aebca2a8a0e3c16'; /// See also [AuthViewModel]. @ProviderFor(AuthViewModel) diff --git a/pubspec.lock b/pubspec.lock index c2fbbe9c..35160ace 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -13,10 +13,10 @@ packages: dependency: transitive description: name: _flutterfire_internals - sha256: a5788040810bd84400bc209913fbc40f388cded7cdf95ee2f5d2bff7e38d5241 + sha256: f871a7d1b686bea1f13722aa51ab31554d05c81f47054d6de48cc8c45153508b url: "https://pub.dev" source: hosted - version: "1.3.58" + version: "1.3.63" ably_flutter: dependency: "direct main" description: @@ -337,6 +337,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.2.0" + dbus: + dependency: transitive + description: + name: dbus + sha256: "79e0c23480ff85dc68de79e2cd6334add97e48f7f4865d17686dd6ea81a47e8c" + url: "https://pub.dev" + source: hosted + version: "0.7.11" dio: dependency: "direct main" description: @@ -421,74 +429,98 @@ packages: dependency: "direct main" description: name: firebase_analytics - sha256: "178b0275c0b3a53daf3350757856fee4fadc8e324f5fddbc86a1b939074f903b" + sha256: "3cfc4089e61e810ffb531af63cfde2c8cfd36f12dc14fdba359e623992311015" url: "https://pub.dev" source: hosted - version: "11.5.2" + version: "12.0.3" firebase_analytics_platform_interface: dependency: transitive description: name: firebase_analytics_platform_interface - sha256: "13ed951a99a53da0c38e9991e077b0c8b8b739e77ed7933a6942e275874d571a" + sha256: "775fc18d9b00a014362510a33f76f1f34deb30f69a64edcb41a7dfd0ebd9cf98" url: "https://pub.dev" source: hosted - version: "4.4.2" + version: "5.0.3" firebase_analytics_web: dependency: transitive description: name: firebase_analytics_web - sha256: a9d6323b2bd7c2b5189088070ead0dfc8b16cf79e8603a1fc7fe4d661de0d123 + sha256: "6eafa8fef5fdca6c922ac3e353c9a093c12344a3ba996e65fd40f8db0a00d26f" url: "https://pub.dev" source: hosted - version: "0.5.10+15" + version: "0.6.0+3" firebase_auth: dependency: "direct main" description: name: firebase_auth - sha256: f5b640f664aae71774b398ed765740c1b5d34a339f4c4975d4dde61d59a623f6 + sha256: "3150a56fc0f20b4b926e1343bfdca3acb591a0aa1c95bae5426353f384085352" url: "https://pub.dev" source: hosted - version: "5.6.2" + version: "6.1.1" firebase_auth_platform_interface: dependency: transitive description: name: firebase_auth_platform_interface - sha256: "62199aeda6a688cbdefbcbbac53ede71be3ac8807cec00a8066d444797a08806" + sha256: "7bc50c0d74dd8f4c72d7840ae64ea7b638f203d089e5c4a90a157b2f2ead1963" url: "https://pub.dev" source: hosted - version: "7.7.2" + version: "8.1.3" firebase_auth_web: dependency: transitive description: name: firebase_auth_web - sha256: caaf29b7eb9d212dcec36d2eaa66504c5bd523fe844302833680c9df8460fbc0 + sha256: "351dcb82bc542e21a426cd97ffcc40d7232981dafc3fd89a6c932876a09240e1" url: "https://pub.dev" source: hosted - version: "5.15.2" + version: "6.0.4" firebase_core: dependency: "direct main" description: name: firebase_core - sha256: c6e8a6bf883d8ddd0dec39be90872daca65beaa6f4cff0051ed3b16c56b82e9f + sha256: "132e1c311bc41e7d387b575df0aacdf24efbf4930365eb61042be5bde3978f03" url: "https://pub.dev" source: hosted - version: "3.15.1" + version: "4.2.0" firebase_core_platform_interface: dependency: transitive description: name: firebase_core_platform_interface - sha256: "5dbc900677dcbe5873d22ad7fbd64b047750124f1f9b7ebe2a33b9ddccc838eb" + sha256: cccb4f572325dc14904c02fcc7db6323ad62ba02536833dddb5c02cac7341c64 url: "https://pub.dev" source: hosted - version: "6.0.0" + version: "6.0.2" firebase_core_web: dependency: transitive description: name: firebase_core_web - sha256: "0ed0dc292e8f9ac50992e2394e9d336a0275b6ae400d64163fdf0a8a8b556c37" + sha256: ecde2def458292404a4fcd3731ee4992fd631a0ec359d2d67c33baa8da5ec8ae + url: "https://pub.dev" + source: hosted + version: "3.2.0" + firebase_messaging: + dependency: "direct main" + description: + name: firebase_messaging + sha256: "5021279acd1cb5ccaceaa388e616e82cc4a2e4d862f02637df0e8ab766e6900a" url: "https://pub.dev" source: hosted - version: "2.24.1" + version: "16.0.3" + firebase_messaging_platform_interface: + dependency: transitive + description: + name: firebase_messaging_platform_interface + sha256: f3a16c51f02055ace2a7c16ccb341c1f1b36b67c13270a48bcef68c1d970bbe8 + url: "https://pub.dev" + source: hosted + version: "4.7.3" + firebase_messaging_web: + dependency: transitive + description: + name: firebase_messaging_web + sha256: "3eb9a1382caeb95b370f21e36d4a460496af777c9c2ef5df9b90d4803982c069" + url: "https://pub.dev" + source: hosted + version: "4.0.3" fixnum: dependency: transitive description: @@ -542,6 +574,38 @@ packages: url: "https://pub.dev" source: hosted version: "5.0.0" + flutter_local_notifications: + dependency: "direct main" + description: + name: flutter_local_notifications + sha256: "19ffb0a8bb7407875555e5e98d7343a633bb73707bae6c6a5f37c90014077875" + url: "https://pub.dev" + source: hosted + version: "19.5.0" + flutter_local_notifications_linux: + dependency: transitive + description: + name: flutter_local_notifications_linux + sha256: e3c277b2daab8e36ac5a6820536668d07e83851aeeb79c446e525a70710770a5 + url: "https://pub.dev" + source: hosted + version: "6.0.0" + flutter_local_notifications_platform_interface: + dependency: transitive + description: + name: flutter_local_notifications_platform_interface + sha256: "277d25d960c15674ce78ca97f57d0bae2ee401c844b6ac80fcd972a9c99d09fe" + url: "https://pub.dev" + source: hosted + version: "9.1.0" + flutter_local_notifications_windows: + dependency: transitive + description: + name: flutter_local_notifications_windows + sha256: "8d658f0d367c48bd420e7cf2d26655e2d1130147bca1eea917e576ca76668aaf" + url: "https://pub.dev" + source: hosted + version: "1.0.3" flutter_plugin_android_lifecycle: dependency: transitive description: @@ -1589,6 +1653,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.5" + timezone: + dependency: transitive + description: + name: timezone + sha256: dd14a3b83cfd7cb19e7888f1cbc20f258b8d71b54c06f79ac585f14093a287d1 + url: "https://pub.dev" + source: hosted + version: "0.10.1" timing: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 5b5f6706..df40c67d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -47,6 +47,7 @@ dependencies: firebase_auth: firebase_core: firebase_analytics: + firebase_messaging: sleek_circular_slider: ^2.0.1 flutter_rating_bar: ^4.0.1 @@ -68,6 +69,7 @@ dependencies: gal: ^2.3.0 pro_image_editor: ^11.3.0 path_provider: ^2.1.5 + flutter_local_notifications: ^19.5.0 dev_dependencies: flutter_test: