# Настройка 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="/files/CtEdeGHVnYGahQgESYaH" alt=""><figcaption></figcaption></figure>

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

<figure><img src="/files/faMdUPQ5QBwXVibVeMc5" 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="/files/0sFVugIyFt1EDFfQZCYt" alt=""><figcaption></figcaption></figure>

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

<figure><img src="/files/qQqCHO8Gf93kw8nizWEG" 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/).

  ##


---

# Agent Instructions: 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:

```
GET https://faq.docs.direct.i-dgtl.ru/kanaly-otpravki/push-rassylki/nastroika-ios-prilozheniya.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
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.
