Skip to content

Commit

Permalink
Merge pull request #67 from proj-poppin/feature/#59
Browse files Browse the repository at this point in the history
✨Feature - FCM Notification 기능 추가 (#59)
  • Loading branch information
puretension authored Jun 23, 2024
2 parents ce3195f + f514757 commit 079d9a2
Show file tree
Hide file tree
Showing 10 changed files with 113 additions and 98 deletions.
81 changes: 0 additions & 81 deletions App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,89 +4,8 @@ import AppInner from './AppInner.tsx';
import {SafeAreaProvider} from 'react-native-safe-area-context';
import {GestureHandlerRootView} from 'react-native-gesture-handler';
import {BottomSheetModalProvider} from '@gorhom/bottom-sheet';
import messaging from '@react-native-firebase/messaging';
import PushNotification from 'react-native-push-notification';
import PushNotificationIOS from '@react-native-community/push-notification-ios';

import store from './src/redux/stores';
import './localConfig';
import {Alert, NativeModules, Platform} from 'react-native';

messaging().setBackgroundMessageHandler(async remoteMessage => {
console.log('Message handled in the background!', remoteMessage);
});

PushNotification.configure({
// (optional) 토큰이 생성될 때 실행됨(토큰을 서버에 등록할 때 쓸 수 있음)
onRegister: function (token: any) {
console.log('TOKEN2:', token);
},

// (required) 리모트 노티를 수신하거나, 열었거나 로컬 노티를 열었을 때 실행
onNotification: function (notification: any) {
console.log('NOTIFICATION:', notification);
if (notification.channelId === 'riders') {
// if (notification.message || notification.data.message) {
// store.dispatch(
// userSlice.actions.showPushPopup(
// notification.message || notification.data.message,
// ),
// );
// }
}
// process the notification

// (required) 리모트 노티를 수신하거나, 열었거나 로컬 노티를 열었을 때 실행
notification.finish(PushNotificationIOS.FetchResult.NoData);
},

// (optional) 등록한 액션을 누렀고 invokeApp이 false 상태일 때 실행됨, true면 onNotification이 실행됨 (Android)
onAction: function (notification: any) {
console.log('ACTION:', notification.action);
console.log('NOTIFICATION:', notification);

// process the action
},

// (optional) Called when the user fails to register for remote notifications. Typically occurs when APNS is having issues, or the device is a simulator. (iOS)
onRegistrationError: function (err: Error) {
console.error(err.message, err);
},

// IOS ONLY (optional): default: all - Permissions to register.
permissions: {
alert: true,
badge: true,
sound: true,
},

// Should the initial notification be popped automatically
// default: true
popInitialNotification: true,

/**
* (optional) default: true
* - Specified if permissions (ios) and token (android and ios) will requested or not,
* - if not, you must call PushNotificationsHandler.requestPermissions() later
* - if you are not using remote notification or do not have Firebase installed, use this:
* requestPermissions: Platform.OS === 'ios'
*/
requestPermissions: true,
});
PushNotification.createChannel(
{
channelId: 'riders', // (required)
channelName: '앱 전반', // (required)
channelDescription: '앱 실행하는 알림', // (optional) default: undefined.
soundName: 'default', // (optional) See `soundName` parameter of `localNotification` function
importance: 4, // (optional) default: 4. Int value of the Android notification importance
vibrate: true, // (optional) default: true. Creates the default vibration patten if true.
},
(created: boolean) =>
console.log(`createChannel riders returned '${created}'`), // (optional) callback returns whether the channel was created, false means it already existed.
);

// ㄴ

function App() {
return (
Expand Down
13 changes: 6 additions & 7 deletions src/apis/popup/addInterestPopUp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,16 @@ export interface AddRecommendReviewResponse {
message: string;
};
}
const addInterestPopup = async (popupId: number, fcmToken: string) => {
interface AddInterestPopupParams {
popupId: number;
fcm_token: string;
}
const addInterestPopup = async (params: AddInterestPopupParams) => {
try {
const response = await nonPublicApiInstance.post(
'/api/v1/interest/add-interest',
null,
{
params: {
popupId: popupId,
fcm_token: 'fcmToken',
},
},
{params: params},
);
console.log('addInterestPopup response:', response.data);

Expand Down
13 changes: 11 additions & 2 deletions src/apis/popup/deleteInterestPopUp.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,23 @@
import nonPublicApiInstance from '../apiInstance/NonPublicApiInstance.ts';

const deleteInterestPopUp = async (popupId: number, fcm_token: string) => {

interface AddInterestPopupParams {
popupId: number;
fcm_token: string;
}

const deleteInterestPopUp = async (params: AddInterestPopupParams) => {
try {
const response = await nonPublicApiInstance.delete(
'/api/v1/interest/remove-interest',
{
params: {popupId: popupId, fcm_token: fcm_token},
data: null,
params: params,
},
);

console.log(response.data);

if (response.data.success) {
return response.data;
} else {
Expand Down
48 changes: 48 additions & 0 deletions src/apis/push/firebase.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import {NavigationProp} from '@react-navigation/native';
import PushNotificationIOS, {
PushNotification,
} from '@react-native-community/push-notification-ios';
import messaging from '@react-native-firebase/messaging';

export const initFirebaseNotification = (
navigation: NavigationProp<ReactNavigation.RootParamList>,
) => {
// 푸시 메세지 Notification 처리
messaging().onMessage(async remoteMessage => {
console.log('Message handled in the foreground!', remoteMessage);
if (remoteMessage.data) {
PushNotificationIOS.addNotificationRequest({
id: 'remoteMessage', // unique identifier for the notification
title: remoteMessage.notification?.title || 'Default Title',
body: remoteMessage.notification?.body || 'Default Body',
userInfo: remoteMessage.data,
});
}
});

// 백그라운드에서 Notification 눌렀을 때 이벤트 처리
messaging().onNotificationOpenedApp(remoteMessage => {
try {
console.log('Message handled in the background!', remoteMessage);
const popupId = remoteMessage?.data?.popupId;
// @ts-ignore
navigation.navigate('PopUpDetail', {id: popupId});
} catch (error) {
console.log('Background Notification Error', error);
}
});

// 포그라운드에서 Notification 눌렀을 때 이벤트 처리
PushNotificationIOS.addEventListener(
'localNotification',
(notification: PushNotification) => {
try {
const pushData = notification.getData();
// @ts-ignore
navigation.navigate('PopUpDetail', {id: pushData.popupId});
} catch (error) {
console.log('Foreground Notification Error', error);
}
},
);
};
13 changes: 13 additions & 0 deletions src/apis/push/registerPushToken.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import PublicApiInstance from '../apiInstance/PublicApiInstance.ts';

interface PushTokenParams {
token: string;
device: string;
}
export const registerPushToken = async (params: PushTokenParams) => {
const response = await PublicApiInstance.post(
'/api/v1/noti/apply/FCMtoken',
params,
);
return response.data;
};
6 changes: 4 additions & 2 deletions src/hooks/detailPopUp/useAddInterestPopUp.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {useState} from 'react';
import addInterestPopUp from '../../apis/popup/addInterestPopUp.ts';
import EncryptedStorage from "react-native-encrypted-storage";

interface AddInterestState {
loading: boolean;
Expand All @@ -14,10 +15,11 @@ const useAddInterestPopUp = () => {
success: null,
});

const addInterest = async (popUpId: number, fcm_token: string) => {
const addInterest = async (popupId: number) => {
setAddInterestState({loading: true, error: null, success: null});
try {
const response = await addInterestPopUp(popUpId, fcm_token);
const fcm_token = (await EncryptedStorage.getItem('pushToken')) ?? '';
const response = await addInterestPopUp({popupId, fcm_token});
if (response.success) {
setAddInterestState({loading: false, error: null, success: true});
} else {
Expand Down
6 changes: 4 additions & 2 deletions src/hooks/detailPopUp/useDeleteInterestPopUp.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {useState} from 'react';
import getDeletePopUp from '../../apis/popup/deleteInterestPopUp.ts';
import EncryptedStorage from "react-native-encrypted-storage";

interface DeleteInterestState {
loading: boolean;
Expand All @@ -15,11 +16,12 @@ const useDeleteInterestPopUp = () => {
success: null,
});

const deleteInterest = async (popUpId: number, fcm_token: string) => {
const deleteInterest = async (popupId: number) => {
setDeleteInterestState({loading: true, error: null, success: null});

try {
const response = await getDeletePopUp(popUpId, fcm_token);
const fcm_token = (await EncryptedStorage.getItem('pushToken')) ?? '';
const response = await getDeletePopUp({popupId, fcm_token});
if (response.success) {
setDeleteInterestState({loading: false, error: null, success: true});
} else {
Expand Down
6 changes: 4 additions & 2 deletions src/hooks/findPopUp/usePostBookmarkPopup.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {useState} from 'react';
import addInterestPopUp from '../../apis/popup/addInterestPopUp.ts';
import EncryptedStorage from "react-native-encrypted-storage";

interface AddInterestState {
loading: boolean;
Expand All @@ -14,10 +15,11 @@ const usePostBookmarkPopup = () => {
success: null,
});

const addInterest = async (popUpId: number) => {
const addInterest = async (popupId: number) => {
setAddInterestState({loading: true, error: null, success: null});
try {
const response = await addInterestPopUp(popUpId);
const fcm_token = (await EncryptedStorage.getItem('pushToken')) ?? '';
const response = await addInterestPopUp({popupId, fcm_token});
if (response.success) {
setAddInterestState({loading: false, error: null, success: true});
} else {
Expand Down
5 changes: 5 additions & 0 deletions src/navigators/AppNavigator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ import ReportOptions from './options/ReportOptions.tsx';
import PopUpEditRequestScreen from '../pages/detail/PopUpEditRequestScreen.tsx';
import PopUpEditRequestOptions from './options/PopUpEditRequestOptions.tsx';
import PrivacyPolicyOptions from './options/PrivacyPolicyOptions.tsx';
import {useNavigation} from '@react-navigation/native';
import {initFirebaseNotification} from '../apis/push/firebase.ts';
import PreferenceSettingScreen from '../pages/myPage/preferenceSetting/PreferenceSettingScreen.tsx';
import FAQFormScreen from '../pages/myPage/FAQFormScreen.tsx';
import PasswordCheckScreen from '../pages/myPage/PasswordCheckScreen.tsx';
Expand All @@ -67,6 +69,9 @@ const DefaultNoHeaderOptions = {
};

function AppNavigator() {
const navigation = useNavigation();
initFirebaseNotification(navigation);

return (
<Stack.Navigator screenOptions={screenOptions}>
<Stack.Screen
Expand Down
20 changes: 18 additions & 2 deletions src/navigators/RootNavigator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import getUser from '../apis/user/getUser.ts';
import LoadingScreen from '../pages/splash/LoadingScreen.tsx';
import userSlice from '../redux/slices/user.ts';
import messaging from '@react-native-firebase/messaging';
import { registerPushToken } from "../apis/push/registerPushToken.ts";
import { Alert, Platform } from "react-native";

const RootNavigator = () => {
const dispatch = useDispatch();
Expand Down Expand Up @@ -63,8 +65,22 @@ const RootNavigator = () => {
}
const token = await messaging().getToken();
console.log('phone token', token);
// dispatch(userSlice.actions.setPhoneToken(token));
// return axios.post(`${Config.API_URL}/phonetoken`, {token});

const storedToken = await EncryptedStorage.getItem('pushToken');
if (storedToken === token) {
console.log('푸시토큰이 이미 등록되어 있습니다.');
return;
}
const response = await registerPushToken({
token: token,
device: Platform.OS,
});
if (response?.success) {
console.log('푸시 토큰 등록에 성공했습니다.');
await EncryptedStorage.setItem('pushToken', token);
} else {
console.error(`푸시 토큰 등록에 실패했습니다. ${response?.error}`);
}
} catch (error) {
console.log(error);
}
Expand Down

0 comments on commit 079d9a2

Please sign in to comment.