# Введение в push-уведомления для iOS

Вводный диалог для push-уведомлений — это диалог предварительного согласия, который вы показываете **перед** системным запросом iOS на разрешение push-уведомлений. iOS показывает системный запрос только один раз за установку — если пользователь нажмет **Не разрешать**, push-уведомления будут потеряны, пока он не включит их снова в Настройках. Вводный диалог позволяет сначала объяснить ценность уведомлений и запросить разрешение в нужный момент, чтобы вы использовали одноразовый системный запрос на пользователях, которые уже сказали «да».

Доступно с версии 7.1.1. Вводный диалог является частью `PushwooshFramework`; дополнительный модуль не требуется.

<figure style={{ textAlign: "center" }}>
  <img
    src="/ios-push-primer-1.webp"
    alt="Вводный диалог, отображаемый перед системным запросом на разрешение"
    style={{ display: "block", margin: "0 auto", maxWidth: "300px", height: "auto" }}
    width="300"
  />
  <figcaption>Вводный диалог, отображаемый перед системным запросом iOS на разрешение</figcaption>
</figure>

## Как это работает

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

- **Не определено** — показывает вводный диалог; при согласии запускает системный запрос на разрешение.
- **Разрешено или предварительно** — молча подавляет вводный диалог (ничего не показывается).
- **Отклонено** — показывает вводный диалог; при согласии перенаправляет пользователя в настройки уведомлений приложения (когда включен `fallbackToSettings`).

Вы решаете, **когда** вызывать вводный диалог (например, после процесса адаптации или после ключевого действия). SDK не навязывает никакого собственного времени, за исключением необязательного ограничения `minInterval`, описанного ниже.

## Базовое использование

Настройте вводный диалог с помощью текучего конструктора и вызовите `present`. Минимальная настройка требует заголовок, сообщение и названия двух кнопок.

<Tabs>
<TabItem label="Swift">
```swift
import PushwooshFramework

Pushwoosh.configure.pushPrimer
    .title("Будьте в курсе")
    .message("Получайте уведомления о скидках и обновлениях заказов первыми")
    .acceptButton("Включить уведомления")
    .declineButton("Не сейчас")
    .present()
```
</TabItem>
</Tabs>

<Aside type="note">
Вызывайте вводный диалог после того, как интерфейс приложения появится на экране (например, через короткое время после запуска или на определенном этапе вашего потока), чтобы он мог отобразиться поверх вашего интерфейса.
</Aside>

## Стили и позиции

Используйте `style`, чтобы выбрать между системным оповещением и пользовательским листом, и `position`, чтобы разместить пользовательский лист. Каждая позиция имеет свой собственный дизайн по умолчанию.

| Значение | Описание |
|-------|-------------|
| `.alert` | Системный `UIAlertController`. Позиция игнорируется. |
| `.sheet` + `.bottom` | Нижний лист, который выдвигается вверх, с элементом для перетаскивания и кнопками во всю ширину (по умолчанию). |
| `.sheet` + `.top` | Компактный баннер, который появляется сверху, как уведомление. |
| `.sheet` + `.center` | Центрированный диалог, который появляется с эффектом масштабирования и затухания. |

<Tabs>
<TabItem label="Swift">
```swift
Pushwoosh.configure.pushPrimer
    .style(.sheet)
    .position(.top)
    .title("Будьте в курсе")
    .message("Получайте уведомления о скидках и обновлениях заказов первыми")
    .acceptButton("Включить уведомления")
    .declineButton("Не сейчас")
    .present()
```
</TabItem>
</Tabs>

<img src="/ios-push-primer-positions.webp" alt="Вводный диалог в нижней, верхней и центральной позициях"/>

## Кастомизация

Все визуальные настройки необязательны — опустите их, чтобы использовать нативные значения по умолчанию, которые адаптируются к светлому и темному режимам.

<Tabs>
<TabItem label="Swift">
```swift
Pushwoosh.configure.pushPrimer
    .style(.sheet)
    .position(.center)
    .title("Будьте в курсе")
    .message("Получайте уведомления о скидках и обновлениях заказов первыми")
    .acceptButton("Включить уведомления")
    .declineButton("Не сейчас")
    .image(UIImage(named: "PrimerHero"))          // локальное изображение или .imageURL("https://…")
    .backgroundColor(.systemBackground)
    .titleColor(.label)
    .messageColor(.secondaryLabel)
    .acceptButtonColor(.systemBlue)
    .acceptButtonTextColor(.white)
    .declineButtonColor(.clear)
    .declineButtonTextColor(.secondaryLabel)
    .cornerRadius(24)
    .buttonCornerRadius(14)
    .buttonBorderColor(.separator)
    .present()
```
</TabItem>
</Tabs>

Справочник по кастомизации:

| Сеттер | Описание |
|--------|-------------|
| `image` / `imageURL` | Локальный `UIImage` или удаленный URL. Отображается в виде круга в центральном и нижнем макетах, и в виде иконки в верхнем баннере. Локальное изображение имеет приоритет над URL. |
| `backgroundColor` | Сплошной цвет фона карточки. |
| `backgroundGradient` | Массив цветов, отображаемый в виде мягкого многоцветного градиента. Переопределяет `backgroundColor`. |
| `titleColor` / `messageColor` | Цвета текста заголовка и сообщения. |
| `acceptButtonColor` / `acceptButtonTextColor` | Цвета фона и текста кнопки принятия. Цвет принятия также окрашивает иконку по умолчанию. |
| `declineButtonColor` / `declineButtonTextColor` | Цвета фона и текста кнопки отклонения. |
| `cornerRadius` | Радиус скругления углов карточки. |
| `buttonCornerRadius` / `buttonBorderColor` | Радиус скругления углов и цвет рамки обеих кнопок. |

<Aside type="note">
Вводный диалог показывает именно те строки, которые вы передаете. Для поддержки нескольких языков передавайте локализованные строки (например, с помощью `NSLocalizedString`).
</Aside>

## Настройки поведения

### Резервный переход в Настройки

По умолчанию, когда уведомления уже отклонены, вводный диалог показывается, и кнопка принятия переводит пользователя в настройки уведомлений приложения. Передайте `false`, чтобы вместо этого полностью подавить вводный диалог в состоянии "отклонено".

```swift
.fallbackToSettings(false)
```

### Частота отображения

По умолчанию у вводного диалога нет встроенного ограничения — он показывается всякий раз, когда вы вызываете `present` (и автоматически подавляется, как только уведомления разрешены). Используйте `minInterval`, чтобы ограничить частоту повторного появления вводного диалога. Время последнего показа сохраняется между запусками.

```swift
.minInterval(7 * 24 * 60 * 60)   // показывать не чаще одного раза в неделю
```

## Обработка результата

Передайте замыкание в `present`, чтобы отреагировать на результат.

<Tabs>
<TabItem label="Swift">
```swift
Pushwoosh.configure.pushPrimer
    .title("Будьте в курсе")
    .message("Получайте уведомления о скидках и обновлениях заказов первыми")
    .acceptButton("Включить уведомления")
    .declineButton("Не сейчас")
    .present { outcome in
        switch outcome {
        case .accepted:            break   // показан, пользователь согласился, запрошен системный диалог
        case .declined:            break   // показан, пользователь отклонил
        case .suppressed:          break   // не показан (уже разрешено или ограничено по частоте)
        case .redirectedToSettings: break  // состояние "отклонено", пользователь перенаправлен в Настройки
        @unknown default:          break
        }
    }
```
</TabItem>
</Tabs>

Окончательный результат системного запроса (состояние "разрешено"/"отклонено" и токен устройства) поступает через обычные обратные вызовы регистрации — вводный диалог повторно использует `registerForPushNotifications` при согласии и не дублирует эту цепочку.

## Ссылки

<CardGrid>
  <LinkCard
    title="Справочник по API iOS SDK"
    description="Полная техническая документация, охватывающая все публичные классы, методы и свойства."
    href="https://pushwoosh.github.io/pushwoosh-ios-sdk/"
  />
  <LinkCard
    title="Настройка iOS SDK"
    description="Другие способы адаптации Pushwoosh iOS SDK для вашего приложения."
    href="/developer/pushwoosh-sdk/ios-sdk/customizing-ios-sdk/"
  />
</CardGrid>