Настройка Pushwoosh InboxKit для iOS
Доступно с iOS SDK 7.0.40.
Pushwoosh InboxKit предоставляет современный экран входящих сообщений на базе UIKit поверх существующего бэкенда для входящих. Шесть стандартных макетов ячеек охватывают распространенные формы карточек с контентом — от простых баннеров до каруселей изображений, встроенного видео и карт Apple Wallet. Встроенные кнопки CTA обрабатывают наиболее частые взаимодействия, а вся поверхность открыта для создания подклассов, если вам нужен индивидуальный дизайн.

Лента InboxKit по умолчанию с карточками типа баннер, с подписью, классический, карусель, видео и Apple Wallet.
Когда использовать InboxKit
Anchor link toИспользуйте InboxKit для любой новой интеграции с iOS. Это рекомендуемая замена для старого модуля PushwooshInboxUI на Objective-C.
InboxKit предоставляет:
- Шесть встроенных типов ячеек — баннер, с подписью, классический, карусель, видео и Apple Wallet — выбираемых для каждого сообщения через
displayTypeв полезной нагрузке или принудительно из кода черезattributes.forceCellKind. Полный список см. в разделе Типы карточек. (Карточка Apple Wallet доступна только для iOS.) - Встроенные кнопки CTA с типизированным перечислением
PushwooshInboxButtonAction(openURL,dismiss,markRead,custom). SDK автоматически обрабатывает первые три; ваш делегат направляетcustomв вашу собственную логику. - Поддержка закрепления: сообщения с
actionParams["pinned"] == trueподнимаются в верхнюю часть ленты и отображают значок булавки. - Свайп для удаления, потянуть для обновления, автоматическая пометка как прочитанное при исчезновении — все это можно переключать через
PushwooshInboxKitAttributes. - Постоянное хранилище: удаления и состояние прочтения сохраняются после перезапуска процесса, даже если сетевой вызов еще не был подтвержден.
- Открытый базовый класс
PushwooshInboxCellдля полностью настраиваемых макетов.
Контракт с сервером не изменился — используются те же бэкенд, полезные нагрузки и инструменты панели управления Pushwoosh для входящих сообщений, что и раньше.
Выберите способ интеграции
Anchor link to- Настройка InboxKit с помощью Swift Package Manager — рекомендуется для новых проектов.
- Настройка InboxKit с помощью CocoaPods — для проектов, уже использующих CocoaPods.
Типы карточек
Anchor link toInboxKit выбирает макет ячейки для каждого сообщения. Распознаватель по умолчанию считывает displayType из полезной нагрузки пуша — поместите его в объект data, который SDK доставляет под actionParams. Если displayType отсутствует, распознаватель прибегает к эвристике: изображение + нет заголовка → баннер, изображение + заголовок + тело → с подписью, в противном случае — классический. Чтобы принудительно установить один макет для всей ленты из кода, установите attributes.forceCellKind.
Каждый расширенный макет корректно упрощается: если обязательное поле отсутствует или имеет неверный формат, карточка возвращается к classic вместо отображения пустого заполнителя (и в лог записывается WARN с причиной). classic является конечным вариантом и отображает все, что несет сообщение; ожидается, что редактор сообщений заполнит его заголовок, тело и иконку.
displayType | Макет | Обязательное поле в полезной нагрузке | Упрощается до |
|---|---|---|---|
banner | Изображение на всю ширину, без текста | image (inbox_image или data.image) | classic при отсутствии изображения |
captioned | Изображение сверху, заголовок + тело снизу | image (inbox_image или data.image), message title и content | classic, если отсутствует изображение, заголовок или тело |
classic | Цветной аватар с инициалами + заголовок + тело | — (ожидаются заголовок, тело и иконка) | — |
carousel | Прокручиваемая галерея из нескольких изображений | message title и content, data.carousel (1–5 слайдов) | classic, если нет слайдов или нет заголовка/тела |
video | Постер со значком воспроизведения, полноэкранный плеер по нажатию | data.video (url + опциональный poster) | classic, если нет дескриптора |
wallet | Кнопка “Добавить в Apple Wallet” (только для iOS) | data.wallet (URL .pkpass) | classic, если нет URL пропуска |






Карточки типа баннер, с подписью и классический управляются стандартными полями сообщения (изображение, заголовок, тело) плюс опциональным массивом buttons — см. Добавление встроенных кнопок CTA. Карточки типа карусель, видео и Apple Wallet несут дополнительные структурированные данные внутри data, которые описаны ниже.
Карточка-карусель
Anchor link toКарусель отображает несколько изображений из одного сообщения — прокручиваемая галерея с опциональными подписями к каждому слайду и ссылками для перехода. Слайды находятся в data.carousel. Для каждого слайда требуется image; title (наложение подписи) и url (глубокая ссылка, открываемая по нажатию) являются опциональными. Слайд без изображения удаляется; нажатие на слайд без url передается действию по умолчанию для строки сообщения. Отображается не более 5 слайдов — лишние слайды удаляются (слайд без изображения не занимает место). Заголовок title и тело content сообщения обязательны для этого макета; без них карточка упрощается до classic.
{ "request": { "application": "XXXXX-XXXXX", "auth": "API_TOKEN", "notifications": [{ "send_date": "now", "ios_title": "New arrivals", "content": "Swipe through this week's drops", "inbox_days": 7, "data": { "displayType": "carousel", "carousel": [ { "image": "https://cdn.example.com/inbox/1.jpg", "title": "New in", "url": "myapp://product/1" }, { "image": "https://cdn.example.com/inbox/2.jpg", "title": "On sale", "url": "myapp://product/2" }, { "image": "https://cdn.example.com/inbox/3.jpg" } ] }, "platforms": [1] }] }}Видео-карточка
Anchor link toВидео-карточка показывает постер с значком воспроизведения; нажатие на него открывает полноэкранный плеер (со звуком, даже если включен беззвучный режим). Дескриптор находится в data.video: url является обязательным и должен быть потоком или файлом http/https; poster — это опциональное изображение для предварительного просмотра.
{ "request": { "application": "XXXXX-XXXXX", "auth": "API_TOKEN", "notifications": [{ "send_date": "now", "ios_title": "Watch the reveal", "content": "Tap to play", "inbox_days": 7, "data": { "displayType": "video", "video": { "url": "https://cdn.example.com/inbox/clip.mp4", "poster": "https://cdn.example.com/inbox/poster.jpg" } }, "platforms": [1] }] }}Карточка Apple Wallet
Anchor link toКарточка Apple Wallet показывает опциональное основное изображение, заголовок и тело над официальной кнопкой Add to Apple Wallet. Нажатие на кнопку загружает .pkpass и представляет системный экран добавления пропусков. Используйте ее для доставки купонов, карт лояльности, билетов или посадочных талонов прямо из входящих. Карточка доступна только для iOS / Mac Catalyst — на других платформах сообщение отображается как классическая карточка.
URL пропуска находится в data.wallet, либо как простая строка, либо как объект с полем pass. Опциональное data.image добавляет основное изображение. Кнопка автоматически скрывается, если нет URL пропуска или устройство не может добавлять пропуски.
{ "request": { "application": "XXXXX-XXXXX", "auth": "API_TOKEN", "notifications": [{ "send_date": "now", "ios_title": "Your loyalty card is ready", "content": "Add it to Apple Wallet in one tap", "inbox_days": 7, "data": { "displayType": "wallet", "image": "https://cdn.example.com/inbox/loyalty.png", "wallet": "https://passes.example.com/v1/passes/pass.com.example.loyalty/abc123?token=…" }, "platforms": [1] }] }}Результат сообщается вашему делегату:
extension MyInboxHost: PushwooshInboxKitDelegate {
func inboxKit(_ vc: PushwooshInboxKitViewController, didAddWalletPassFor message: PWInboxMessageProtocol) { // Пропуск теперь в Wallet пользователя — при желании можно показать подтверждение. }
func inboxKit(_ vc: PushwooshInboxKitViewController, didFailToAddWalletPassFor message: PWInboxMessageProtocol, error: Error?) { // Загрузка не удалась — можно показать кнопку повтора, записать в лог и т.д. }}Оба колбэка являются опциональными (они имеют пустые реализации по умолчанию). Отмена пользователем системного экрана не является ни успехом, ни неудачей, поэтому в этом случае колбэк не вызывается.
Доступность
Anchor link toЯчейки InboxKit готовы к работе с VoiceOver “из коробки”. Карточки типа баннер, с подписью и классический предоставляют свой заголовок, тело и дату через соответствующие метки, а встроенные кнопки CTA зачитывают свои собственные заголовки. Расширенные карточки добавляют явную семантику:
- Видео — постер представлен как единый элемент кнопки с меткой “Play video” (свойства
.button+.startsMediaSession), поэтому VoiceOver объявляет его как элемент управления медиа, а не простое изображение. - Карусель — каждый слайд является элементом кнопки, чья метка доступности — это подпись слайда или “Slide”, если подписи нет. Индикатор страниц объявляет текущую позицию как “n из total”.
- Apple Wallet — кнопка Add to Apple Wallet является стандартной кнопкой Apple
PKAddPassButton, которая имеет свою собственную локализованную метку VoiceOver.
Для UI-тестирования и автоматизации установлены два стабильных accessibilityIdentifier: inboxkit.video.play на постере видео и inboxkit.wallet.add на кнопке Wallet.
Чтение пользовательских данных из сообщения
Anchor link toЧтобы пуш появился во входящих, запрос createMessage в Messages API должен включать inbox_image, inbox_date или inbox_days — без одного из этих полей пуш доставляется как обычное уведомление и никогда не попадает в ленту входящих. Произвольные пользовательские данные помещаются под ключ data, который SDK доставляет клиенту как параметр u:
{ "request": { "application": "XXXXX-XXXXX", "auth": "API_TOKEN", "notifications": [{ "send_date": "now", "ios_title": "Summer sale", "content": "30% off everything — limited time only", "inbox_image": "https://cdn.example.com/inbox/summer.png", "inbox_days": 7, "data": { "displayType": "captioned", "promo_id": "SUMMER2026", "screen": "promo_details" }, "platforms": [1] }] }}SDK предоставляет этот объект в сообщении входящих через actionParams. Считайте его из делегата, когда пользователь нажимает на строку или встроенную кнопку CTA:
extension MyInboxHost: PushwooshInboxKitDelegate {
func inboxKit(_ vc: PushwooshInboxKitViewController, didSelect message: PWInboxMessageProtocol) -> Bool { guard let params = message.actionParams as? [String: Any] else { return true }
// Пользовательский объект `data` приходит под ключом "u" — // либо как вложенный словарь, либо как строка в формате JSON, // в зависимости от того, как была сформирована полезная нагрузка. let custom: [String: Any]? = { if let dict = params["u"] as? [String: Any] { return dict } if let raw = params["u"] as? String, let bytes = raw.data(using: .utf8), let parsed = try? JSONSerialization.jsonObject(with: bytes) as? [String: Any] { return parsed } return nil }()
if let promoId = custom?["promo_id"] as? String { navigateToPromo(promoId) return false // мы обработали нажатие; SDK не должен выполнять действие по умолчанию } return true }}Тот же поиск actionParams["u"] работает внутри inboxKit(_:didTapButton:onMessage:) для встроенных кнопок CTA. Для типизированных случаев CTA (openURL, dismiss, markRead) SDK уже выполняет действие по умолчанию — верните true, чтобы сохранить это поведение, или false, чтобы подавить его и выполнить свое собственное.
Добавление встроенных кнопок CTA
Anchor link toСообщение может содержать до трех встроенных кнопок призыва к действию. Кнопки находятся вместе с другими пользовательскими данными внутри data в виде массива buttons. SDK автоматически отображает их в ячейках с подписью и классических ячейках:
{ "request": { "application": "XXXXX-XXXXX", "auth": "API_TOKEN", "notifications": [{ "send_date": "now", "ios_title": "New promo card", "content": "Tap a button to claim or save", "inbox_image": "https://cdn.example.com/inbox/promo.png", "inbox_days": 7, "data": { "displayType": "captioned", "promo_id": "SUMMER2026", "buttons": [ { "title": "Claim", "url": "https://example.com/promo/SUMMER2026" }, { "title": "Read", "action": "markRead" }, { "title": "Save", "action": "custom", "tag": "save_promo" } ] }, "platforms": [1] }] }}Каждый объект кнопки имеет следующие поля:
| Поле | Тип | Когда |
|---|---|---|
title | string | Обязательно. Видимая метка кнопки. |
url | string | Непустой и корректный URL создает действие openURL. SDK открывает его через UIApplication.shared.open, если ваш делегат не отменяет это действие. |
action | string | Явный токен действия: dismiss (удаляет сообщение из ленты), markRead (помечает сообщение как прочитанное) или custom (обрабатывается хостом). Регистронезависимый. |
| Что-либо еще | any | Когда action равно custom, каждый ключ в объекте кнопки, кроме title и action, передается вашему делегату в качестве пользовательской полезной нагрузки — договоритесь с маркетологом о ключе (например, tag) и выполняйте действия на его основе. |
Приоритет разрешения: сначала явный токен action, затем url, если он не пуст, в противном случае кнопка попадает в custom, неся полную полезную нагрузку (минус title и action).
Перехватывайте нажатия из вашего делегата. Свойство button.action является типизированным перечислением PushwooshInboxButtonAction:
extension MyInboxHost: PushwooshInboxKitDelegate {
func inboxKit(_ vc: PushwooshInboxKitViewController, didTapButton button: PushwooshInboxButton, onMessage message: PWInboxMessageProtocol) -> Bool { switch button.action { case .openURL(let url): // Поведение по умолчанию подходит — пусть SDK откроет URL. return true
case .dismiss, .markRead: // SDK обрабатывает оба случая. Верните false, если хотите переопределить. return true
case .custom(let payload): // Пользовательская кнопка, определенная маркетологом. Выполните действие на основе ключа, о котором вы договорились. if let tag = payload["tag"] as? String { switch tag { case "save_promo": saveCurrentPromoLocally(message: message) default: break } } return true // игнорируется для custom — SDK никогда не выполняет здесь действие по умолчанию } }}