> 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/ios/action/push-notification.md).

# 푸시

## 시작하기 전에

[유저 프로필 설정](/developer-guide/platform/ios/user-profile.md)을 통해 사용하고자 하는 액션의 채널 수신 동의 설정이 선행되어야 합니다.

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

{% hint style="warning" %}
현재 iOS Sandbox 토큰으로는 콘솔을 통해 푸시 메시지를 전송하실 수 없습니다. 토큰의 종류 상관없이 콘솔이 아닌 로컬환경에서 테스트하는 방법은 [iOS 푸시 페이로드 가이드 페이지](/developer-guide/common/specification/ios-push-payload.md)에서 확인해주세요
{% endhint %}

### SDK 연동

AppDelegate 클래스에 푸시 토큰 등록 코드를 추가합니다.

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

```swift
import UIKit
import UserNotifications

import DfinerySDK

@main
class AppDelegate: UIResponder, UIApplicationDelegate {

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        ...
        ...
        application.registerForRemoteNotifications()
        ...
        ...
    }

    func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
        
        Dfinery.shared().set(pushToken: deviceToken)

    }

}
```

{% endtab %}

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

```objective-c
#import <UIKit/UIKit.h>
#import <DfinerySDK/DfinerySDK.h>
#import <UserNotifications/UserNotifications.h>

@interface AppDelegate : UIResponder <UIApplicationDelegate, UNUserNotificationCenterDelegate>

@end

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    ...
    [application registerForRemoteNotifications];
    ...
    return YES;
}

- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
    [[Dfinery shared] setPushToken:deviceToken];
}

- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
    NSLog(@"Failed to register for remote notifications: %@", error);
}

@end

```

{% endtab %}
{% endtabs %}

{% hint style="warning" %}
푸시 메시지 사용을 위해 유저 권한을 획득해야 합니다.
{% endhint %}

### 예시 코드

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

```swift
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, sound]) { granted, err in
   if granted {
       DispatchQueue.main.async {
           UIApplication.shared.registerForRemoteNotifications()
       }
   }
}
```

{% endtab %}

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

```objective-c
[[UNUserNotificationCenter currentNotificationCenter] requestAuthorizationWithOptions:(UNAuthorizationOptionAlert | UNAuthorizationOptionSound)
    completionHandler:^(BOOL granted, NSError * _Nullable error) {
        if (granted) {
            dispatch_async(dispatch_get_main_queue(), ^{
                [[UIApplication sharedApplication] registerForRemoteNotifications];
            });
        }
    }
];
```

{% endtab %}
{% endtabs %}

### 푸시 핸들링

푸시 핸들링을 위해 AppDelegate 클래스에 UNUserNotificationCenterDelegate 프로토콜을 채택하고 SDK 코드를 연동해주세요.

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

```swift
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        ...
        ...
        UNUserNotificationCenter.current().delegate = self
        ...
        ...
    }

    func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
        
        if Dfinery.shared().canHandleNotification(response: response) {
            completionHandler()
            return
        }
        
    }
    
    func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {

        if Dfinery.shared().canHandleForeground(notification, completionHandler: completionHandler) {
            return
        }
        
    }
}
```

{% endtab %}

{% tab title="Objective-C" %}
AppDelegate.h

```objective-c
#import <UserNotifications/UserNotifications.h>

@interface AppDelegate : UIResponder <UIApplicationDelegate, UNUserNotificationCenterDelegate>
```

AppDelegate.m

```objective-c

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    ...
    ...
    [[UNUserNotificationCenter currentNotificationCenter] setDelegate:self];
    ...
    ...
}

- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler
{
    if ([[Dfinery shared] canHandleNotificationWithResponse:response]) {
        completionHandler();
        return;
    }
}

- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler
{
    if ([[Dfinery shared] canHandleForeground:notification completionHandler:completionHandler]) {
        return;
    }
}
```

{% endtab %}
{% endtabs %}

### Service Extension

디파이너리 푸시의 이미지, 버튼 사용을 위해 Notification Service Extension을 추가로 생성하고 DfineryServiceExtension을 연동해야 합니다.

{% tabs %}
{% tab title="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)
        }
    }
    ...
}
```

{% endtab %}

{% tab title="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 %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## 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, and the optional `goal` query parameter:

```
GET https://docs.dfinery.ai/developer-guide/platform/ios/action/push-notification.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

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.
