> For the complete documentation index, see [llms.txt](https://docs.dfinery.ai/developer-guide/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.dfinery.ai/developer-guide/platform/reactnative/action/push-notification.md).

# 푸시

이 문서는 React Native에 대한 푸시 알림을 설정하는 방법을 다룹니다. 푸시 알림을 통합하려면 각 기본 플랫폼을 별도로 설정해야합니다. 나열된 각 안내서를 따라 설치를 완료하십시오.

## 1. 플랫폼 별 초기 설정 <a href="#platform-setup" id="platform-setup"></a>

{% tabs %}
{% tab title="Android" %}

#### Android 프로젝트에 Firebase 추가하기

Firebase에서 제공되는 [Android 프로젝트에 Firebase 추가](https://firebase.google.com/docs/android/setup) 의 지시사항에 따라 Android 프로젝트에 Firebase를 추가합니다.

{% hint style="info" %}
가이드 완료시 확인해야 할것

* [google-services.json](https://support.google.com/firebase/answer/7015592) 파일이 앱에 추가되어 있는지 확인
* 앱 레벨의 `build.gradle`에 `com.google.gms.google-services` 플러그인이 추가되어 있는지 확인
  {% endhint %}

#### Dfinery Console에서 Firebase 정보 등록하기

Console에서 [부가설정/채널 부가 설정/푸시/Android 설정관리](https://console.dfinery.ai)에 들어가 발신자 ID를 입력하고 JSON 형식의 Firebase 사용자 인증 정보 비공개 키 파일을 업로드합니다.

#### 발신자 ID 확인 방법

1. [**Firebase Console**](https://console.firebase.google.com/)로 이동합니다.
2. 프로젝트를 선택합니다.
3. 좌측 패널에서 프로젝트 개요 오른쪽에 ⚙️ 아이콘을 클릭합니다.
4. 프로젝트 설정을 클릭합니다.
5. 프로젝트 설정 상단 탭에서 클라우드 메시징을 클릭합니다.
6. [**발신자 ID**](https://firebase.google.com/docs/cloud-messaging/concept-options?hl=ko#senderid)를 확인합니다.

#### Firebase 사용자 인증 정보 비공개 키 파일 발급 방법

Firebase에서 제공하는 [수동으로 사용자 인증 정보 제공](https://firebase.google.com/docs/cloud-messaging/auth-server?hl=ko#provide-credentials-manually)을 참고하여 JSON 형식으로 키를 저장한다음 Console에 파일을 업로드 해주세요.

해당 페이지에서 확인할 수 있는 주요 내용은 다음과 같습니다.

1. [Firebase Console](https://console.firebase.google.com/)에서 설정 > [서비스 계정](https://console.cloud.google.com/iam-admin/)을 엽니다.
2. 새 비공개 키 생성을 클릭한 다음 키 생성을 클릭하여 확인합니다.
3. 키가 들어 있는 JSON 파일을 안전하게 저장합니다.

만약 비공개 키 파일 발급에 어려움을 겪으실 경우 [Firebase 사용자 인증 정보 비공개 키 파일 발급 따라해보기](https://github.com/IGAWorksDev/dfn-v2-gitbook-sync/tree/main/dev_guide_ko/platform/reactnative/action/push_notification.md#firebase-사용자-인증-정보-비공개-키-파일-발급-따라해보기)를 참고하여 주시기 바랍니다.

#### 앱 매니페스트에 FirebaseMessagingService를 상속받는 서비스 추가

```xml
<application>
    ...
    <service
        android:name="com.igaworks.dfinery.DfineryFirebaseMessagingService"
        android:exported="false">
        <intent-filter>
            <action android:name="com.google.firebase.MESSAGING_EVENT" />
        </intent-filter>
    </service>
</application>
```

#### 앱 매니페스트에 `POST_NOTIFICATIONS` 권한 추가하기

Android 13이상의 기기일 경우 `POST_NOTIFICATIONS` 권한이 필요합니다. `AndroidManifest.xml`에 해당 권한을 추가해주시기 바랍니다.

```xml
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
```

다음은 작성이 완료된 `AndroidManifest.xml` 예시입니다.

```xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.dfineryreactnativesdkexample">

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
    <uses-permission android:name="com.google.android.gms.permission.AD_ID"/>

    <application
      android:name=".MainApplication"
      android:label="@string/app_name"
      android:icon="@mipmap/ic_launcher"
      android:roundIcon="@mipmap/ic_launcher_round"
      android:allowBackup="false"
      android:theme="@style/AppTheme">
      <activity
        android:name=".MainActivity"
        android:label="@string/app_name"
        android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode"
        android:launchMode="singleTask"
        android:windowSoftInputMode="adjustResize"
        android:exported="true">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
      </activity>
      <service
        android:name="com.igaworks.dfinery.DfineryFirebaseMessagingService"
        android:exported="false">
        <intent-filter>
            <action android:name="com.google.firebase.MESSAGING_EVENT" />
        </intent-filter>
      </service>
    </application>
</manifest>
```

### 푸시 알림 채널을 Dfinery에 연동하기

#### 푸시 알림 채널 생성

Android 8.0부터는 알림을 수신받기 위해 알림 채널 생성이 필요합니다. `createNotificationChannel()` 메소드를 사용하여 알림 채널을 생성할 수 있습니다.

{% hint style="info" %}
알림 채널 API는 [Android 8.0](https://developer.android.com/about/versions/oreo?hl=ko)이상에서 지원하며 그 미만 기기에서는 아무런 동작을 하지 않습니다.
{% endhint %}

```javascript
const properties = {
    [DFAndroidNotificationChannelProperty.ID]: 'dfinery_channel',
    [DFAndroidNotificationChannelProperty.NAME]: 'Default Notification Channel',
    [DFAndroidNotificationChannelProperty.IMPORTANCE]: DFAndroidNotificationChannelImportance.HIGH,
    [DFAndroidNotificationChannelProperty.BADGE]: true,
    [DFAndroidNotificationChannelProperty.SOUND]: true,
    [DFAndroidNotificationChannelProperty.VISIBILITY]: DFAndroidNotificationChannelVisibility.PUBLIC,
    [DFAndroidNotificationChannelProperty.VIBRATION]: true
  };
Dfinery.createNotificationChannel(properties);
```

<details>

<summary>createNotificationChannel() 정보</summary>

| 값                                                | 설명                                                                                                                                                                                  | 타입      |
| ------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- |
| DFAndroidNotificationChannelProperty.ID          | [알림 채널의 ID](https://developer.android.com/reference/android/app/NotificationChannel#NotificationChannel\(java.lang.String,%20java.lang.CharSequence,%20int\))                       | String  |
| DFAndroidNotificationChannelProperty.NAME        | [알림 채널의 이름](https://developer.android.com/reference/android/app/NotificationChannel#setName\(java.lang.CharSequence\))                                                              | String  |
| DFAndroidNotificationChannelProperty.DESCRIPTION | [알림 채널의 설명](https://developer.android.com/reference/android/app/NotificationChannel#setDescription\(java.lang.String\))                                                             | String  |
| DFAndroidNotificationChannelProperty.BADGE       | [알림 채널의 뱃지 표시 유무](https://developer.android.com/reference/android/app/NotificationChannel#setShowBadge\(boolean\))                                                                  | Boolean |
| DFAndroidNotificationChannelProperty.SOUND       | [알림 채널의 알림음 재생 유무](https://developer.android.com/reference/android/app/NotificationChannel#setSound\(android.net.Uri,%20android.media.AudioAttributes\))                            | Boolean |
| DFAndroidNotificationChannelProperty.SOUND\_URI  | [알림 채널의 알림음 URI](https://developer.android.com/reference/android/app/NotificationChannel#setSound\(android.net.Uri,%20android.media.AudioAttributes\)), 알림음 파일은 `res/raw`에 위치해야 합니다 | String  |
| DFAndroidNotificationChannelProperty.IMPORTANCE  | [알림 채널의 중요도](https://developer.android.com/reference/android/app/NotificationChannel#setImportance\(int\))                                                                          | Integer |
| DFAndroidNotificationChannelProperty.LIGHTS      | [알림 채널의 표시등 표시 여부](https://developer.android.com/reference/android/app/NotificationChannel#enableLights\(boolean\))                                                                 | Boolean |
| DFAndroidNotificationChannelProperty.VIBRATION   | [알림 채널의 진동 여부](https://developer.android.com/reference/android/app/NotificationChannel#enableVibration\(boolean\))                                                                  | Boolean |
| DFAndroidNotificationChannelProperty.VISIBILITY  | [알림 채널의 잠금 채널 표시 유무](https://developer.android.com/reference/android/app/NotificationChannel#setLockscreenVisibility\(int\))                                                        | Boolean |
| DFAndroidNotificationChannelProperty.BYPASS\_DND | [알림 채널의 방해금지 시 노출 여부](https://developer.android.com/reference/android/app/NotificationChannel#setBypassDnd\(boolean\))                                                              | Boolean |
| DFAndroidNotificationChannelProperty.GROUP\_ID   | [알림 채널의 알림 채널 그룹 ID](https://developer.android.com/reference/android/app/NotificationChannel#setGroup\(java.lang.String\))                                                          | String  |

</details>

#### 생성한 푸시 알림 채널 ID 등록

Dfinery 초기화시 `initWithConfig()`메소드를 사용하여 사용하여 생성한 알림 채널의 ID를 등록합니다.

```javascript
import React, { useEffect } from "react";
import Dfinery from 'dfinery-react-native-sdk';

const App = () => {
  useEffect(() => {
    const config = {
      [DFConfig.ANDROID_NOTIFICATION_CHANNEL_ID]: 'dfinery_channel'
    };
    Dfinery.initWithConfig("{YOUR_SERVICE_ID}", config);
  }, []);

  return (
    <div>
      ...
    </div>
  )
```

#### 푸시 알림 채널 그룹 생성 (선택사항)

Andorid 알림 채널에는 선택적으로 알림 채널 그룹을 설정할 수 있습니다.

{% hint style="info" %}
알림 채널 그룹 API는 [Android 8.0](https://developer.android.com/about/versions/oreo?hl=ko)이상에서 지원하며 그 미만 기기에서는 아무런 동작을 하지 않습니다.
{% endhint %}

```javascript
//알림 채널 그룹 생성
const notificationChannelGroupProperties = {
    [DFAndroidNotificationChannelGroupProperty.ID] : 'dfinery_channel_group',
    [DFAndroidNotificationChannelGroupProperty.NAME] : 'Default Notification Channel Group'
  };
Dfinery.createNotificationChannelGroup(notificationChannelGroupProperties);
//알림 채널에 그룹 할당
const notificationChannelProperties = {
    [DFAndroidNotificationChannelProperty.ID]: 'dfinery_channel',
    [DFAndroidNotificationChannelProperty.GROUP_ID]: 'dfinery_channel_group'
  };
Dfinery.createNotificationChannel(notificationChannelProperties);
```

<details>

<summary>createNotificationChannelGroup() 정보</summary>

| 값                                              | 설명                                                                                                                                                                  | 타입     |
| ---------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------ |
| DFAndroidNotificationChannelGroupProperty.ID   | [알림 채널 그룹의 ID](https://developer.android.com/reference/android/app/NotificationChannelGroup#NotificationChannelGroup\(java.lang.String,%20java.lang.CharSequence\)) | String |
| DFAndroidNotificationChannelGroupProperty.NAME | [알림 채널 그룹의 이름](https://developer.android.com/reference/android/app/NotificationChannelGroup#NotificationChannelGroup\(java.lang.String,%20java.lang.CharSequence\)) | String |

</details>

#### 푸시 알림 아이콘 설정하기

Android에서 푸시 알림을 표시하기 위해서는 아이콘 설정이 필요합니다. init시 config를 설정할때 아이콘 Drawable의 이름을 입력하여 설정합니다.

{% hint style="info" %}
알림 아이콘은 시스템이 색조(tint)를 적용할 수 있으므로, 투명한 배경을 사용하는 것이 좋습니다.
{% endhint %}

{% hint style="warning" %}
아이콘 설정은 drawable 만을 지원합니다. mipmap은 지원하지 않습니다.
{% endhint %}

```javascript
import React, { useEffect } from "react";
import Dfinery from 'dfinery-react-native-sdk';

const App = () => {
  useEffect(() => {
    const config = {
      [DFConfig.ANDROID_NOTIFICATION_ICON_NAME]: 'ic_dfinery',
    };
    Dfinery.initWithConfig("{YOUR_SERVICE_ID}", config);
  }, []);

  return (
    <div>
      ...
    </div>
  )
```

## 푸시 알림 강조색 지정하기 <a href="#push_accent_color" id="push_accent_color"></a>

알림 아이콘 강조색은 init시 config에 색상의 hexString 값을 입력하여 적용할 수 있습니다. 색상을 지정하지 않으면 시스템 기본 색상으로 표시됩니다.

{% hint style="info" %}

* 푸시 알림 강조색은 사용 중인 OS 버전과 런처에 따라 다르게 표시될 수 있습니다.
* 값은 Hex color codes 형태로 입력해야 합니다.
  {% endhint %}

```javascript
import React, { useEffect } from "react";
import Dfinery from 'dfinery-react-native-sdk';

const App = () => {
  useEffect(() => {
    const config = {
      [DFConfig.ANDROID_NOTIFICATION_ACCENT_COLOR]: '#E00052',
    };
    Dfinery.initWithConfig("{YOUR_SERVICE_ID}", config);
  }, []);

  return (
    <div>
      ...
    </div>
  )
```

{% endtab %}

{% tab title="iOS" %}

#### Dfinery Console에 APNs 인증키 등록

푸시메시지를 사용하기 위해 Apple로부터 발급받은 .p8 APNs 인증키를 [DFINERY 콘솔](https://console.dfinery.ai/)에 등록해주세요. 콘솔의 부가 설정 / 채널 부가 설정 / 푸시 / iOS 설정 관리에서 등록할 수 있습니다.

#### Capabilities 설정

아래 스크린샷과 같이 PushNotification, Background Modes/Remote Notifications에 대한 Capabilities를 추가해 주세요.

![Capabilities설정](/files/6t9hqleUUWB3DvPsSqOT)

#### Notification Service Extension 추가

아래 스크린샷과 같이 Notification Service Extension을 추가해주세요

![ServiceExtension추가](/files/bVGEJBNSsWKDNsmCZ5sz)

![ServiceExtension추가](/files/0lO6byMxKeR4UYMWwajt)

![donotactivate](/files/5XJXR57iSwRqvTyomwsm)

{% hint style="info" %}
ServiceExtension 타겟의 Minimum Deployments 설정을 한번 더 확인해 주세요.
{% endhint %}

#### cocoapods 연동

ios 디렉토리 내 podfile에 추가한 NotificationServiceExtension에 대한 타겟과 디파이너리 의존성을 추가합니다.

```ruby
target 'NotificationServiceExtension' do
  pod 'DfinerySDKServiceExtension'
end
```

이후 pod install을 통해 SDK를 설치합니다.

#### iOS 네이티브 코드 수정

생성한 Notification Service Extension 프로젝트 내에 DfinerySDKServiceExtension을 import 후 코드를 수정합니다.

**Swift**

```swift
import UserNotifications
import DfinerySDKServiceExtension

class NotificationService: UNNotificationServiceExtension {

    var contentHandler: ((UNNotificationContent) -> Void)?
    var bestAttemptContent: UNMutableNotificationContent?

    override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
        self.contentHandler = contentHandler
        bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
        
        if let bestAttemptContent = bestAttemptContent {
            
            if DfineryServiceExtension.canHandle(content: bestAttemptContent, contentHandler: contentHandler) {
                return
            }
            
            contentHandler(bestAttemptContent)
        }
    }
    // ...
}
```

**Objective-C**

```objective-c
#import "NotificationService.h"
#import <DfinerySDKServiceExtension/DfinerySDKServiceExtension.h>

// ...

- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler {
    self.contentHandler = contentHandler;
    self.bestAttemptContent = [request.content mutableCopy];
    
    if (self.bestAttemptContent) {
        if ([DfineryServiceExtension canHandleWithContent:self.bestAttemptContent contentHandler:contentHandler]) {
            return;
        }
        
        self.contentHandler(self.bestAttemptContent);
    }
}
// ...
```

{% endtab %}
{% endtabs %}

## 2. 런타임 알림 권한 요청하기 <a href="#request-permission" id="request-permission"></a>

[react-native-permissions](https://github.com/zoontek/react-native-permissions) 패키지를 활용한 푸시 알림 권한 요청 예시입니다.

```javascript
    requestNotifications(['alert', 'sound', 'badge']).then(({status, settings}) => {
      if (status === 'granted') {
        Dfinery.getPushToken().then((token)=>{
          Dfinery.setPushToken(token);
        });
      } 
    }).catch((error) => {
      console.error('Notification permission error:', error);
    });

```

## 3. 토큰을 Dfinery에 연동하기 <a href="#register-token" id="register-token"></a>

Firebase/APNS에서 발급된 토큰을 Dfinery에 연동하기 위해서 다음과 같이 작성해주시기 바랍니다.

아래는 가장 최근에 발급받은 푸시 토큰을 가져오고 Dfinery에 연동하는 예제입니다.

{% hint style="info" %}
`Dfinery.getPushToken()`은 [Firebase Messaging](https://mvnrepository.com/artifact/com.google.firebase/firebase-messaging) API를 사용하여 푸시 토큰을 가져옵니다. 다른 방법으로 푸시 토큰을 가져와 설정하셔도 무관합니다.
{% endhint %}

```javascript
import React, { useEffect } from "react";
import Dfinery from '@igaworks/dfinery-react-native-sdk';

const App = () => {
  useEffect(() => {
    Dfinery.getPushToken().then((token)=>{
        Dfinery.setPushToken(token);
    });
  }, []);

  return (
    <div>
      ...
    </div>
  )
}
```

## 4. 푸시 클릭시 호출되는 딥링크 연동하기 <a href="#deeplink-setup" id="deeplink-setup"></a>

{% tabs %}
{% tab title="Android" %}
[앱 콘텐츠 딥 링크 만들기](https://developer.android.com/training/app-links/deep-linking)에 따라 딥링크 설정을 해주세요.

```xml
<activity
    android:name=".MainActivity"
    android:exported="true"
    android:launchMode="singleTop"
    android:theme="@style/LaunchTheme">
    
    <!-- 기존 intent-filter -->
    <intent-filter android:autoVerify="true">
        <action android:name="android.intent.action.MAIN"/>
        <category android:name="android.intent.category.LAUNCHER"/>
    </intent-filter>
    
    <!-- 딥링크를 위한 intent-filter -->
    <intent-filter android:autoVerify="true">
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data android:scheme="yourapp" />
    </intent-filter>
</activity>
```

{% endtab %}

{% tab title="iOS" %}
[Apple의 가이드](https://developer.apple.com/documentation/xcode/defining-a-custom-url-scheme-for-your-app) 대로 딥링크 스킴을 설정 후

AppDelegate 클래스에 다음과 같이 메소드를 추가해주세요

{% tabs %}
{% tab title="Swift" %}

```swift
  func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
    return RCTLinkingManager.application(app, open: url, options: options)
  }
```

{% endtab %}

{% tab title="Objective-C" %}

```objective-c

- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options
{
  return [RCTLinkingManager application:app openURL:url options:options];
}
...
```

{% endtab %}
{% endtabs %}
{% endtab %}
{% endtabs %}

## 5. 푸시 알림 수신 허용 유무 반영하기 <a href="#consent-settings" id="consent-settings"></a>

광고성 목적이 있는 푸시의 경우 [정보통신망법](https://www.law.go.kr/%EB%B2%95%EB%A0%B9/%EC%A0%95%EB%B3%B4%ED%86%B5%EC%8B%A0%EB%A7%9D%20%EC%9D%B4%EC%9A%A9%EC%B4%89%EC%A7%84%20%EB%B0%8F%20%EC%A0%95%EB%B3%B4%EB%B3%B4%ED%98%B8%20%EB%93%B1%EC%97%90%20%EA%B4%80%ED%95%9C%20%EB%B2%95%EB%A5%A0/%EC%A0%9C50%EC%A1%B0) 에 따라 사용자에게 사전 수신동의를 받아야 합니다. 사용자에게 푸시 알림이 허용되었다는 정보를 Dfinery에 반영하기 위해서 다음의 일련의 작업을 수행하여 주시기 바랍니다.

1. 사용자에게 푸시 알림 허용에 대한 고지하기
2. 사용자의 허용/거부 의사에 대한 값을 반영하기 위해 다음의 코드를 작성

[알림 수신 동의 설정하기](https://github.com/IGAWorksDev/dfn-v2-gitbook-sync/tree/main/dev_guide_ko/platform/reactnative/action/user_profile.md#알림-수신-동의-정보-설정하기)를 참고하여 사용자가 동의한 항목에 대해 값을 입력해주시기 바랍니다. 아래 코드는 광고성 수신 동의를 허용한 예시입니다.

```javascript
const param = {
    [DFUserProfile.PUSH_ADS_OPTIN]: true
};
Dfinery.setUserProfiles(param);
```

## 6. 완료 <a href="#complete" id="complete"></a>

이제 Dfinery에서 알림을 사용하기 위한 모든 준비가 완료되었습니다.
