Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: fcm android headup 알림 추가, fcm 어드민 유저 병합 #96

Merged
merged 2 commits into from
Nov 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />

<application
android:name=".MainApplication"
android:label="@string/app_name"
Expand All @@ -21,6 +24,11 @@ xmlns:tools="http://schemas.android.com/tools">
android:name="com.naver.maps.map.CLIENT_ID"
android:value="@string/NAVER_MAP_CLIENT_ID" />

<meta-data
android:name="com.google.firebase.messaging.default_notification_channel_id"
android:value="default_channel_id"
tools:replace="android:value" />

<activity
android:name=".MainActivity"
android:label="@string/app_name"
Expand Down
25 changes: 24 additions & 1 deletion android/app/src/main/java/com/clientapp/MainActivity.kt
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package com.clientapp

import android.app.NotificationChannel
import android.app.NotificationManager
import android.os.Build
import android.os.Bundle
import com.facebook.react.ReactActivity
import com.facebook.react.ReactActivityDelegate
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.fabricEnabled
import com.facebook.react.defaults.DefaultReactActivityDelegate
import android.os.Bundle;

class MainActivity : ReactActivity() {

Expand All @@ -16,6 +19,26 @@ class MainActivity : ReactActivity() {

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(null)

// 알림 채널 생성
createNotificationChannel()
}

/**
* Creates a notification channel for Android 8.0+.
*/
private fun createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channelId = "default_channel_id"
val channelName = "Default Channel"
val descriptionText = "This is the default notification channel for the app."
val importance = NotificationManager.IMPORTANCE_HIGH // 헤드업 알림을 위해 중요도 설정
val channel = NotificationChannel(channelId, channelName, importance).apply {
description = descriptionText
}
val notificationManager = getSystemService(NotificationManager::class.java)
notificationManager?.createNotificationChannel(channel)
}
}

/**
Expand Down
22 changes: 8 additions & 14 deletions ios/ClientApp.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */; };
94CEB96F1A265B79C82B089E /* Pods_ClientApp.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5D3FFA28E7504B9A37D2855D /* Pods_ClientApp.framework */; };
FA2F185C2C9BC72C007629B4 /* SwiftBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA2F185B2C9BC72C007629B4 /* SwiftBridge.swift */; };
FA7928292CDCB37A00B2C9E2 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = FA7928282CDCB37A00B2C9E2 /* GoogleService-Info.plist */; };
FA69802C2CF48CE3004798B8 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = FA69802B2CF48CE3004798B8 /* GoogleService-Info.plist */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand Down Expand Up @@ -51,7 +51,7 @@
ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };
FA2F185A2C9BC72C007629B4 /* ClientApp-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "ClientApp-Bridging-Header.h"; sourceTree = "<group>"; };
FA2F185B2C9BC72C007629B4 /* SwiftBridge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftBridge.swift; sourceTree = "<group>"; };
FA7928282CDCB37A00B2C9E2 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = "<group>"; };
FA69802B2CF48CE3004798B8 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = "GoogleService-Info.plist"; path = "ClientApp/GoogleService-Info.plist"; sourceTree = "<group>"; };
FA79284D2CDD056300B2C9E2 /* ClientApp.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; name = ClientApp.entitlements; path = ClientApp/ClientApp.entitlements; sourceTree = "<group>"; };
FAD230592CB5955600F07473 /* Config.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Config.xcconfig; sourceTree = "<group>"; };
/* End PBXFileReference section */
Expand Down Expand Up @@ -97,7 +97,6 @@
isa = PBXGroup;
children = (
FA79284D2CDD056300B2C9E2 /* ClientApp.entitlements */,
FA7928282CDCB37A00B2C9E2 /* GoogleService-Info.plist */,
13B07FAF1A68108700A75B9A /* AppDelegate.h */,
13B07FB01A68108700A75B9A /* AppDelegate.mm */,
13B07FB51A68108700A75B9A /* Images.xcassets */,
Expand Down Expand Up @@ -132,6 +131,7 @@
83CBB9F61A601CBA00E9B192 = {
isa = PBXGroup;
children = (
FA69802B2CF48CE3004798B8 /* GoogleService-Info.plist */,
FAD230592CB5955600F07473 /* Config.xcconfig */,
13B07FAE1A68108700A75B9A /* ClientApp */,
832341AE1AAA6A7D00B99B32 /* Libraries */,
Expand Down Expand Up @@ -260,7 +260,7 @@
buildActionMask = 2147483647;
files = (
81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */,
FA7928292CDCB37A00B2C9E2 /* GoogleService-Info.plist in Resources */,
FA69802C2CF48CE3004798B8 /* GoogleService-Info.plist in Resources */,
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */,
1AEF1DDAEA082183D637D172 /* PrivacyInfo.xcprivacy in Resources */,
);
Expand Down Expand Up @@ -519,7 +519,7 @@
"-ObjC",
"-lc++",
);
PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.capstone.ClientApp-0.0.1";
PRODUCT_BUNDLE_IDENTIFIER = com.momchanpick.userapp;
PRODUCT_NAME = ClientApp;
SWIFT_OBJC_BRIDGING_HEADER = "ClientApp-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
Expand Down Expand Up @@ -549,7 +549,7 @@
"-ObjC",
"-lc++",
);
PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.capstone.ClientApp-0.0.1";
PRODUCT_BUNDLE_IDENTIFIER = com.momchanpick.userapp;
PRODUCT_NAME = ClientApp;
SWIFT_OBJC_BRIDGING_HEADER = "ClientApp-Bridging-Header.h";
SWIFT_VERSION = 5.0;
Expand Down Expand Up @@ -642,10 +642,7 @@
"-DFOLLY_CFG_NO_COROUTINES=1",
"-DFOLLY_HAVE_CLOCK_GETTIME=1",
);
OTHER_LDFLAGS = (
"$(inherited)",
" ",
);
OTHER_LDFLAGS = "$(inherited) ";
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
SDKROOT = iphoneos;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) DEBUG";
Expand Down Expand Up @@ -730,10 +727,7 @@
"-DFOLLY_CFG_NO_COROUTINES=1",
"-DFOLLY_HAVE_CLOCK_GETTIME=1",
);
OTHER_LDFLAGS = (
"$(inherited)",
" ",
);
OTHER_LDFLAGS = "$(inherited) ";
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
SDKROOT = iphoneos;
USE_HERMES = true;
Expand Down
21 changes: 21 additions & 0 deletions src/apis/Fcm.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import apiClient from './ApiClient';

export const registerFCMToken = async (
deviceToken: string,
): Promise<boolean> => {
try {
const res = await apiClient.post<{code: number; message: string}>(
'/members/device-token',
{},
{
params: {
deviceToken,
},
},
);
return !!res && res.code === 200;
} catch (error) {
console.error(error);
return false;
}
};
8 changes: 3 additions & 5 deletions src/screens/FeedScreen/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ import {BottomButton} from '@/components/common';
import S from './SearchBar.style';

import {
handleForegroundMessage,
onForegroundMessageHandler,
requestUserPermission,
requestNotificationPermission,
setBackgroundMessageHandler,
} from '@/utils/fcm';
} from '@/utils/notification';
type Props = {
navigation: StackNavigationProp<RootStackParamList, 'Home'>;
};
Expand Down Expand Up @@ -162,10 +162,8 @@ const FeedScreen = ({navigation}: Props) => {
useEffect(() => {
requestNotificationPermission();
requestUserPermission();
const unsubscribe = handleForegroundMessage();
setBackgroundMessageHandler();

return unsubscribe;
onForegroundMessageHandler();
}, [navigation]);

useEffect(() => {
Expand Down
106 changes: 106 additions & 0 deletions src/utils/notification.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import messaging from '@react-native-firebase/messaging';
import notifee, {AndroidImportance} from '@notifee/react-native';
import {PermissionsAndroid, Platform} from 'react-native';
import {registerFCMToken} from '@/apis/Fcm';

// 포어그라운드에서 푸시 알림 처리 함수
export const onForegroundMessageHandler = () => {
messaging().onMessage(async remoteMessage => {
console.log('Foreground Message:', remoteMessage);
await displayNotification(remoteMessage);
});
};

// 백그라운드에서 푸시 알림 처리 함수
export const setBackgroundMessageHandler = () => {
messaging().setBackgroundMessageHandler(async remoteMessage => {
console.log('Background Message:', remoteMessage);
await displayNotification(remoteMessage);
});
notifee.onBackgroundEvent(async ({type, detail}) => {
console.log('Notifee Background Event:', type, detail);
});
};

// 알림 표시 함수
export const displayNotification = async (remoteMessage: any) => {
const {title, body} = remoteMessage.notification ?? {};
console.log('notification body:', title, body);

if (Platform.OS === 'android') {
await notifee.displayNotification({
title,
body,
android: {
channelId: await createAndroidChannel(),
importance: AndroidImportance.HIGH,
sound: 'default',
pressAction: {
id: 'default',
},
},
});
} else {
const settings = await notifee.requestPermission();
if (settings.authorizationStatus) {
console.log('iOS firebase notification permission');
}
await notifee.displayNotification({
title,
body,
ios: {
sound: 'default',
},
});
}
};

// Android 채널 생성 함수
export const createAndroidChannel = async (): Promise<string> => {
const channelId = await notifee.createChannel({
id: 'default',
name: 'Default Channel',
importance: AndroidImportance.HIGH,
sound: 'default', // 채널 기본 사운드 추가
});
return channelId;
};

// 알림 권한 요청 함수
export const requestUserPermission = async () => {
const authStatus = await messaging().requestPermission();
const enabled =
authStatus === messaging.AuthorizationStatus.AUTHORIZED ||
authStatus === messaging.AuthorizationStatus.PROVISIONAL;

if (enabled) {
console.log('Notification permission granted');
const token = await messaging().getToken();
await registerFCMToken(token);
console.log('FCM Token:', token);
} else {
console.log('Notification permission denied');
}
};

// 알림 권한 요청 함수 (안드로이드)
export const requestNotificationPermission = async () => {
if (Platform.OS === 'android' && Platform.Version >= 33) {
const granted = await PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.POST_NOTIFICATIONS,
{
title: '푸시 알림 권한 요청',
message: '알림을 활성화하려면 권한이 필요합니다.',
buttonNeutral: '나중에',
buttonNegative: '취소',
buttonPositive: '확인',
},
);

if (granted === PermissionsAndroid.RESULTS.GRANTED) {
console.log('Notification permission granted');
} else {
console.log('Notification permission denied');
}
}
};
Loading