Skip to content

9oHigh/usket.SNS-App

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

75 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

SNS APP

πŸ“ƒ λͺ©μ°¨


πŸ’ ν”„λ‘œμ νŠΈ μ†Œκ°œ

"Firestore와 Firebase Cloud Messaging, Cloud Functionsλ₯Ό ν™œμš©ν•΄ μ‹€μ‹œκ°„ μ•Œλ¦Όμ„ μ œκ³΅ν•˜λŠ” SNS APP"

  • 이미지와 ν•¨κ»˜ κ²Œμ‹œλ¬Όμ„ μž‘μ„±ν•˜κ³ , μ‚¬μš©μžλ“€μ˜ λŒ“κΈ€κ³Ό μ’‹μ•„μš” μ΄λ²€νŠΈμ— λŒ€ν•œ μ‹€μ‹œκ°„ μ•Œλ¦Όμ„ μ œκ³΅ν•˜λŠ” κ°„λ‹¨ν•œ SNS μ•±

πŸ“± μŠ€ν¬λ¦°μƒ·

Β Β Β  Image 2 Β Β Β  Image 3

βš™οΈ μ‚¬μš©ν•œ 기술 μŠ€νƒ

  • Front

    flutter Β Β Β  dart
    Package Purpose
    flutter_riverpod μƒνƒœ 관리λ₯Ό μœ„ν•΄ μ‚¬μš©
    shared_preferences κ°„λ‹¨ν•œ 데이터λ₯Ό λ‘œμ»¬μ— μ €μž₯ν•˜κΈ° μœ„ν•΄ μ‚¬μš©(둜그인 μƒνƒœ, UserId λ“±)
    go_router ν™”λ©΄ μ „ν™˜ 관리λ₯Ό μœ„ν•΄ μ‚¬μš©
    get_it μ˜μ‘΄μ„± 관리λ₯Ό μœ„ν•΄ μ‚¬μš©
  • Back

    nodejs Β Β Β 
    Package Purpose
    firebase_auth Firebase Authentication을 μ΄μš©ν•œ νšŒμ›κ°€μž… 진행을 μœ„ν•΄ μ‚¬μš©
    cloud_firestore Firestoreλ₯Ό μ΄μš©ν•΄ μ‚¬μš©μž 정보, κ²Œμ‹œκΈ€, μ•Œλ¦Ό λ“±μ˜ 데이터 μ €μž₯ν•˜κΈ° μœ„ν•΄ μ‚¬μš©
    firebase_messaging μ’‹μ•„μš”, λŒ“κΈ€ μ•Œλ¦Όμ„ μ‚¬μš©μžμ—κ²Œ 보내기 μœ„ν•΄ μ‚¬μš©
    cloud_functions μ’‹μ•„μš”, λŒ“κΈ€ μ΄λ²€νŠΈκ°€ λ°œμƒν•˜κ³ , Firestore에 변경사항을 감지해 ν•΄λ‹Ή μ‚¬μš©μžμ—κ²Œ μ•Œλ¦Όμ„ 보내기 μœ„ν•΄ μ‚¬μš©
    firebase_storage μ‚¬μš©μžκ°€ μ—…λ‘œλ“œν•œ κ²Œμ‹œλ¬Όμ˜ 사진을 μ €μž₯ν•˜κ³ , κ΄€λ¦¬ν•˜κΈ° μœ„ν•΄ μ‚¬μš©

  • ν˜‘μ—…λ„κ΅¬

    gitlab Β Β Β  notion Β Β Β  discord Β Β Β 

πŸ—οΈ 디렉토리 ꡬ쑰

β”œβ”€β”€ core
β”‚   β”œβ”€β”€ constants
β”‚   β”‚   β”œβ”€β”€ colors.dart
β”‚   β”‚   └── sizes.dart
β”‚   β”œβ”€β”€ di
β”‚   β”‚   └── injector.dart
β”‚   β”œβ”€β”€ manager
β”‚   β”‚   β”œβ”€β”€ alert_manager.dart
β”‚   β”‚   └── shared_preferences_manager.dart
β”‚   └── router
β”‚       └── router.dart
β”œβ”€β”€ data
β”‚   β”œβ”€β”€ datasources
β”‚   β”‚   β”œβ”€β”€ signin
β”‚   β”‚   └── signup
β”‚   β”œβ”€β”€ models
β”‚   β”‚   β”œβ”€β”€ comment_model.dart
β”‚   β”‚   β”œβ”€β”€ notification_model.dart
β”‚   β”‚   β”œβ”€β”€ post_model.dart
β”‚   β”‚   └── user_model.dart
β”‚   └── repositories
β”‚       β”œβ”€β”€ signin
β”‚       β”œβ”€β”€ signup
β”‚       └── user
β”œβ”€β”€ domain
β”‚   β”œβ”€β”€ repositories
β”‚   β”‚   β”œβ”€β”€ signin
β”‚   β”‚   └── signup
β”‚   └── usecases
β”‚       β”œβ”€β”€ signin
β”‚       └── signup
β”œβ”€β”€ firebase_options.dart
β”œβ”€β”€ main.dart
└── presentation
    β”œβ”€β”€ screens
    β”‚   β”œβ”€β”€ app
    β”‚   β”œβ”€β”€ create_post
    β”‚   β”œβ”€β”€ feed
    β”‚   β”œβ”€β”€ notification
    β”‚   β”œβ”€β”€ post_detail
    β”‚   β”œβ”€β”€ profile
    β”‚   β”œβ”€β”€ signin
    β”‚   └── signup
    └── widgets
        β”œβ”€β”€ bottom_nav_bar.dart
        β”œβ”€β”€ comment_card.dart
        β”œβ”€β”€ custom_appbar.dart
        β”œβ”€β”€ custom_floating_button.dart
        β”œβ”€β”€ gesture_button.dart
        β”œβ”€β”€ label_textfield.dart
        └── post_card.dart

🚩 μ„±κ³Ό

  • FCMκ³Ό Cloud Functionsλ₯Ό 톡해 μ‹€μ‹œκ°„ μ•Œλ¦Όμ„ μ œκ³΅ν•˜λŠ” 방법을 μ•Œ 수 μžˆμ—ˆμŠ΅λ‹ˆλ‹€.
    1. μ΄ˆκΈ°ν™”
      Future<void> _initializeFCM() async {
      // 앱이 싀행쀑이 아닐 경우, 메세지λ₯Ό μ²˜λ¦¬ν•˜λŠ” ν•Έλ“€λŸ¬λ₯Ό μΆ”κ°€
      FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
      // Flutter Local Notification을 μ΄ˆκΈ°ν™”
      final flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
      // μ•ˆλ“œλ‘œμ΄λ“œ μ•Œλ¦Ό 채널 생성 ( 8.0 μ΄μƒμ—μ„œ ν•„μˆ˜ )
      await flutterLocalNotificationsPlugin
          .resolvePlatformSpecificImplementation<
              AndroidFlutterLocalNotificationsPlugin>()
          ?.createNotificationChannel(const AndroidNotificationChannel(
              'high_importance_channel', 'high_importance_notification',
              importance: Importance.max));
      await flutterLocalNotificationsPlugin.initialize(const InitializationSettings(
          android: AndroidInitializationSettings("@mipmap/ic_launcher")));
      // Foreground μƒνƒœμ—μ„œλ„ ν‘œμ‹œν•˜κΈ° μœ„ν•œ μ˜΅μ…˜ μ„€μ • 
      await FirebaseMessaging.instance.setForegroundNotificationPresentationOptions(
          alert: true, badge: true, sound: true);
      }
    2. Cloud Functionsλ₯Ό μ΄ˆκΈ°ν™”, index.js μž‘μ„±
    • μ˜ˆμ‹œ ) μ’‹μ•„μš” μ΄λ²€νŠΈμ— λŒ€ν•œ 트리거λ₯Ό μ„€μ • ( firestore에 document 생성 )
      exports.sendLikeNotification = onDocumentCreated(
          "/posts/{postId}/likes/{uid}",
          async (event) => {
              /*
              [feed_notifier.dart]
              likeDocRef.set({
                  'userId': userId,
                  'likedAt': FieldValue.serverTimestamp(),
                  'nickname': nickname,
              });
              likesDoc에 μœ„μ˜ μ½”λ“œλ₯Ό 톡해 μ’‹μ•„μš”λ₯Ό ν΄λ¦­ν•œ μœ μ €κ°€ μΆ”κ°€λœλ‹€.
              */
              // event -> onDocumentCreated("/posts/{postId}/likes/{uid}")
              // event.parms -> { postId: ..., uid: ... }
              const postId = event.params.postId; 
              const uid = event.params.uid;
              /*
              "/posts/{postId}/likes/{uid}" κ²½λ‘œμ— 생긴 데이터λ₯Ό λ§ν•œλ‹€.
              event.data -> {
                  "userId": ...,
                  "likedAt": ...,
                  "nickname": ...
              }
              */
              const likeData = event.data.data();
              const postSnapshot = await admin.firestore().collection("posts").doc(postId).get();
              const post = postSnapshot.data();
              const authorId = post.uid;
              // μžμ‹ μ΄ μž‘μ„±ν•œ κ²Œμ‹œλ¬Όμ— μ’‹μ•„μš”λ₯Ό λˆŒλ €μ„ λ•ŒλŠ” μ•Œλ¦Ό 처리 X
              if (authorId === uid) {
                  return;
              }
              // κ²Œμ‹œμžμ—κ²Œ μ•Œλ¦Ό 보내기
              const userSnapshot = await admin.firestore().collection("users").doc(authorId).get();
              const authorData = userSnapshot.data();
              const token = authorData.fcmToken;
              const message = {
                  notification: {
                      title: "μƒˆλ‘œμš΄ μ’‹μ•„μš”",
                      body: `${likeData.nickname}λ‹˜μ΄ κ²Œμ‹œλ¬Όμ„ μ’‹μ•„ν•©λ‹ˆλ‹€.\nν™•μΈν•΄λ³΄μ„Έμš” :)`,
                  },
                  token: token,
                  // νƒ€μž…μ„ 톡해 μ•„μ΄μ½˜ μ΄ˆκΈ°ν™”
                  // IDλ₯Ό ν†΅ν•΄μ„œ ν™”λ©΄μ „ν™˜, κ²Œμ‹œλ¬Ό λ‚΄μš© ν‘œμ‹œ
                  data: {
                      type: "like",
                      postId: postId,
                  },
              };
              // FCM이 메세지λ₯Ό λ³΄λ‚΄λŠ” μ½”λ“œ
              await admin.messaging().send(message);
      
              const notification = {
                  type: "like",
                  postId: postId,
                  userId: uid,
                  message: `${likeData.nickname}λ‹˜μ΄ κ²Œμ‹œλ¬Όμ„ μ’‹μ•„ν•©λ‹ˆλ‹€.`,
                  createdAt: admin.firestore.FieldValue.serverTimestamp(),
              };
              // firestore에도 user의 notification μ»¬λ ‰μ…˜μ— μΆ”κ°€ν•΄μ£ΌκΈ°
              await admin.firestore().collection("users").doc(authorId).collection("notifications").add(notification);
          },
      );
    1. FCM λ¦¬μŠ€λ„ˆλ₯Ό μ„€μ •ν•˜κ³ , 처리
    • appNotifier.dart μ—μ„œ μ•Œλ¦Ό μˆ˜μ‹ μ‹œ 화면에 ν‘œμ‹œλ  μ•Œλ¦Ό 갯수λ₯Ό μˆ˜μ •ν•œλ‹€.

      FirebaseMessaging.onMessage.listen((RemoteMessage message) async {
          RemoteNotification? notification = message.notification;
          if (notification != null) {
              FlutterLocalNotificationsPlugin().show(
                  notification.hashCode,
                  notification.title,
                  notification.body,
                  const NotificationDetails(
                      android: AndroidNotificationDetails(
                      'high_importance_channel',
                      'high_importance_notification',
                      importance: Importance.max,
                  )));
              // 갯수 μΆ”κ°€ + μ €μž₯ 데이터 μ—…λ°μ΄νŠΈ
              int count = state.notificationCount;
              state = state.copyWith(notificationCount: count + 1);
              SharedPreferenceManager()
                  .setPref<int>(PrefsType.unReadNotificationCount, count + 1);
          }
      });

😎 νŒ€μ›

ν”„λ‘œν•„ 이미지 μ§„μœ λ¦¬
- ν”„λ‘œν•„ ν™”λ©΄ & ν”„λ‘œν•„ μˆ˜μ • ν™”λ©΄ κ΅¬ν˜„
- κ²Œμ‹œλ¬Ό 생성 ν™”λ©΄ κ΅¬ν˜„
ν”„λ‘œν•„ 이미지 이경후
- νšŒμ›κ°€μž… & 둜그인 ν™”λ©΄ ꡬ좕 및 κΈ°λŠ₯ κ΅¬ν˜„
- ν”Όλ“œ ν™”λ©΄ 및 κΈ°λŠ₯ κ΅¬ν˜„
- Firestore, cloud storage κ΅¬μΆ•ν•˜κ³  κ΄€λ ¨ 둜직 μΆ”κ°€(Create, Read)
- Cloud Functionsλ₯Ό 톡해 μ•Œλ¦Ό μžλ™ν™” ꡬ좕

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 4

  •  
  •  
  •  
  •