728x90

RN Firebase messaging 포스팅의 최종판이다.

 

[이전 관련글]

https://honeystorage.tistory.com/255

https://honeystorage.tistory.com/276

https://honeystorage.tistory.com/292

https://honeystorage.tistory.com/301

https://honeystorage.tistory.com/305

 

왜 이렇게나 한가지 기능에 대해

많은 포스팅을 하게 된것일까...

 

첫째,

아마도 너무나도 다양한

환경설정 속에서

내게 맞는 솔루션을 찾지 못했던것

 

둘째,

공식 가이드라인을

꼼꼼히 읽어보지않고

stackoverflow에 너무 크게 의존한것

 

셋째,

내 상황을 정확히 분석하지 못하고

해답만 찾으려고 시도했던것

 

넷째,

클라인지 서버인지

무엇이 잘못된건지모르고

해결하려고 삽질했던것

 

각설하고

앞으로 한국 RN 유저들이 더이상

나와 같은 시행착오를

겪지 않았으면 하는 마음으로

상세히 포스팅을 작성해봅니다.

 

[ 환경 설정 - client ]
* RN: 0.63
* @react-native-firebase/app: ^12.9.0
* @react-native-firebase/messaging: ^12.9.0
* @react-native-community/push-notification-ios: ^1.10.1
* @types/react-native-push-notification: *7.3.3


[환경 설정 - server]
* firebase-admin: ^10.0.0

 

자, 그럼 지금부터

길고  긴 push notification 구현을 위한

여정을 떠나보도록 하겠습니다.

 

1. 개발환경 설정

먼저, 구현 단계 이전의 환경설정 파트는

https://honeystorage.tistory.com/255

위 글에서 매우 상세히 다루었습니다.

 

위 글을 참고하여 코드 구현 이외의

환경설정을 완료하도록 하면 되겠습니다.

 

 

2. 코드 구현 - 서버

서버에서는 간략 하지만 강력한

푸시메시지 발송 방법을 소개하겠습니다.

(아래와 같은 설명은 그 어디에서도 명쾌하게 설명된것을 본적이 없습니다.)

 

서버에서 발송하는 메시지는

2가지로 나뉩니다.

 

Silent / None Silent

 

Silent, 말 그대로

쥐도새도모르게 푸시가 와서

Status Bar에 푸시가 떠있습니다.

 

이 경우엔 화면에 푸시 팝업이 뜨지 않으며,

진동이나 소리도 나지 않습니다.

 

조용히 알려주는 광고 알림등에서는

이를 이용하여 사용자가 기분 상하지 않는선에서

광고를 할수 있겠죠.

 

None Silent는 Silent와 반대입니다.

진동이나 소리가 나며 푸시가 도착합니다.

핸드폰 화면이 켜져있는 상태에서는

푸시 팝업이 나타나며 푸시가 왔음을 명확히 알려줍니다.

 

(저는 None Silent 기능이 필요했는데

대부분의 자료에서는 Silent관련 내용만 나와있더군요 ...)

 

어떻게 해야 알맞는 방법으로

메시지를 보낼 수 있는지

코드로 확인해보겠습니다.

// Silent Push Notification

import fbAdmin from 'firebase-admin';

type PushMessage = {
  token: string;
  title: string;
  body: string;
}

const sendPushNotification = ({ token, title, body }: PushMessage) => {
  const message = {
    token,
    notification: {
      title,
      body,
    },
    data: {
      title,
      body,
    },
    android: {
      priority: 'high',
      notification: {
        title,
        body,
        sound: 'default'
      }
    },
    apns: {
      headers: {
        'apns-priority': 5,
        'apns-push-type': 'background'
      },
      payload: {
        aps: {
          sound: 'default',
          'content-available': 1
        }
      }
    }
  };


  fbAdmin
    .messaging()
    .send(message)
    .catch(error => {
      console.log('push error: ', error);
      // delete token or do something
    })
}
// None Silent Push Notification

import fbAdmin from 'firebase-admin';

type PushMessage = {
  token: string;
  title: string;
  body: string;
}

const sendPushNotification = ({ token, title, body }: PushMessage) => {
  const message = {
    token,
    notification: {
      title,
      body,
    },
    android: {
      priority: 'high',
      notification: {
        sound: 'default'
      }
    },
    apns: {
      headers: {},
      payload: {
        aps: {
          sound: 'default',
          'content-available': 1
        }
      }
    }
  };


  fbAdmin
    .messaging()
    .send(message)
    .catch(error => {
      console.log('push error: ', error);
      // delete token or do something
    })
}

Silent Message가 설정해줄것들이

조금 더 많은것을 볼 수 있습니다.

 

Docs나 Stackoverflow에 많은 정보들이 있지만

이대로만 하면 위 두가지 사항중

원하는 목적을 달성할 수 있습니다.

 

3. 코드 구현 - 클라이언트

정확하게 알맞는 디바이스에

푸시를 발송해주기 위해서는

token을 사용자 디바이스별로

잘 관리해주어야합니다.

 

token일 불일치 할 경우,

아무리 올바르게 fcm 메시징 요청을 하더라도

디바이스에서 수신을 못합니다.

 

token을 관리하는 코드를

작성해보도록 하겠습니다.

import messaging from '@react-native-firebase/messaging'
import { Platform } from 'react-native';
import axios from 'axios';


const [_permission, setPermission] = useState(0);

useEffect(() => {
  _requestPermissionHandler();
}, []);

useEffect(() => {
  requestNotiPermission();
}, [_permission])

const _requestPermissionHandler = () => {
  const perm = await messaging().hasPermission();
  setPermission(perm);
}

const requestNotiPermission = async () => {
  // 사용자 푸시 권한 수락/거절상태 갱신
  await axios.put('url...', { uId: userId, permission: _permission });
  
  // 사용자 푸시 권한이 수락 상태면 토큰 얻어서 갱신
  if (_permission >= 1) {
    const token = await messaging().getToken();
    await axios.put('url...', { uId: userId, token });
    Platform.OS && messaging().setAutoInitEnabled(true);
  }
}

 

이런식으로

사용자의 푸시 권한 상태에 대한 확인 및 갱신과

푸시 토큰의 갱신을 위한 코드를 작성하면 되겠습니다.

 

얼마나 자주, 언제 토큰이나 권한을 갱신해줄지는

앱의 특성이나 상황에 따라 설정해주면 될것입니다.

 

 

4. background 알림 수신 처리 (optional)

마지막 파트는 선택사항입니다.

백그라운드 알림을 수신해

badge를 갱신한다던지 무언가 처리를 원할때

처리하시면 되겠습니다.

(* badge: 앱 아이콘 위에 나타나는 숫자)

 

바로, 말도 많고 탈도 많은

setBackgroundMessageHandler 기능을 활용한

background 알림 처리를 다뤄보겠습니다.

 

최근까지도 계속해서

되니 안되니 이슈가 많은것으로 보이는 기능입니다.

 

계속 연구를 해보니

아래와 같은 경우의 수를 체크해서

알람이 정상인지 확인할수가 있습니다.

  aos - 알림 aos - 백그라운드 ios - 알림 ios - 백그라운드
App - foreground        
App - background        
App - quit State        

 

앱의 각 상태별로, 그리고 OS별로

알림은 오는지, 백그라운드에서 수신은 되는지를 확인하는 것입니다.

 

모두 Ok라면 푸시는 완벽히 설정됐다고 볼 수 있습니다.

 

// index.js

import { Platform, Vibration, AppRegistry } from 'react-native';

messaging().setBackgroundMessageHandler(async remoteMessage => {
    onMessageReceived(remoteMessage);
});

function HeadlessCheck({ isHeadless }) {
  if (isHeadless) {
    <AppFake />;
  }
  
  return (
    <App />
  );
}

const AppFake = () => {
    return null;
};

const onMessageReceived = message => {
  console.log('background message: ', message);
  
  // 저는 ios에서 진동이 정확히 울리지 않는것으로 보여
  // background에서 알림이 수신될 경우 진동이 울리는 코드를 추가하였습니다.
  Platform.OS === 'ios' && Vibration.vibrate([400]);
}

AppRegistry.registerComponent(appName, () => HeadlessCheck);

 

 

 

[ 참고 ]

https://sweetdev.tistory.com/476

https://stackoverflow.com/questions/15834581/ios-push-notification-custom-format

https://firebase.google.com/docs/cloud-messaging/concept-options

https://firebase.google.com/docs/cloud-messaging/send-message#example-notification-message-with-platform-specific-delivery-options

https://mrgamza.tistory.com/837

https://hryang.tistory.com/34

728x90
반응형