Перейти к содержанию

Настройка Pushwoosh InboxKit для iOS

Доступно с iOS SDK 7.0.40.

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

Лента InboxKit, показывающая карточки типа баннер, с подписью, классический, карусель, видео и Apple Wallet

Лента 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

Типы карточек

Anchor link to

InboxKit выбирает макет ячейки для каждого сообщения. Распознаватель по умолчанию считывает 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 и contentclassic, если отсутствует изображение, заголовок или тело
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 пропуска
Карточка-баннер InboxKit
Карточка-баннер
Карточка с подписью InboxKit
Карточка с подписью
Классическая карточка InboxKit
Классическая карточка
Карточка-карусель InboxKit
Карточка-карусель
Видео-карточка InboxKit
Видео-карточка
Карточка Apple Wallet InboxKit
Карточка Apple Wallet

Карточки типа баннер, с подписью и классический управляются стандартными полями сообщения (изображение, заголовок, тело) плюс опциональным массивом buttons — см. Добавление встроенных кнопок CTA. Карточки типа карусель, видео и Apple Wallet несут дополнительные структурированные данные внутри data, которые описаны ниже.

Карточка-карусель

Anchor link to

Карусель отображает несколько изображений из одного сообщения — прокручиваемая галерея с опциональными подписями к каждому слайду и ссылками для перехода. Слайды находятся в data.carousel. Для каждого слайда требуется image; title (наложение подписи) и url (глубокая ссылка, открываемая по нажатию) являются опциональными. Слайд без изображения удаляется; нажатие на слайд без url передается действию по умолчанию для строки сообщения. Отображается не более 5 слайдов — лишние слайды удаляются (слайд без изображения не занимает место). Заголовок title и тело content сообщения обязательны для этого макета; без них карточка упрощается до classic.

POST https://api.pushwoosh.com/json/1.3/createMessage
{
"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 — это опциональное изображение для предварительного просмотра.

POST https://api.pushwoosh.com/json/1.3/createMessage
{
"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 пропуска или устройство не может добавлять пропуски.

POST https://api.pushwoosh.com/json/1.3/createMessage
{
"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:

POST https://api.pushwoosh.com/json/1.3/createMessage
{
"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 автоматически отображает их в ячейках с подписью и классических ячейках:

POST https://api.pushwoosh.com/json/1.3/createMessage
{
"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]
}]
}
}

Каждый объект кнопки имеет следующие поля:

ПолеТипКогда
titlestringОбязательно. Видимая метка кнопки.
urlstringНепустой и корректный URL создает действие openURL. SDK открывает его через UIApplication.shared.open, если ваш делегат не отменяет это действие.
actionstringЯвный токен действия: 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 никогда не выполняет здесь действие по умолчанию
}
}
}