# ReactNative 푸시메세지 설정

### 푸시알림 권한 확인 <a href="#reactnative_permission" id="reactnative_permission"></a>

사용자의 푸시알림 권한에 대한 확인을 거친 후 사용자의 푸시토큰을 수집 합니다.

아래의 예제는 사용자의 푸시알림 권한을 확인하는 방법으로 안드로이드의 경우 내장된 react-native PermissionAndroid를 사용하였으며, ios의 경우 React Native Firebase iOS permission API를 사용하였습니다. &#x20;

{% hint style="danger" %}
푸시알림 권한 확인 절차에 대한 예제일 뿐, <mark style="color:red;">**앱의 특성이나 상황에 따라 권한을 확인 및 요청하는 위치는 달라질 수 있습니다.**</mark>&#x20;

예제에서 사용한 권한 확인 방식은 다음과 같으며, 자세한 내용은 사용된 API의 도큐먼트를 확인 해 주세요.

* android : react-native PermissionAndroid API 사용
* ios의 경우 React Native Firebase iOS permission API 사용
  {% endhint %}

> ```
> iOS permission 요청시 확인되는 authorizationStatus 값.
> -1 = NOT_DETERMINED: 애플리케이션에 대한 권한이 아직 요청되지 않았습니다
> 0  = DENIED: 사용자가 알림 권한을 거부했습니다
> 1  = AUTHORIZED: 사용자가 권한을 수락했고 활성화되었습니다.
> 2  = PROVISIONAL: 임시 권한이 부여되었습니다.
> 3  = EPHEMERAL: 앱이 제한된 시간 동안 알림을 만들 수 있는 권한이 있습니다. 앱 클립에 사용됩니다.
> ```

{% tabs %}
{% tab title="Notification permission Check 예제" %}

```tsx
import messaging from '@react-native-firebase/messaging';
import {Platform, NativeModules, PermissionsAndroid} from 'react-native';

const Main = () => {
const firebaseMessaging = messaging();

 useEffect(() => {
    Platform.OS === 'android'
      ? androidRequestPermission()
      : iosRequestPermission();
  }, []);
  
  // ios 사용자에게 알림권한 요청
  const iosRequestPermission = async () => {
    try {
      const authorizationStatus = await messaging().requestPermission();
      // 알림 권한이 허용되면 authorizationStatus 값에 대한 안내는 상단에 작성되어 있습니다.
      // authorizationStatus 값이 AUTHORIZED 일 때, 
      if (authorizationStatus === 1) {
        const apnsToken = await firebaseMessaging.getAPNSToken();
        // APNs 토큰이 등록되어 있지 않으면 getToken() 함수가 실패합니다.
        // FCM토큰을 가져오기 전에 APNs 토큰이 등록되어있는지 먼저 확인합니다.
        if (apnsToken) {
          const fcmToken = await firebaseMessaging.getToken();
          // 와이즈트래커 SDK가 토큰을 수집합니다.
          NativeModules.DotReactBridge.setPushToken(fcmToken);
        }
      } else {
        console.log('알림권한 비 활성화:');
      }
    } catch (error) {
      console.log('ios error::', error);
    }
  };

  // Android 사용자에게 알림권한 요청
  const androidRequestPermission = async () => {
    const authorizationStatus = await messaging().requestPermission();
    console.log('authorizationStatus:', authorizationStatus);
    try {
      const fcmToken = await firebaseMessaging.getToken();
      if (Platform.OS === 'android') {
        console.log('get android FCM Token:', fcmToken);
        if (Platform.Version >= 33) {
          const granted = await PermissionsAndroid.request(
            PermissionsAndroid.PERMISSIONS.POST_NOTIFICATIONS,
            /*
             * 알림허용이 denied 일때, 알림 허용에 대한 재안내와 
             * 알림수신에 대한 요청을 다시 할 수 있는 내용 작성가능.
             * */
          );
          if (granted === PermissionsAndroid.RESULTS.GRANTED) {
            console.log('Android 13이상 , 알림권한 허용.');
            if (fcmToken) {
              //토큰 수집
              NativeModules.DotReactBridge.setPushToken(fcmToken);
            }
          }
        }
        // API 레벨 32 이하일 때
        try {
          if (fcmToken) {
            //토큰 수집
            NativeModules.DotReactBridge.setPushToken(fcmToken);
          }
        } catch (e) {
          console.log('android token API level 32 이하 error:', e);
        }
      }
    } catch (error) {
      console.log('Android error:', error);
    }
  };
...
}
```

{% endtab %}
{% endtabs %}

### Device Token 수집 <a href="#reactnative_get_token_" id="reactnative_get_token_"></a>

알림 권한 허용에 대한 확인 여부를 진행했다면, 사용자의 푸시토큰을 수집해야 합니다.

OS 모두 Firebase messaging 서비스를 기반으로 동작하기 때문에, **`getToken`** 호출을 통해 Token을 확인할 수 있습니다. 로그를 통해 수집된 token이 확인된다면, `setPushToken` 호출을 통해 와이즈트래커 SDK가 토큰을 수집할 수 있도록 코드를 추가 해 주세요.

{% tabs %}
{% tab title="푸시토큰 수집 예제" %}

<pre class="language-jsx"><code class="lang-jsx">import messaging from '@react-native-firebase/messaging';
import {Platform, NativeModules, PermissionsAndroid} from 'react-native';

const Main = () => {
const firebaseMessaging = messaging();

if (Platform.OS === 'android') {
  const fcmToken = await firebaseMessaging.getToken();
     // 와이즈트래커 SDK가 토큰을 수집합니다.
     NativeModules.DotReactBridge.setPushToken(fcmToken);
} else {
 // iOS의 경우 APNs 토큰이 등록되어 있지 않으면 getToken() 함수가 실패합니다.
 // FCM토큰을 가져오기 전에 APNs 토큰이 등록되어있는지 먼저 확인합니다.
<strong>  const apnsToken = await firebaseMessaging.getAPNSToken();
</strong>   if (apnsToken) {
      const fcmToken = await firebaseMessaging.getToken();
      // 와이즈트래커 SDK가 토큰을 수집합니다.
      NativeModules.DotReactBridge.setPushToken(fcmToken);
    }      
};
</code></pre>

{% endtab %}
{% endtabs %}

### 푸시메시지 클릭 측정 <a href="#rn_push_appstatus" id="rn_push_appstatus"></a>

앱의 상태는 총 3가지로 나눌 수 있습니다.&#x20;

* <mark style="color:red;">**Foreground**</mark> 상태 :  앱이 켜져있고, 앱을 사용하고 있는 상태 > 이벤트 핸들러의 `onMessage`를 이용해 핸들링 할 수 있습니다.
* <mark style="color:red;">**Background**</mark> : Background는 앱이 꺼져있거나, 홈버튼을 눌러 앱을 빠져나온 경우입니다 >  이벤트 핸들러의 `setBackgroundMessageHandler`를 이용할 수 있습니다.
* <mark style="color:red;">**Quit**</mark> :  Quit는 앱이 종료된 상태를 나타냅니다 > Background와 동일하게 이벤트 핸들러의 `setBackgroundMessageHandler`를 이용할 수 있습니다.

앱의 상태에 따라, 발송된 푸시메세지가 도착하여 <mark style="background-color:green;">유저가 메세지를 클릭하는 것을 측정</mark>하기 위해서 <mark style="color:red;">**앱에 진입하는 시점**</mark>에`"NativeModules.`<mark style="color:blue;">`DotReactBridge.setPushClick`</mark>`"` 을 호출하는 로직을 작성해야 합니다.

유의 해 주셔야 할점은 앱이 Foreground 상태일때 알림메시지 수신에 대한 구현 방식에 따라서, 유저가 Foreground 상태에서 알림을 받아 , 해당 알림을 클릭한 시점에 setPushClick을 호출해주셔야 한다는 점 입니다.&#x20;

만약 Foreground 상태일때 알림메세지에 대한 구현부가 없으나,  `NativeModules.DotReactBridge.setPushClick` 을 호출한다면, 아래의 이미지 처럼 유저가 알림을 클릭하지 않았음에도, 대시보드에서 다이렉트 오픈이 카운팅될 수 있습니다.&#x20;

<figure><img src="/files/ETCejFWxO4xz7q6G0OzE" alt=""><figcaption></figcaption></figure>

{% hint style="danger" %}
와이즈트래커 대시보드에서 푸시메세지 테스트 발송시와 Firebase 콘솔에서 푸시 메세지 테스트 발송시 확인되는 메세지에는 다른점이 있습니다. 와이즈트래커 대시보드에서 메시지 발송시에는<mark style="color:red;">`'RW_push_payload_WP'`</mark>객체 확인이 가능하나, Firebase 콘솔에서 메시지 발송 테스트 시에는  <mark style="color:red;">`RW_push_payload_WP`</mark> 객체정보는 확인되지 않습니다.&#x20;

(아래에서 예제 확인 해 주세요)

<mark style="color:red;">`'RW_push_payload_WP'`</mark> 객체가 들어있는 정보만 setPushClick을 통해 전달하며, JsonString의 parsing을 통해 Direct오픈 여부등을 체크하기에, 다음과 같이 대시보드에서 발송시에만 setPushClick함수가 호출될 수 있도록 제어 해 주세요.
{% endhint %}

<details>

<summary><mark style="color:blue;">와이즈트래커 대시보드 발송과 Firebase console 에서 발송되는 메시지 payload 비교</mark></summary>

```
1. 와이즈트래커 대시보드에서 메시지 전송시 수신되는 remoteMessage 원본:  
{
   "data":{
      "RW_push_payload_WP":
      "{\"RW_push_payload_CK\":\"0000\",\"RW_push_payload_SK\":\"00000000\",
         \"RW_push_payload_TT\":\"ios test\",\"RW_push_payload_EXPIRED\":\"1672498800000\",
         \"RW_push_payload_PR\":\"7\",\"RW_push_payload_BD\":\"ios test\"
      }"
   },
   "from":"0000000000000",
   "messageId":"0000000000000000",
   "notification":{
      "body":"ios test",
      "title":"ios test"
   }
}

2. firebase console 발송 테스트시 수신되는 remoteMessage 원본 : 
{
   "data":{},
   "from":"0000000000000",
   "messageId":"0000000000000000",
   "mutableContent":true,
   "notification":{
      "body":"fcm test",
      "title":"fcm test"
   },
   "sentTime":"0000000000"
}
```

</details>

앱 진입시점은 앱마다 다를 수 있으며 아래의 예제는 App.js 를 진입시점으로 예제가 작성되었습니다.

{% tabs %}
{% tab title="App.js(Function component)" %}

```tsx
import React, {useEffect} from 'react';
import messaging from '@react-native-firebase/messaging';
import {NativeModules} from 'react-native';

const App = () => {
  ...
  // 포그라운드 상태에서 FCM 메시지를 받았을 때
  useEffect(() => {
    const foregroundMessage = messaging().onMessage(async remoteMessage => {
      // 메시지를 처리하는 로직은 필요에따라 별도 구현 해 주세요.
      // 별도 구현 후 대시보드에서 유저가 알림을 클릭하여 캠페인 정보를 
      // 확인하고자 할때 DotReactBridge의 setPushClick함수를 호출합니다.
      if (JSON.stringify(remoteMessage).includes('RW_push_payload_WP')) {
        NativeModules.DotReactBridge.setPushClick(remoteMessage.data["RW_push_payload_WP"]);
      }
    });
    return foregroundMessage;
  }, []);
  
  useEffect(() => {
    //사용자가 FCM을 통해 표시된 알림을 누르면 앱이 백그라운드 상태에서 열린 경우 호출
    const backgroundMessage = messaging().onNotificationOpenedApp(
      remoteMessage => {
        // 메시지를 처리하는 로직은 필요에따라 별도 구현 해 주세요.
        // 와이즈트래커 SDK와 통신하여 푸시메세지 클릭을 처리.
        if (JSON.stringify(remoteMessage).includes('RW_push_payload_WP')) {
          // NativeModules.DotReactBridge.setPushClick(remoteMessage.data.RW_push_payload_WP);
          NativeModules.DotReactBridge.setPushClick(remoteMessage.data["RW_push_payload_WP"]);
        }
      },
    );

    /* Android의 경우 사용자가 FCM을 통해 표시된 알림을 앱이 종료된 상태에서 알림을 클릭한 경우
    앱이 처음 시작될 때 실행됩니다. 메시지가 없으면 null을 반환합니다.*/
    messaging()
      .getInitialNotification()
      .then(remoteMessage => {
        if (remoteMessage) {
          console.log('앱이 종료 상태에서 알림클릭으로 앱이 오픈되었을때:', remoteMessage);
          // 메시지를 처리하는 로직은 필요에따라 별도 구현 해 주세요.
          // 와이즈트래커 SDK와 통신하여 푸시메세지 클릭을 처리.
          if (JSON.stringify(remoteMessage).includes('RW_push_payload_WP')) {
            NativeModules.DotReactBridge.setPushClick(remoteMessage.data["RW_push_payload_WP"]);
          }
        }
      });
    return backgroundMessage;
  },[]);
  ...
  ...
};
```

{% endtab %}
{% endtabs %}

### 푸시 수신동의

푸시발송은 기본 적용에서는 "수신거부"입니다. 아래 링크를 참조하여 화면에서 수신동의/거부를 진행 후 해당 데이터를 "태깅"작업을 통해 남겨주세요.

{% embed url="<https://document.wisetracker.co.kr/v2-developer/in-app-event/event-list/messaging#push_noti_authorized>" %}

### 🎉 축하합니다!

ReactNative 앱의 푸시메세지 발송을 위한 모든 준비가 끝났습니다!&#x20;

푸시메세지 발송 테스트를 통해 메시지 수신이 잘 이루어지는지 체크 해 주세요!

{% embed url="<https://document.wisetracker.co.kr/marketing-action/marketing-message>" %}
푸시메세지 테스트 방법
{% endembed %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://document.wisetracker.co.kr/v2-developer/push/undefined/react-native/push_message.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
