# iOS 기초 설정

## APNS 인증서 발급

{% embed url="<https://document.wisetracker.co.kr/v/v2-developer/push/ios/apns_setting>" %}

## Firebase 연동

다음 [<mark style="color:blue;">Firebase console</mark>](https://console.firebase.google.com/)에서 프로젝트 개요 오른쪽의 setting 아이콘을 클릭하여 **프로젝트 설정**으로 들어갑니다.

**클라우드 메시징** 메뉴를 클릭하여 다음과 같이 발급받은 APN 인증 (.p8) 키를 업로드 합니다.

{% hint style="danger" %}
Firebase console 클라우드메시징 설정 화면에서 APNS Authentication Key (APN 인증키), APNS Certificates(APN인증서) 업로드 2가지 설정을 확인할 수 있습니다.

여기에 Apple 에서 발급받은 Key 또는 Certificates를 넣어야만 원격 푸시가 정상적으로 작동하며, 둘 중 하나만 업로드 하여도 됩니다.

* APNS Key :  .p8 형태를 띄고 하나만 업로드.
* APNS Certificates : .p12 형태를 띄고 개발용, 배포용 인증서가 따로 존재. 일년마다 갱신 필요.

\*와이즈트래커 도큐먼트는 .p8 업로드를 기준으로 작성되었습니다.
{% endhint %}

<figure><img src="https://423922975-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M_ZKcnBFmefw9Yfed6b-3102695190%2Fuploads%2FWAuOcY7shohUhx983trC%2Fimage.png?alt=media&#x26;token=c5a7c933-d29f-4ab8-8af5-2496f83304cc" alt=""><figcaption></figcaption></figure>

그리고 Firebase 구성 파일도 Xcode 루트에 복사합니다.

<figure><img src="https://423922975-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M_ZKcnBFmefw9Yfed6b-3102695190%2Fuploads%2FNZTikDjeFDGmbbY08DKu%2Fimage.png?alt=media&#x26;token=68079aa3-03c1-45ce-a9d1-e9bfbbd046da" alt=""><figcaption></figcaption></figure>

<figure><img src="https://423922975-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M_ZKcnBFmefw9Yfed6b-3102695190%2Fuploads%2FYR1b7qVTVAKRLDph6Dym%2Fimage.png?alt=media&#x26;token=60e07966-5a1d-4019-a806-2e64afa3d03b" alt=""><figcaption></figcaption></figure>

## 대시보드 설정 <a href="#reactnative_dashboard_setting" id="reactnative_dashboard_setting"></a>

[<mark style="color:blue;">와이즈트래커 대시보드</mark>](https://analytics.wisetracker.co.kr/)에서 푸시 연동을 위한 설정을 진행합니다.&#x20;

서비스설정 > 어플리케이션설정 > **푸시연동** 메뉴를 클릭합니다.

아래 이미지에서 푸시 서비스 타입을 <mark style="color:red;">**Firebase Cloud Messaging**</mark> 으로 선택 후 Android 푸시 연동시 추가한 Firebase Admin SDK용 "<mark style="color:red;">**private key**</mark>" 파일을 추가 해 주세요.

<figure><img src="https://423922975-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M_ZKcnBFmefw9Yfed6b-3102695190%2Fuploads%2FzfyOcCBGUKPo1Lpu6RvP%2Fimage.png?alt=media&#x26;token=bbffd442-10f2-4bf4-a5fb-d05d086b9584" alt=""><figcaption></figcaption></figure>

## SDK 설치

### Cocoapod에서 SDK 다운로드

{% hint style="info" %}
Swift로 FCM을 사용할때는, 'pod' 파일을 수정할 필요는 없습니다.
{% endhint %}

XCode 프로젝트 파일중 `Podfile` 파일에 다음과 같이 SDK와 FirebaseMessaging을 추가합니다.

```
pod 'RW'
pod 'Firebase/Messaging'    >>> Objective-C 의 경우 추가 해 주세요.
```

기존에 SDK를 한번 설치한 경우에는 설치할SDK 버전을 표시해야 하는 경우도 있습니다. 아래와 같이 설치할 SDK버전을 명시적으로 표시하면 됩니다.

```
pod 'RW', '~> 1.1.57'
```

#### **`Terminal`**

`Podfile` 에 해당라인을 추가한 후 Terminal 프로그램을 실행하여 다음의 명령을 수행합니다.

```
pod install
```

SDK 버전 업데이트의 경우 다음의 명령을 수행합니다.

```
pod update
```

### Cocoapod 사용하지 않을 경우

SDK 파일을 [<mark style="color:blue;">**URL**</mark>](https://github.com/WisetrackerTechteam/RW-iOS-SDK)에서 다운로드 합니다.

다운된 파일을 압축 해제하면 다음과 같은 파일이 확인 가능하고 이중 아래에 선택된 3개의 파일을 분석 대상 앱 프로젝트에 추가합니다.

![](https://423922975-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M_ZKcnBFmefw9Yfed6b-3102695190%2Fuploads%2Fpk3AbexS18KRNF1PTHG8%2Fimage.png?alt=media\&token=7272a544-3333-48cd-8244-b266971cb094)

프로젝트 선택후 마우스 우클릭, Add Files to 메뉴를 선택합니다.

![](https://423922975-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M_ZKcnBFmefw9Yfed6b-3102695190%2Fuploads%2FM0jnJbDePvo8eBND9Hey%2Fimage.png?alt=media\&token=2e33c0b8-e040-4cd8-813b-f901788bed15)

앞에서 다운로드 받고, 압축 해제한 폴더에 들어가서 아래와 같이 추가 대상 파일을 선택하고, 화면 아래쪽 설정은 존재하는 모든 target에 포함되었는지 확인후 추가 하면 됩니다.

![](https://423922975-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M_ZKcnBFmefw9Yfed6b-3102695190%2Fuploads%2FvAVAojnTWxd7d8xbAasi%2Fimage.png?alt=media\&token=94d8ffb8-a830-44ec-b2ad-afe495884e72)

BuildSetting 에 아래와 같이 설정을 추가합니다.

<figure><img src="https://423922975-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M_ZKcnBFmefw9Yfed6b-3102695190%2Fuploads%2FHv8zVhSKkDJeHQEX8P3p%2Fimage.png?alt=media&#x26;token=a4c240c5-a8be-4bfe-92f2-7c51ae3cbca3" alt=""><figcaption></figcaption></figure>

xcode 가 12.3 이후 버전이고 빌드 과정에서 아래와 유사한 오류가 발생하는 경우가 있으며,

![](https://423922975-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M_ZKcnBFmefw9Yfed6b-3102695190%2Fuploads%2FYKj0m0uWm8i3OdigjmKX%2Fimage.png?alt=media\&token=a0bec7b2-e1ec-45f1-8a13-05ca77982e61)

위의 경우에는 아래와 같이 설정을 하고, 빌드를 하면됩니다.

![](https://423922975-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M_ZKcnBFmefw9Yfed6b-3102695190%2Fuploads%2Fhh7wsdUjki6IzgLEcsss%2Fimage.png?alt=media\&token=fcb545d5-45d6-4e14-a5f8-63098e237774)

CocoaPod을 사용하지 않을경우, Firebase 수동 설정은 아래의 Firebase 공식 document를 참고하여 수동으로 프로젝트에 추가해 주세요.

{% embed url="<https://firebase.google.com/docs/ios/setup?hl=ko#objective-c_1>" %}

### dotAuthorizationKey 등록

info.plist 파일을 **Open As Source Code** 방식으로 오픈한 후, 아래 코드를 추가합니다.

{% tabs %}
{% tab title="info.plist" %}

```xml
<key>dotAuthorizationKey</key>
<dict>
    <key>serviceNumber</key>
    <string>xxxxx</string>          >>> 서비스 번호 확인 후 변경
    <key>expireDate</key>
    <string>14</string>
    <key>isDebug</key>
    <string>true</string>
    <key>isInstallRetention</key>
    <string>true</string>
    <key>isFingerPrint</key>
    <string>true</string>
    <key>accessToken</key>
    <string></string>
    <key>useMode</key>
    <string>2</string>
</dict>
```

{% endtab %}
{% endtabs %}

추가한 코드 중 `serviceNumber`의 value를 올바른 값으로 변경해야 합니다.&#x20;

[<mark style="color:blue;">와이즈트래커 대시보드</mark>](https://analytics.wisetracker.co.kr/)에 로그인하여 설정 > 서비스설정 메뉴에서 '<mark style="color:red;">`서비스번호`</mark>' 항목에 기재된 숫자를 확인 후 복사하여 serviceNumber 값을 변경 해 주세요.

<figure><img src="https://423922975-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M_ZKcnBFmefw9Yfed6b-3102695190%2Fuploads%2F4lZPrtqvB8VgaU67G3vP%2Fimage.png?alt=media&#x26;token=1e8f5e42-e8bc-4725-bf46-5243bdad751c" alt=""><figcaption><p>서비스번호 확인</p></figcaption></figure>

### HTTP 통신 허용

{% hint style="warning" %}
이 내용은 Wisetracker 기본 SDK가 이미 적용된 경우에는 새로 적용할\
필요가 없습니다. 메시징 서비스만 이용하는 경우 참조해주세요.&#x20;
{% endhint %}

http통신을 허용하기 위해 NSAppTransportSecurity 를 아래와 같이 추가합니다.

이전과 마찬가지로 info.plist 파일을 **Open As Source Code** 방식으로 오픈한 후, 아래 코드를 추가합니다.

```markup
<key>NSAppTransportSecurity</key>
<dict>
    <key>NSAllowsArbitraryLoads</key>
    <true/>
</dict>
```

### **"Push Notification" Capability 추가**

앱에 푸시기능을 추가합니다.

"Signing & Capabilities" 탭을 선택한 후 화면 왼쪽의 "+ Capability"를 눌러주세요.

<figure><img src="https://423922975-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M_ZKcnBFmefw9Yfed6b-3102695190%2Fuploads%2FUF5du7toz3yht1JvHiKK%2Fimage.png?alt=media&#x26;token=c72810b7-83f3-4dc6-973a-46498cb14f21" alt=""><figcaption></figcaption></figure>

"Capability"화면에서 "Push Notification"기능을 검색하여 선택합니다.

<figure><img src="https://423922975-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M_ZKcnBFmefw9Yfed6b-3102695190%2Fuploads%2FLnzOOy6RpcViu7EDUqIm%2Fimage.png?alt=media&#x26;token=87446e0e-8077-4f9d-ae29-15238ee8e61b" alt=""><figcaption></figcaption></figure>

Background Modes도 위와 같은 방법으로 검색 후 추가 해 줍니다.&#x20;

<figure><img src="https://423922975-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M_ZKcnBFmefw9Yfed6b-3102695190%2Fuploads%2F9Gw0izBY9sTc5wR7VF0p%2Fimage.png?alt=media&#x26;token=857556db-4760-4492-b98d-78ce8fe293e6" alt=""><figcaption></figcaption></figure>

### 초기화

* 초기화 방법은 SceneDelegate 가 설정된 경우와 설정되지 않은 경우에 따라 달라집니다.
* SceneDelegate를 사용하지 않으면 AppDelegate에서 초기화작업을 하고, 그렇지 않고 SceneDelegate를 사용하면 SceneDelegate에서 이 작업을 해야 합니다.

#### 1. iOS13 미만 (`SceneDelegate` 없음)

AppDelegate의 `didFinishLaunchingWithOptions` 함수에 SDK를 Initialization하기 위한 코드를 다음과 같이 적용합니다. SDK가 정상적으로 초기화 되었을 때 아래와 같은 기본 분석이 가능합니다.

* 앱 실행 및 방문수, 일/주/월순수방문수 등 방문과 관련된 지표
* 통신사, 단말기, 국가 등 방문자의 단말기 환경으로 부터 추출될 수 있는 지표

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

```swift
import DOT
import Firebase

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
...
...
  // 등록 토큰을 수신하기 위한 SDK구성
  FirebaseApp.configure()
  
  // S: Wisetracker SDK init
  DOT.initialization(launchOptions, application: application)
  #if DEBUG
    DOT.checkDebugMode(true)
  #else
    DOT.checkDebugMode(false)
  #endif
  // E: Wisetracker SDK init
}
```

{% endtab %}

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

```objectivec
#import <DOT/DOT.h>
#import <Firebase.h>
...
...
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
 
  // 등록 토큰을 수신하기 위한 SDK구성
  [FIRApp configure];
  
    // S: Wisetracker SDK init
  [DOT initialization:launchOptions application:application];
  #ifdef DEBUG
    [DOT checkDebugMode:true]
  #else
    [DOT checkDebugMode:false]
  #endif
  // E: Wisetracker SDK init
}
```

{% endtab %}
{% endtabs %}

DOT가 사용되는 곳에서는 `import DOT`을 통해 import가 필요합니다.

#### 2. iOS13 이상 (`SceneDelegate` 사용)

#### 👉 iOS13 이상이어도 SceneDelegate를 사용하지 않을 수도 있어요, 이  때에는 위의 SceneDelegate를 사용하지 않는 경우를 참조하세요.

`SceneDelegate`의 `sceneDidBecomeActive`함수에 SDK를 Initialization하기 위한 코드를 다음과 같이 적용합니다. SDK가 정상적으로 초기화 되었을 때 아래와 같은 기본 분석이 가능합니다.

* 앱 실행 및 방문수, 일/주/월순수방문수 등 방문과 관련된 지표
* 통신사, 단말기, 국가 등 방문자의 단말기 환경으로 부터 추출될 수 있는 지표

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

```swift
import DOT
import Firebase

class SceneDelegate: UIResponder, UIWindowSceneDelegate {
...
  func sceneDidBecomeActive(_ scene: UIScene) {
  
    // 등록 토큰을 수신하기 위한 SDK구성
    FirebaseApp.configure()
  
    // =======================================================
    // Wisetracker 기본 SDK가 이미 적용된 경우에는 새로 적용할 필요가 없습니다.
    // 메시징 서비스만 이용하는 경우 참조해주세요.
    // =======================================================
    // Start : Wisetracker SDK 호출
    DOT.initialization(nil, application: UIApplication.shared)
    #if DEBUG
      DOT.checkDebugMode(true)
    #else
      DOT.checkDebugMode(false)
    #endif
    // E: Wisetracker SDK init
  }
...
}
```

{% endtab %}

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

```objectivec
#import <DOT/DOT.h>
#import <Firebase.h>

@implementation SceneDelegate
...
- (void)sceneDidBecomeActive:(UIScene *)scene {
...
...
  // 등록 토큰을 수신하기 위한 SDK구성
  [FIRApp configure];
  
  // =======================================================
  // Wisetracker 기본 SDK가 이미 적용된 경우에는 새로 적용할 필요가 없습니다.
  // 메시징 서비스만 이용하는 경우 참조해주세요.
  // =======================================================
  // Start : Wisetracker SDK 호출
  [DOT initialization:nil application:[UIApplication sharedApplication]];
  #ifdef DEBUG
    [DOT checkDebugMode:true]
  #else
    [DOT checkDebugMode:false]
  #endif
  // End : Wisetracker SDK 호출
}
...
@endo
```

{% endtab %}
{% endtabs %}

### Bridge 파일 추가  <a href="#ios_bridge_file_add" id="ios_bridge_file_add"></a>

마지막으로 bridge 함수들을 호출 할 수 있게 bridge 파일을 추가 합니다.

왼쪽은 처음 플러그인 다운로드시 생긴 node\_modules/DotReactNativeBridge/ios 폴더 하위에 있는 bridge파일의 위치이며 파일을 복사한 뒤 , 오른쪽에 보이는 현 프로젝트 폴더의 /프로젝트명/ios/프로젝트명과 동일한 폴더 경로에 복사한 **두 개의 bridge 파일**을 붙여넣습니다.

<figure><img src="https://423922975-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M_ZKcnBFmefw9Yfed6b-3102695190%2Fuploads%2FucRn8Be1KezeJsP13I3J%2Fimage.png?alt=media&#x26;token=31a79cc1-4539-40a7-96af-02442aef89fe" alt=""><figcaption></figcaption></figure>

Bridge 파일 추가 후 AppDelegate.mm 파일에 `DotReactBridge *dotReactBridge`를 추가 해 줍니다.

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

```objectivec
#import "DotReactBridge.h"

- (NSArray<id<RCTBridgeModule>> *)extraModulesForBridge:(RCTBridge *)bridge
{
  // If you'd like to export some custom RCTBridgeModules, add them here!
  DotReactBridge *dotReactBridge = [DotReactBridge alloc];
  return @[dotReactBridge]; 
}
```

{% endtab %}
{% endtabs %}

### 이미지 푸시메시지 적용 (선택사항) <a href="#rn-imagepush" id="rn-imagepush"></a>

1. **Notification Service Extension Target 추가**

이미지를 포함한 푸시메세를 수신받기 위해 필요합니다.

File - New - Target 메뉴에서 "`Notification Service Extension`"을 선택합니다.

<figure><img src="https://423922975-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M_ZKcnBFmefw9Yfed6b-3102695190%2Fuploads%2Fd3utwKheiUQjbqs9Cq7S%2F%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202023-09-08%20%E1%84%8B%E1%85%A9%E1%84%8C%E1%85%A5%E1%86%AB%209.32.02.png?alt=media&#x26;token=359402f6-8b7b-4e60-85bf-e267541c139f" alt=""><figcaption></figcaption></figure>

Product Name에 타겟명을 입력합니다. (아래에서 Podfile에 target을 추가할때 사용할 타겟명입니다)

<figure><img src="https://423922975-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M_ZKcnBFmefw9Yfed6b-3102695190%2Fuploads%2F7QevHyg3KrMKqxNfS9GY%2Fimage.png?alt=media&#x26;token=a1b9dbc1-514e-48b1-9d7c-70400e0d3f5a" alt=""><figcaption></figcaption></figure>

추가 완료 후 `NotificationServiceExtension` 폴더가 생성됩니다.

<figure><img src="https://423922975-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M_ZKcnBFmefw9Yfed6b-3102695190%2Fuploads%2FwD7BBmGOfCrSHp5ONLkI%2Fimage.png?alt=media&#x26;token=12388377-0f57-4bdf-9800-ad0573346322" alt=""><figcaption><p>Language에 따른 폴더 형태</p></figcaption></figure>

2. **Podfile 수정**

Podfile에 아래와 같이 앱의 타겟 안에 이미지 푸시를 위한 타겟을 추가한 후 `pod install` 명령어를 실행시켜 줍니다.

#### **`Podfile`**

:heavy\_check\_mark:프레임워크 추가시 앱의 프레임워크 방식과 동일하게 작성될 수 있도록 한번 더 체크 해 주세요. (동적 or 정적)

:heavy\_check\_mark:Wisetracker SDK 버전이 명시되어 있다면, 동일하게 버전이 명시되어 있는 형태로 추가했는지 체크 해 주세요.

```
target 'wisetracker' do
  ...
  # S: Wisetracker SDK add
  pod 'RW', '~> 1.1.45'
  pod 'Firebase/Messaging'
  # E: Wisetracker SDK add
  ...

  # =======================================================
  #Start : 이미지 푸시 수신을 위한 추가
  #=======================================================
  target ‘NotificationServiceExtension’ do
  
    # 프레임워크를 동적으로 링크하는것이 권장되오나, 앱에 따라 정적으로 링크하는 경우,
    # 앱의 프레임워크 링크방식과 동일하게 사용 해 주세요. 아래의 방식은 정적으로 링크하는 경우입니다.
    # use_frameworks!  >>>>>>>>> 동적의 경우일때 사용
    use_frameworks! :linkage => :static
    
    # Wisetracker SDK 의 버전이 명시되어 있는 경우 동일하게 버전을 명시 해 주세요.
    pod 'RW', '~> 1.1.45'
    pod ‘FirebaseMessaging’, :modular_headers => true
   end
  #=======================================================
  #End : 이미지 푸시
  #=======================================================

...
...
end
```

위의 "<mark style="color:red;">NotificationServiceExtension</mark>"은 고객사에서 만든 타켓명으로 해주셔야 합니다.&#x20;

예시는 타겟명이 "<mark style="color:red;">NotificationServiceExtension</mark>"인 경우입니다.

{% hint style="danger" %}
:red\_circle: Podfile에 이미지 푸시를 추가하였으나 아래와 같은 에러가 발생된다면 아래의 앱 확장 코드를 추가 해 주세요.

<mark style="color:red;">'sharedApplication' is unavailable: not available on iOS (App Extension) - Use view controller based solutions where appropriate instead.</mark>
{% endhint %}

```
target 'wisetracker' do
...

  post_install do |installer|
    react_native_post_install(
      installer,
      ...
      ...
    )
    ...
    ###############  App Extension 에러 발생시 추가 ######################
    # 앱 확장이 iOS 기능과 라이브러리에 자유롭게 액세스할 수 있게 설정.
    installer.pods_project.targets.each do |target|
     target.build_configurations.each do |config|
      config.build_settings[‘APPLICATION_EXTENSION_API_ONLY’] = ‘NO’
     end
    end
    ###################################################################
  end
  
  # S: Wisetracker SDK add
  pod 'RW', '~> 1.1.45'
  pod 'Firebase/Messaging'
  # E: Wisetracker SDK add
  
...
...
end
```

3. **NotificationService 수정**

* `NotificationService` 파일을 열어 아래의 내용으로 대체해 주세요.\ <mark style="color:red;">**\* 기존 내용을 모두 삭제하고 아래 내용으로 대체하는것이며, 추가가 아님에 유의 해 주세요.**</mark>

**`NotificationService`**

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

```swift
// =======================================================
// Start : 소스코드 모두 바꾸기
// =======================================================
import UserNotifications
import FirebaseMessaging

class NotificationService: UNNotificationServiceExtension {
    var contentHandler: ((UNNotificationContent) -> Void)?
    var bestAttemptContent: UNMutableNotificationContent?

    override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
        self.contentHandler = contentHandler
        self.bestAttemptContent = request.content.mutableCopy() as? UNMutableNotificationContent
        
        if let bestAttemptContent = self.bestAttemptContent {
            // DOT didReceiveNotificationExtensionRequest 메서드 호출
            self.bestAttemptContent = self.didReceiveNotificationExtensionRequest(request, withContent: bestAttemptContent)
            
            if let contentHandler = self.contentHandler {
                FIRMessagingExtensionHelper().populateNotificationContent(bestAttemptContent, withContentHandler: contentHandler)
            }
        }
    }
    
    override func serviceExtensionTimeWillExpire() {
        if let contentHandler = self.contentHandler, let bestAttemptContent = self.bestAttemptContent {
            contentHandler(bestAttemptContent)
        }
    }
    
    func didReceiveNotificationExtensionRequest(_ request: UNNotificationRequest, withContent content: UNMutableNotificationContent) -> UNMutableNotificationContent {
        return content
    }
}
// =======================================================
// End : 소스코드 모두 바꾸기
// =======================================================
```

{% endtab %}

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

```objectivec
// =======================================================
// Start : 소스코드 모두 바꾸기
// =======================================================
#import "NotificationService.h"
#import <DOT/DOT.h>
#import <FirebaseMessaging/FirebaseMessaging.h>

@interface NotificationService ()
@property (nonatomic, strong) void (^contentHandler)(UNNotificationContent *contentToDeliver);
@property (nonatomic, strong) UNMutableNotificationContent *bestAttemptContent;
@end
@implementation NotificationService
- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler {
    self.contentHandler = contentHandler;
    self.bestAttemptContent = [request.content mutableCopy];
    self.bestAttemptContent = [DOT didReceiveNotificationExtensionRequest:request withContent:self.bestAttemptContent];
    [[FIRMessaging extensionHelper] populateNotificationContent:self.bestAttemptContent withContentHandler:self.contentHandler];
}
- (void)serviceExtensionTimeWillExpire {
    self.contentHandler(self.bestAttemptContent);
}
@end
// =======================================================
// End : 소스코드 모두 바꾸기
// =======================================================

```

{% endtab %}
{% endtabs %}

{% hint style="warning" %}
:red\_circle: `NotificationService 파일에서`FirebaseMessaging 모듈이 없다는 에러 발생시 `Notification Service Extension` 타겟의 빌드 설정에서 "<mark style="color:red;">Header Search Paths</mark>" 항목을 확인하고 Firebase Messaging 헤더 파일이 포함된 디렉토리가 있는지 확인하세요.

<img src="https://423922975-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M_ZKcnBFmefw9Yfed6b-3102695190%2Fuploads%2FpHgow1ZLqVquTYleuTnT%2Fimage.png?alt=media&#x26;token=b4044bbc-c8e1-49ac-b92f-bd785378cc71" alt="" data-size="original">
{% endhint %}

iOS 기초설정은 완료하셨습니다 🎉

다음으로 푸시메세지 설정을 위한 단계를 진행 해 주세요 👇🏻
