# Отслеживание доставки сообщений в iOS

В Pushwoosh есть [API-метод](/ru/developer/api-reference/device-api#messagedeliveryevent), который отслеживает доставку push-уведомлений. iOS-приложения не поддерживают этот метод «из коробки», поскольку push-уведомления в iOS обрабатываются операционной системой, а не Pushwoosh SDK. Вы можете добавить отслеживание доставки, добавив Notification Service Extension в ваш проект. На этой странице показано, как реализовать отслеживание доставки сообщений для iOS-приложений.

<Aside>
Требуется Pushwoosh iOS SDK 7.x, который поддерживает iOS 13.0 и более поздние версии.
</Aside>

<Aside type="note">
Начиная с Pushwoosh iOS SDK 7.1.0, рекомендуемой интеграцией является использование базового класса `PushwooshNotificationServiceExtension`, как показано ниже. Он отправляет событие о доставке сообщения, устанавливает значок (badge), загружает медиавложения и обрабатывает обязательный резервный вариант `serviceExtensionTimeWillExpire` за вас. Старый API `PWNotificationExtensionManager` все еще работает, но является устаревшим — см. [Устаревшая интеграция](#legacy-integration).
</Aside>

## Добавление Notification Service Extension

1. В Xcode выберите **File** > **New** > **Target...** (Файл > Новый > Цель...)

2. Выберите **Notification Service Extension** и нажмите **Next** (Далее).

<img src="/ios-push-notifications-ios-message-delivery-tracking-1.webp" alt="Окно выбора шаблона цели в Xcode с выбранным Notification Service Extension"/>

3. Введите название продукта и нажмите **Finish** (Завершить).

<Aside type="caution">
Не нажимайте **Activate** (Активировать) в диалоговом окне, которое появится после нажатия **Finish**.
</Aside>

4. Нажмите **Cancel** (Отмена) в запросе **Activate scheme** (Активировать схему).

<img
  src="/ios-push-notifications-ios-message-delivery-tracking-2.webp"
  alt="Запрос на активацию схемы с выделенной кнопкой Cancel"
  style={{ display: "block", margin: "0 auto", maxWidth: "40%", height: "auto" }}
  width="400"
/>

Отменив это действие, вы сохраните отладку вашего приложения в Xcode вместо только что созданного расширения. Если вы случайно активировали его, вы можете переключиться обратно на отладку вашего приложения в Xcode.

## Зависимости для Notification Service Extension (только CocoaPods)

Если вы используете Swift Package Manager для управления зависимостями, вы можете пропустить этот шаг, так как зависимости добавляются автоматически.

Откройте ваш `Podfile` и добавьте зависимость для цели (target):

```ruby title="Podfile"
target 'NotificationServiceExtension' do
  use_frameworks!
  pod 'PushwooshXCFramework'
end
```

Выполните следующие команды в терминале, чтобы установить зависимости:

```shell
rm -rf Podfile.lock
pod deintegrate
pod setup
pod repo update
pod install
```

## Добавление кода для отслеживания событий доставки сообщений

Сделайте ваше расширение подклассом `PushwooshNotificationServiceExtension`. Пустого подкласса достаточно: Pushwoosh автоматически отправляет событие о доставке сообщения, устанавливает значок (badge), загружает медиавложения и обрабатывает резервный вариант при истечении времени ожидания.

Замените сгенерированное содержимое вашего файла **NotificationService**:

<Tabs>
<TabItem label="Swift">

```swift
import UserNotifications
import PushwooshFramework

class NotificationService: PushwooshNotificationServiceExtension {}
```

</TabItem>

<TabItem label="Objective-C">

```objective-c
#import <PushwooshFramework/PushwooshNotificationServiceExtension.h>

@interface NotificationService : PushwooshNotificationServiceExtension

@end

@implementation NotificationService

@end
```

</TabItem>
</Tabs>

<Aside type="tip">
Если вам не нужен какой-либо пользовательский код, вы можете полностью пропустить исходный файл и указать `NSExtensionPrincipalClass` в Info.plist расширения непосредственно на `PushwooshNotificationServiceExtension`.
</Aside>

### App ID

Начиная с версии 7.1.0, расширение наследует `Pushwoosh_APPID` (и другие ключи `Pushwoosh_*`) из Info.plist основного приложения, поэтому вам больше не нужно дублировать его в расширении. Добавляйте `Pushwoosh_APPID` в Info.plist расширения, только если вы хотите переопределить значение основного приложения:

```xml title="NotificationService/Info.plist"
<key>Pushwoosh_APPID</key>
<string>XXXXX-XXXXX</string>
```

<Aside type="note">
В версиях Pushwoosh iOS SDK ранее 7.1.0 расширение не наследует конфигурацию от основного приложения. В этих версиях вы должны добавить `Pushwoosh_APPID` в Info.plist расширения.
</Aside>

### App Group (значок и обратный прокси)

App Group, общая для приложения и расширения, необходима для синхронизации счетчика значка (badge) и для чтения настроек обратного прокси (reverse-proxy), которые хранит основное приложение.

1. Добавьте возможность **App Groups** к цели (target) расширения и включите ту же группу, что и в основном приложении. Это обязательно — без общего контейнера счетчик значка и настройки обратного прокси не могут быть синхронизированы.

2. Укажите имя App Group. Как и `Pushwoosh_APPID`, расширение наследует `PW_APP_GROUPS_NAME` из Info.plist основного приложения начиная с версии 7.1.0, поэтому, если вы уже установили его там для значков, вам не нужно добавлять его в расширение. Устанавливайте его в Info.plist расширения только для переопределения значения основного приложения или предоставляйте его программно, переопределив `pushwooshAppGroupsName`.

```xml title="App Info.plist"
<key>PW_APP_GROUPS_NAME</key>
<string>group.com.example.app</string>
```

<Aside type="caution">
Если основное приложение использует обратный прокси (`Pushwoosh_ALLOW_REVERSE_PROXY`), расширению необходима эта App Group для чтения URL-адреса прокси, сохраненного приложением. Без этого событие о доставке будет задержано, а не отправлено напрямую в обход прокси.
</Aside>

## Настройка уведомления (необязательно)

Базовый класс предоставляет несколько точек для переопределения, от наименьшего до наибольшего контроля. Pushwoosh в любом случае выполняет отправку события о доставке, обработку значка, вложения и резервный вариант при истечении времени ожидания.

Установите App Group программно вместо использования ключа в Info.plist:

```swift
override func pushwooshAppGroupsName() -> String? {
    "group.com.example.app"
}
```

Выполните асинхронную подготовку перед тем, как Pushwoosh обработает push-уведомление — например, предварительную загрузку медиа для Push Stories — без переопределения стандартного `didReceive`. Вызовите `completion` ровно один раз в главном потоке:

```swift
override func pushwooshPrepare(for request: UNNotificationRequest,
                              completion: @escaping () -> Void) {
    // async work here
    completion()
}
```

Измените содержимое перед его отображением, переопределив `didReceive`. Вызовите `super` с вашим собственным обработчиком содержимого, измените содержимое внутри него, а затем передайте его исходному обработчику:

```swift
override func didReceive(_ request: UNNotificationRequest,
                         withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
    super.didReceive(request) { content in
        let mutable = (content.mutableCopy() as? UNMutableNotificationContent) ?? content
        // customize `mutable` here
        contentHandler(mutable)
    }
}
```

## Устаревшая интеграция

<Aside type="caution">
`PWNotificationExtensionManager` устарел с версии 7.1.0. Используйте его, только если вы не можете создать подкласс `PushwooshNotificationServiceExtension` — например, если расширение уже наследует базовый класс другого SDK или является кросс-платформенной оберткой (React Native, Flutter, Unity). В новых интеграциях следует использовать базовый класс, описанный выше.
</Aside>

Этот низкоуровневый API управляет той же обработкой (событие о доставке, значок, вложение) из обычного `UNNotificationServiceExtension`:

<Tabs>
<TabItem label="Swift">

```swift
import UserNotifications
import PushwooshFramework

class NotificationService: UNNotificationServiceExtension {

    override func didReceive(_ request: UNNotificationRequest,
                             withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
        PWNotificationExtensionManager.sharedManager()
            .handleNotificationRequest(request, contentHandler: contentHandler)
    }
}
```

</TabItem>

<TabItem label="Objective-C">

```objective-c
#import "PWNotificationExtensionManager.h"

@interface NotificationService : UNNotificationServiceExtension

@end

@implementation NotificationService

- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request
                   withContentHandler:(void (^)(UNNotificationContent *))contentHandler {
    [[PWNotificationExtensionManager sharedManager] handleNotificationRequest:request
                                                              contentHandler:contentHandler];
}

@end
```

</TabItem>
</Tabs>

## Поделитесь с нами своим мнением

Ваши отзывы помогают нам улучшать наш продукт, поэтому мы будем рады, если вы поделитесь своим мнением о процессе интеграции SDK. Если вы столкнетесь с какими-либо трудностями, пожалуйста, не стесняйтесь поделиться своими мыслями с нами [через эту форму](https://docs.google.com/forms/d/e/1FAIpQLSd_0b8jwn-V_JmoPLIxIFYbHACCQhrzidOZV3ELywoQPXRSxw/viewform).