# iOS 연동

## 사전 작업 <a href="#pre-work" id="pre-work"></a>

iOS Push Notification을 설정하려면 iOS SDK 연동이 필요합니다. 다음 가이드를 완료 후 진행해주세요.

{% content-ref url="../../sdk-integrating/initialize/ios-sdk" %}
[ios-sdk](https://docs.marketap.io/t3ZS4WXNMj0HK27EtIMV/developer/sdk-integrating/initialize/ios-sdk)
{% endcontent-ref %}

## 1. Xcode 설정

Xcode에서 설정이 필요합니다. 이미 사용중인 설정은 스킵해주세요.

### 1.1 Push Notifications 추가

Xcode의 Target > Signing & Capabilities 에서 Push Notification 을 추가합니다.

<figure><img src="https://content.gitbook.com/content/TQoY0rYrzNUQxhlUfYFm/blobs/vNIYm5EsM0LtAYn2SF5s/%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%202025-02-20%20%E1%84%8B%E1%85%A9%E1%84%8C%E1%85%A5%E1%86%AB%2011.36.36.png" alt=""><figcaption></figcaption></figure>

### 1.2 Notification Service Extension 추가

Xcode의 File > New > Target 에서 Notification Service Extension을 추가합니다.&#x20;

<figure><img src="https://content.gitbook.com/content/TQoY0rYrzNUQxhlUfYFm/blobs/L3yeP6UBW2rjkcB37VI2/%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%202025-02-20%20%E1%84%8B%E1%85%A9%E1%84%8C%E1%85%A5%E1%86%AB%2011.42.50.png" alt=""><figcaption></figcaption></figure>

적절한 이름을 입력, Embed in Application 에서 앱 타겟이 선택되어 있는지 확인해준 후 계속 진행합니다. 이 가이드에서는 `DummyNotificationServiceExtension` 으로 추가하겠습니다.

<figure><img src="https://content.gitbook.com/content/TQoY0rYrzNUQxhlUfYFm/blobs/LjluYPYeC9IRTa7XSR1W/%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%202025-02-20%20%E1%84%8B%E1%85%A9%E1%84%8C%E1%85%A5%E1%86%AB%2011.43.24.png" alt=""><figcaption></figcaption></figure>

Activate 까지 완료해줍니다.

<figure><img src="https://content.gitbook.com/content/TQoY0rYrzNUQxhlUfYFm/blobs/pmpTAR24mhzCMXwehpOV/%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%202025-02-20%20%E1%84%8B%E1%85%A9%E1%84%8C%E1%85%A5%E1%86%AB%2011.43.31.png" alt=""><figcaption></figcaption></figure>

## 2. SDK 추가하기

CocoaPods와 SPM을 지원합니다.

### 2.1 CocoaPods

Podfile에 다음과 같이 추가하고 pod insall 해주세요.&#x20;

```ruby
use_frameworks!

# 1.2 에서 추가한 NotificationServiceExtension 타겟 이름을 넣어주세요.
target 'DummyNotificationServiceExtension' do
  pod 'MarketapSDKNotificationServiceExtension', '~> 1.0.9'
end
```

### 2.2 SPM (Swift Package Manager)

[ios-sdk](https://docs.marketap.io/t3ZS4WXNMj0HK27EtIMV/developer/sdk-integrating/initialize/ios-sdk "mention") 에서 `MarketapSDK`  패키지를 추가했다면 `MarketapNotificationServiceExtension` 가 함께 설치되어 있습니다. [#id-1.2-notification-service-extension](#id-1.2-notification-service-extension "mention") 에서 설정한 NotificationServiceExtension 타겟에 추가해줍니다.

<figure><img src="https://260547158-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FTQoY0rYrzNUQxhlUfYFm%2Fuploads%2FLqrJNqXllGTeITmyZeLA%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%202025-07-07%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%203.33.33.png?alt=media&#x26;token=fbf11040-44b6-4134-a9a2-50b462f28f1c" alt=""><figcaption></figcaption></figure>

## 3. 연동 코드 작성하기

### 3.1 UNUserNotificationCenterDelegate 설정

앱 푸시 설정을 위해 `UNUserNotificationCenterDelegate` 를 추가하고 SDK 와 연동해줍니다. 이미 사용중인 `UNUserNotificationCenterDelegate` 가 있다면 동일하게 사용 가능합니다.

예시에서는 `AppDelegate`에 `UNUserNotificationCenterDelegate`를 채택하고 사용하겠습니다.

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

<pre class="language-swift"><code class="lang-swift">import MarketapSDK

class AppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDelegate {
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {    
        // ...
        Marketap.initialize(projectId: "PROJECT_ID")
        Marketap.application(application, didFinishLaunchingWithOptions: launchOptions)

        // delegate 추가
<strong>        UNUserNotificationCenter.current().delegate = self
</strong>        // ...
        return true
    }

    func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
        // ...
        // 푸시 토큰 등록
<strong>        Marketap.setPushToken(token: deviceToken)
</strong>    }

    func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
        // ...
        // 마켓탭이 푸시를 처리했으면 리턴 (마켓탭 콘솔에서 전송했을 경우)
<strong>        if Marketap.userNotificationCenter(center, willPresent: notification, withCompletionHandler: completionHandler) {
</strong><strong>            return
</strong><strong>        }
</strong>        // 마켓탭이 처리하지 않았으면 이어서 진행
        // ...
    }

    func userNotificationCenter(
        _ center: UNUserNotificationCenter,
        didReceive response: UNNotificationResponse,
        withCompletionHandler completionHandler: @escaping () -> Void
    ) {
        // ...
        // 마켓탭이 푸시 클릭을 처리했으면 리턴 (마켓탭 콘솔에서 전송했을 경우)
<strong>        if Marketap.userNotificationCenter(center, didReceive: response, withCompletionHandler: completionHandler) {
</strong><strong>            return
</strong><strong>        }
</strong>        // 마켓탭이 처리하지 않았으면 이어서 진행
        // ...
    }
}

</code></pre>

{% endtab %}

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

<pre class="language-objectivec"><code class="lang-objectivec">@import MarketapSDK;

@interface AppDelegate () &#x3C;UNUserNotificationCenterDelegate>

@end

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    ...
    [Marketap initializeWithProjectId:@"PROJECT_ID"];
    
    // delegate 추가
<strong>    [UNUserNotificationCenter currentNotificationCenter].delegate = self;
</strong>    ...
    return YES;
}

- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
<strong>    [Marketap setPushTokenWithToken:deviceToken];
</strong>}

- (void)userNotificationCenter:(UNUserNotificationCenter *)center
       willPresentNotification:(UNNotification *)notification
         withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler {
    ...
    // 마켓탭이 푸시를 처리했으면 리턴 (마켓탭 콘솔에서 전송했을 경우)
<strong>    if ([Marketap userNotificationCenter:center willPresent:notification withCompletionHandler:completionHandler]) {
</strong><strong>        return;
</strong><strong>    }
</strong>    // 마켓탭이 처리하지 않았으면 이어서 진행
    ...
}

- (void)userNotificationCenter:(UNUserNotificationCenter *)center
    didReceiveNotificationResponse:(UNNotificationResponse *)response
         withCompletionHandler:(void (^)(void))completionHandler {
    ...
    // 마켓탭이 푸시 클릭을 처리했으면 리턴 (마켓탭 콘솔에서 전송했을 경우)
<strong>    if ([Marketap userNotificationCenter:center didReceive:response withCompletionHandler:completionHandler]) {
</strong><strong>        return;
</strong><strong>    }
</strong>    // 마켓탭이 처리하지 않았으면 이어서 진행
    ...
}

@end

</code></pre>

{% endtab %}
{% endtabs %}

### 3.2 앱 푸시 수신 설정 (선택)

푸시 알림을 발송하려면 사용자에게 수신 동의를 받아야 합니다. 관련 권한을 앱에서 직접 관리하거나 MarketapSDK 가 지원하는 함수를 사용할 수 있습니다. 다음은 예시 코드입니다.

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

<pre class="language-javascript"><code class="lang-javascript">func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    // ...
    Marketap.initialize(projectId: "PROJECT_ID")
    Marketap.application(application, didFinishLaunchingWithOptions: launchOptions)

    // 권한 요청 및 등록
<strong>    Marketap.requestAuthorizationForPushNotifications()
</strong>    // ...
    return true
}
</code></pre>

{% endtab %}

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

```objectivec
[[UNUserNotificationCenter currentNotificationCenter] requestAuthorizationWithOptions:(UNAuthorizationOptionAlert | UNAuthorizationOptionBadge | UNAuthorizationOptionSound)
    completionHandler:^(BOOL granted, NSError * _Nullable error) {
        if (granted) {
            dispatch_async(dispatch_get_main_queue(), ^{
                [[UIApplication sharedApplication] registerForRemoteNotifications];
            });
        } else if (error) {
            NSLog(@"Notification permission error: %@", error.localizedDescription);
        }
}];
```

{% endtab %}
{% endtabs %}

### 3.3 Notification Service Extension 연동하기

{% hint style="danger" %}
이 섹션의 연동을 진행하지 않을 경우 이미지 누락, 임프레션 집계 오류 등 마켓탭 푸시가 정상 동작하지 않을 수 있습니다. 필수로 연동해주세요.
{% endhint %}

[#id-1.2-notification-service-extension](#id-1.2-notification-service-extension "mention") 에서 추가한 Notification Service Extension의 `NotificationService`에 다음과 같이 추가해줍니다.

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

<pre class="language-swift"><code class="lang-swift">import UIKit
<strong>import MarketapSDKNotificationServiceExtension
</strong>
class NotificationService: UNNotificationServiceExtension {
    var contentHandler: ((UNNotificationContent) -> Void)?
    var bestAttemptContent: UNMutableNotificationContent?

    override func didReceive(
        _ request: UNNotificationRequest,
        withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void
    ) {
        // 마켓탭이 푸시를 처리했으면 리턴 (마켓탭 콘솔에서 전송했을 경우)
<strong>        if MarketapNotificationService.didReceive(request, withContentHandler: contentHandler) {
</strong><strong>            return
</strong><strong>        }
</strong>        // 마켓탭이 처리하지 않았으면 이어서 진행
        // ...
    }

    override func serviceExtensionTimeWillExpire() {
        // 마켓탭이 처리했으면 리턴 (마켓탭 콘솔에서 전송했을 경우)
<strong>        if MarketapNotificationService.serviceExtensionTimeWillExpire() {
</strong><strong>            return
</strong><strong>        }
</strong>        // 마켓탭이 처리하지 않았으면 이어서 진행
        // ...
    }
}
</code></pre>

{% endtab %}

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

<pre class="language-python"><code class="lang-python">#import &#x3C;UIKit/UIKit.h>
#import &#x3C;UserNotifications/UserNotifications.h>
@import MarketapSDKNotificationServiceExtension;

@interface NotificationService : UNNotificationServiceExtension

@property (nonatomic, strong) void (^contentHandler)(UNNotificationContent *content);
@property (nonatomic, strong) UNMutableNotificationContent *bestAttemptContent;

@end

@implementation NotificationService

- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request
                withContentHandler:(void (^)(UNNotificationContent *content))contentHandler {
    // 마켓탭이 푸시를 처리했으면 리턴 (마켓탭 콘솔에서 전송했을 경우)
<strong>    if ([MarketapNotificationService didReceive:request withContentHandler:contentHandler]) {
</strong><strong>        return;
</strong><strong>    }
</strong>    // 마켓탭이 처리하지 않았으면 이어서 진행
    // ...
}

- (void)serviceExtensionTimeWillExpire {
    // 마켓탭이 처리했으면 리턴 (마켓탭 콘솔에서 전송했을 경우)
<strong>    if ([MarketapNotificationService serviceExtensionTimeWillExpire]) {
</strong><strong>        return;
</strong><strong>    }
</strong>    // 마켓탭이 처리하지 않았으면 이어서 진행
    // ...
}

@end
</code></pre>

{% endtab %}
{% endtabs %}

## 4. 클릭 액션 커스텀하기 (선택)

푸시 캠페인에 클릭 액션 URL이 설정되어 있는 경우, **마켓탭 SDK는 기본 동작으로** `UIApplication.shared.open`을 호출하여 해당 URL을 실행합니다.

실행된 URL은 앱의 딥링크 처리 루트(예: `application(_:open:options:)` 또는 `SceneDelegate`의 `scene(_:openURLContexts:)`)에서 수신하여 처리할 수 있습니다.

이 기본 동작을 비활성화하고 클릭 시 액션을 직접 제어하려면, 아래 페이지 안내에 따라 clickHandler 기반 커스텀 연동을 진행해주세요.

{% content-ref url="../../advanced-usage/custom-click-handler" %}
[custom-click-handler](https://docs.marketap.io/t3ZS4WXNMj0HK27EtIMV/developer/advanced-usage/custom-click-handler)
{% endcontent-ref %}

## 5. 이어서 진행하기

이제 Push Notification 연동이 완료되었습니다. 아래 문서에서 이어서 진행해주세요.

<table data-view="cards"><thead><tr><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td>Push Notification 테스트</td><td><a href="../test">test</a></td></tr><tr><td>In-App Campaign 테스트</td><td><a href="../../in-app-message/in-app-campaign">in-app-campaign</a></td></tr><tr><td>심화 연동</td><td><a href="../../advanced-usage/overview">overview</a></td></tr></tbody></table>
