> 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).

# 푸시

## 시작하기 전에 <a href="#before-you-begin" id="before-you-begin"></a>

[유저 프로필 설정](/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 연동 <a href="#sdk-integration" id="sdk-integration"></a>

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 %}

### 예시 코드 <a href="#example-code" id="example-code"></a>

{% 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 %}

### 푸시 핸들링 <a href="#push-handling" id="push-handling"></a>

푸시 핸들링을 위해 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 <a href="#service-extension" id="service-extension"></a>

디파이너리 푸시의 이미지, 버튼 사용을 위해 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 %}
