# Настройка iOS приложения

## **Настройка приложения для получения и отображения push-уведомлений**

Для получения и отображения push-уведомлений выполните следующие шаги:

1. Зарегистрируйте приложение в Apple Push Notification Service (APNs): [Registering Your App with APNs](https://developer.apple.com/documentation/usernotifications/registering_your_app_with_apns).
2. Запросите разрешение на показ уведомлений: [Asking Permission to Use Notifications](https://developer.apple.com/documentation/usernotifications/asking_permission_to_use_notifications).
3. Реализуйте метод `userNotificationCenter(_:willPresent:withCompletionHandler:)` для отображения уведомлений, когда приложение запущено и активно: [Handling Notifications and Notification-Related Actions](https://developer.apple.com/documentation/usernotifications/handling_notifications_and_notification-related_actions).
4. Реализуйте отправку токена на мобильный бекенд при вызове метода **application(\_:didRegisterForRemoteNotificationsWithDeviceToken:)**.

### Пример AppDelegate после выполнения вышеуказанных действий

```swift
@main
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {
    
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        UNUserNotificationCenter.current().delegate = self
        UNUserNotificationCenter.current().requestAuthorization(options: [.badge, .sound, .alert]) { (granted, error) in
            if let error = error {
                print("Failed to request notification center authorization: \\(error)")
            }
        }
        
        application.registerForRemoteNotifications()
        return true
    }
    
    func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
        let stringToken = deviceToken.map { String(format: "%02.2hhx", $0) }.joined()
        self.sendDeviceTokenToBackend(token: stringToken)
    }
    
    func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
        print("Failed to register for remote notifications: \\(error)")
        // Try again later.
    }
    
    // MARK: - UNUserNotificationCenterDelegate

    // The method will be called on the delegate only if the application is in the foreground.
    func userNotificationCenter(_ center: UNUserNotificationCenter,
                                willPresent notification: UNNotification,
                                withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
        completionHandler([.alert, .sound, .badge])
    }
}
```

## **Отслеживание статусов доставки**

При получении уведомления вам необходимо передавать на наш сервер информацию об идентификаторе сообщения на нашей платформе и статусе уведомления. Для этого необходимо выполните следующие шаги:&#x20;

1. Добавьте к приложению расширение [Notification Service Extension](https://developer.apple.com/documentation/usernotifications/unnotificationserviceextension).
2. В методе `didReceive(_:withContentHandler:)` расширения отправляйте следующий HTTP-запрос:

```json
POST <https://nativepush.i-dgtl.ru/notification-state>
Content-Type: application/json

{
	"messageId": "MESSAGE_ID",
	"state": "RECEIVED"
}
```

В ответ наш сервер должен вернуть _204 No Content_.

### Как добавить расширение **Notification Service Extension?**

1. В Xcode выберите **File** → **New** → **Target**.
2. Выберите из списка шаблонов **Notification Service Extension** и нажмите **Next**.

<figure><img src="../../.gitbook/assets/notification-service-extension.png" alt=""><figcaption></figcaption></figure>

3. Введите название расширения и нажмите **Finish**.

<figure><img src="../../.gitbook/assets/image (103).png" alt=""><figcaption></figcaption></figure>

### Пример реализации расширения

```swift
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 let messageId = bestAttemptContent.userInfo["messageId"] as? String {
                sendReceivedStateCallback(messageId: messageId) { error in
                    if let error = error {
												// handle request error
                    }
                    contentHandler(bestAttemptContent)
                }
            } else {
                contentHandler(bestAttemptContent)
            }
        }
    }
    
    override func serviceExtensionTimeWillExpire() {
        // Called just before the extension will be terminated by the system.
        // Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used.
        if let contentHandler = contentHandler, let bestAttemptContent =  bestAttemptContent {
            contentHandler(bestAttemptContent)
        }
    }
    
    func sendReceivedStateCallback(messageId: String, completionHandler: @escaping (Error?) -> Void) {
        #if DEBUG
        let callbackUrl = "<https://nativepush-test.i-dgtl.ru/notification-state>"
        #else
        let callbackUrl = "<https://nativepush.i-dgtl.ru/notification-state>"
        #endif
        
        let callbackParams = ["messageId": messageId, "state": "RECEIVED"]
        var request = URLRequest(url: URL(string: callbackUrl)!, timeoutInterval: 15)
        request.httpMethod = "POST"
        request.addValue("application/json", forHTTPHeaderField: "Content-Type")
        request.httpBody = try? JSONSerialization.data(withJSONObject: callbackParams)
        
        let task = URLSession.shared.dataTask(with: request, completionHandler: { _, response, error in
            guard error == nil else {
                completionHandler(error)
                return
            }
            if let httpResponse = response as? HTTPURLResponse {
                guard (200...299).contains(httpResponse.statusCode) else {
                    completionHandler(NSError(domain: "unsuccessful http status code", code: httpResponse.statusCode, userInfo: nil))
                    return
                }
            }
            completionHandler(nil)
        })
        
        task.resume()
    }
}
```

{% hint style="info" %}
Время выполнения метода `didReceive(_:withContentHandler:)` ограничено 30 секундами, однако мы рекомендуем устанавливать меньший таймаут запроса, так как уведомление пользователю будет показано только после вызова contentHandler.
{% endhint %}

## Отправка уведомлений

При отправке уведомлений используется ключ в формате`.p8` для авторизации на сервере APNs, который вам нужно передать i-Digital.

### Как создать ключ p8?

1. Войдите в ваш [Appple Developer Account](https://developer.apple.com/) и перейдите на страницу [Certificates, Identifiers & Profiles](https://developer.apple.com/account/resources).
2. В меню слева выберите Keys и нажмите на синюю кнопку (+).

<figure><img src="../../.gitbook/assets/p8-key.png" alt=""><figcaption></figcaption></figure>

3. Введите название ключа, отметьте **Apple Push Notifications service (APNs)** и нажмите **Continue**.

<figure><img src="../../.gitbook/assets/register-new-p8-key.png" alt=""><figcaption></figcaption></figure>

4. Нажмите **Register,** после чего скачайте созданный ключ, нажав **Download.**

### Как передать созданный `p8` ключ в i-Digital?

Отправьте письмо на support@i-dgtl.ru с темой "Подключение PUSH i-digital direct", указав в теле письма следующее:

* название вашей организации,
* файл ключа,
* **Key ID** - отображается после создания ключа,
*   **Team ID** - можно найти в [Appple Developer Account](https://developer.apple.com/) на странице [Membership ](https://developer.apple.com/account/#!/membership/).

    ##
