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

Синтаксис нативных шаблонов In-App

Нативные In-App сообщения отображаются непосредственно SDK. WebView при этом не используется. Вместо страницы index.html ZIP-ресурс содержит файл native-config.json, который описывает сообщение в виде структурированных данных (тип макета, тексты, цвета, изображения, кнопки). SDK считывает этот файл и отрисовывает соответствующее нативное представление, что обеспечивает более плавную анимацию и лучшую производительность по сравнению со встроенной веб-страницей.

В этом руководстве описана схема native-config.json: поля, типы и примеры для каждого типа отображения. О классическом формате на основе HTML читайте в статье Синтаксис шаблонов Rich Media.

Предварительные требования

Anchor link to

Для нативных In-App сообщений требуется:

  • iOS: SDK 7.2.0 или новее (7.2.1+ для баннера, карусели и листа)
  • Android: SDK 6.10.0 или новее (6.10.1+ для баннера, карусели и листа)

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

Поддержка платформ

Anchor link to
Тип отображения
iOS
Android
modal✅ 7.2.0+✅ 6.10.0+
fullscreen✅ 7.2.0+✅ 6.10.0+
stories✅ 7.2.0+✅ 6.10.0+
banner✅ 7.2.1+✅ 6.10.1+
carousel✅ 7.2.1+✅ 6.10.1+
sheet✅ 7.2.1+✅ 6.10.1+
video✅✅ 6.11.0+
pip✅Пока недоступно
scratchcard✅Пока недоступно
spinwheel✅Пока недоступно

Структура шаблона

Anchor link to

Нативный шаблон In-App — это ZIP-архив, такой же, как и обычный шаблон Rich Media, за исключением того, что в корневом каталоге вместо index.html находится файл native-config.json:

<template>.zip
├── native-config.json ← required, layout and content
├── pushwoosh.json ← optional, localization (see below)

Изображения и видео, на которые есть ссылки в native-config.json (image, poster, fallback, url в pip/video), должны быть абсолютными URL-адресами HTTPS. SDK загружает их по сети. Локальные файлы из архива он не считывает.

Сама конфигурация представляет собой единый объект JSON:

{ "displayType": "<type>", "<type>": { /* content block for this type */ } }

displayType выбирает один из десяти форматов, описанных ниже. Объект под соответствующим ключом содержит контент этого формата. Конфигурация с неизвестным displayType, отсутствующим блоком контента или пустым обязательным списком (items для carousel/stories, segments для spinwheel) является недействительной. SDK пропустит ее отображение, чтобы не отрисовывать некорректный макет.

Настройки доставки (даты начала/окончания и ограничение частоты показов) не являются частью native-config.json. Они настраиваются так же, как и для любого другого In-App сообщения, на шаге Настройки отображения кампании.

Кроме того, для ограничения частоты показов нативных In-App сообщений требуется явное согласие на стороне SDK. См. Интеграция SDK.

Цвета

Anchor link to

Каждое значение цвета — это шестнадцатеричная строка CSS: #RGB, #RGBA, #RRGGBB или #RRGGBBAA. Начальный символ # обязателен во всех четырех формах.

Общие строительные блоки

Anchor link to

Эти небольшие объекты повторно используются в нескольких типах отображения.

ПолеТипОбязательноОписание
textstringдаТекстовое содержимое
colorstringдаЦвет текста
{ "text": "Spin for a garage perk", "color": "#FFFFFFFF" }
ПолеТипОбязательноОписание
colorstringдаЦвет рамки
radiusnumberдаРадиус скругления углов в пунктах
{ "color": "#0E72E5FF", "radius": 12 }

Необязательное изображение поверх фонового цвета. Используется в fullscreen и scratchcard.

ПолеТипОбязательноОписание
imagestringнетURL-адрес изображения обложки
backgroundstringдаФоновый цвет, отображаемый под изображением (или вместо него)
{ "image": "https://example.com/cover.jpg", "background": "#1A1A1EFF" }

Различаемое объединение по type:

ВариантПоляОписание
{ "type": "close" }НетЗакрывает In-App сообщение
{ "type": "url", "url": string }url обязательноОткрывает URL или диплинк
{ "type": "url", "url": "pushwoosh://sale" }
ПолеТипОбязательноОписание
textTextдаНадпись на кнопке
backgroundstringдаЦвет заливки кнопки
borderBorderдаРамка кнопки
actionActionдаДействие, выполняемое при нажатии

spinButton (spinwheel) и revealButton (scratchcard) имеют ту же структуру, но без action. Их поведение (вращать колесо, открыть карту) является встроенным.

{
"text": { "text": "Book a test drive", "color": "#FFFFFFFF" },
"background": "#0E72E5FF",
"border": { "color": "#0E72E5FF", "radius": 12 },
"action": { "type": "url", "url": "pushwoosh://sale" }
}

Панель с призом, отображаемая в scratchcard и spinwheel. Действительная награда должна иметь title или code.

ПолеТипОбязательноОписание
titleTextнетЗаголовок награды
messageTextнетОписание награды
codestringнетПромокод, отображаемый с кнопкой копирования
buttonButtonнетКнопка подтверждения с собственным действием
{
"title": { "text": "20% off detailing", "color": "#111111FF" },
"message": { "text": "Valid for any full-detail booking this month.", "color": "#555555FF" },
"code": "APEX20",
"button": {
"text": { "text": "Book detailing", "color": "#FFFFFFFF" },
"background": "#B3227CFF",
"border": { "color": "#B3227CFF", "radius": 12 },
"action": { "type": "url", "url": "pushwoosh://detailing" }
}
}

Типы отображения

Anchor link to

Компактная панель, закрепленная у верхнего или нижнего края экрана.

ПолеТипОбязательноОписание
showClosebooleanдаПоказывать кнопку закрытия (✕)
positiontop | bottomдаКрай экрана
backgroundstringдаЦвет фона панели
imagestringнетМиниатюра слева
titleTextнетОднострочный заголовок, усекаемый многоточием
messageTextнетОсновной текст, до 2 строк
actionActionдаВыполняется при нажатии на саму панель
autoDismissnumberнетАвтоматически закрыть через указанное количество секунд. Опустите, чтобы оставить до закрытия вручную
{
"displayType": "banner",
"banner": {
"showClose": true,
"position": "bottom",
"background": "#4B5057FF",
"image": "https://example.com/thumb.jpg",
"title": { "text": "Alpine A110 just dropped", "color": "#FFFFFFFF" },
"message": { "text": "The featherweight icon — tap to see the build", "color": "#FFFFFFFF" },
"action": { "type": "url", "url": "pushwoosh://product/x6f" },
"autoDismiss": 6
}
}

Полноэкранный набор карточек с возможностью прокрутки и индикаторами страниц.

ПолеТипОбязательноОписание
showClosebooleanдаПоказывать кнопку закрытия (✕)
itemsItem[]даКарточки (не менее 1)

Элемент карусели:

ПолеТипОбязательноОписание
titleTextнетЗаголовок карточки
messageTextнетПодзаголовок карточки
imagestringнетИзображение карточки
actionActionнетВыполняется при нажатии на карточку
{
"displayType": "carousel",
"carousel": {
"showClose": true,
"items": [
{
"image": "https://example.com/card-1.jpg",
"title": { "text": "AMG GT R", "color": "#FFFFFFFF" },
"message": { "text": "585 hp biturbo V8 — just landed", "color": "#FFFFFFFF" },
"action": { "type": "url", "url": "pushwoosh://product/n6fx" }
},
{
"image": "https://example.com/card-2.jpg",
"title": { "text": "Alpine A110", "color": "#FFFFFFFF" },
"message": { "text": "Featherweight icon — limited allocation", "color": "#FFFFFFFF" },
"action": { "type": "url", "url": "pushwoosh://product/x6f" }
}
]
}
}

fullscreen

Anchor link to

Изображение обложки от края до края с текстом и кнопками поверх него.

ПолеТипОбязательноОписание
showClosebooleanдаПоказывать кнопку закрытия (✕)
coverCoverдаФоновое изображение и цвет
titleTextнетЗаголовок
messageTextнетОсновной текст
buttonsButton[]даКнопки внизу (может быть пустым)
{
"displayType": "fullscreen",
"fullscreen": {
"showClose": true,
"cover": { "image": "https://example.com/hero.jpg", "background": "#1A1A1EFF" },
"title": { "text": "Pure Maranello", "color": "#FFFFFFFF" },
"message": { "text": "The prancing horse, reimagined.", "color": "#EBEBEBFF" },
"buttons": [
{
"text": { "text": "Reserve now", "color": "#FFFFFFFF" },
"background": "#0E72E5FF",
"border": { "color": "#0E72E5FF", "radius": 8 },
"action": { "type": "url", "url": "pushwoosh://sale" }
},
{
"text": { "text": "Not now", "color": "#FFFFFFFF" },
"background": "#00000000",
"border": { "color": "#FFFFFF99", "radius": 8 },
"action": { "type": "close" }
}
]
}
}

Карточка, расположенная по центру.

ПолеТипОбязательноОписание
showClosebooleanдаПоказывать кнопку закрытия (✕)
dimBackgroundbooleanдаЗатемнять экран за карточкой
backgroundstringдаЦвет фона карточки
imagestringнетИзображение обложки
titleTextнетЗаголовок
messageTextнетОсновной текст
buttonsButton[]даКнопки под текстом (может быть пустым)
{
"displayType": "modal",
"modal": {
"showClose": true,
"dimBackground": true,
"background": "#FFFFFFFF",
"image": "https://example.com/cover.jpg",
"title": { "text": "The GT R has landed", "color": "#4B5057FF" },
"message": { "text": "585 hp — now in the showroom.", "color": "#4B5057FF" },
"buttons": [
{
"text": { "text": "Book a test drive", "color": "#FFFFFFFF" },
"background": "#0E72E5FF",
"border": { "color": "#0E72E5FF", "radius": 12 },
"action": { "type": "url", "url": "pushwoosh://sale" }
},
{
"text": { "text": "Not now", "color": "#4B5057FF" },
"background": "#FFFFFFFF",
"border": { "color": "#4B5057FF", "radius": 12 },
"action": { "type": "close" }
}
]
}
}

Плавающее окно с видео в режиме «картинка в картинке», закрепленное в углу экрана.

ПолеТипОбязательноОписание
showClosebooleanдаПоказывать кнопку закрытия (✕)
positionbottom-right | bottom-left | top-right | top-leftдаУгол экрана
loopbooleanдаЗациклить воспроизведение
mutedbooleanдаНачать с выключенным звуком
urlstringдаURL-адрес видео
posterstringнетПостер, отображаемый до начала воспроизведения
fallbackstringнетИзображение, отображаемое, если видео не удалось воспроизвести
widthnumberдаШирина окна в процентах от ширины экрана, в диапазоне 15–70
aspectRationumberдаСоотношение высоты и ширины окна
borderRadiusnumberнетРадиус скругления углов окна в пунктах
actionActionнетВыполняется при нажатии на само окно

На pip нет настраиваемых кнопок. Элементы управления окном (развернуть на весь экран, выключить звук, закрыть) предоставляются системой.

{
"displayType": "pip",
"pip": {
"showClose": true,
"position": "bottom-right",
"loop": true,
"muted": true,
"url": "https://example.com/teaser.mp4",
"poster": "https://example.com/poster.jpg",
"width": 40,
"aspectRatio": 0.5625,
"action": { "type": "url", "url": "pushwoosh://product/x6f" }
}
}

scratchcard

Anchor link to

Карточка с наградой, скрытой под стираемым слоем.

ПолеТипОбязательноОписание
showClosebooleanдаПоказывать кнопку закрытия (✕)
backgroundstring | string[]даЦвет фона карточки или точки градиента
revealThresholdnumberдаДоля слоя, которую необходимо стереть (0–1), прежде чем появится награда
coverCoverдаСтираемый слой. Без image на фоновом цвете отображается подсказка «сотрите здесь»
revealButtonButton (no action)нетКнопка «Показать сразу»
titleTextнетЗаголовок
messageTextнетОсновной текст
rewardRewardдаПриз, скрытый под слоем
{
"displayType": "scratchcard",
"scratchcard": {
"showClose": true,
"background": ["#3A1C71FF", "#B3227CFF", "#E0503AFF"],
"revealThreshold": 0.55,
"cover": { "background": "#C9CDD6FF" },
"revealButton": {
"text": { "text": "Reveal without scratching", "color": "#3A1C71FF" },
"background": "#F2DFF5FF",
"border": { "color": "#F2DFF5FF", "radius": 10 }
},
"title": { "text": "Your loyalty reward", "color": "#FFFFFFFF" },
"message": { "text": "Scratch the foil to reveal this week's garage perk.", "color": "#F2DFF5FF" },
"reward": {
"title": { "text": "20% off detailing", "color": "#111111FF" },
"message": { "text": "Valid for any full-detail booking this month.", "color": "#555555FF" },
"code": "APEX20",
"button": {
"text": { "text": "Book detailing", "color": "#FFFFFFFF" },
"background": "#B3227CFF",
"border": { "color": "#B3227CFF", "radius": 12 },
"action": { "type": "url", "url": "pushwoosh://detailing" }
}
}
}
}

Карточка, закрепленная у нижнего края, с маркером для перетаскивания.

ПолеТипОбязательноОписание
showClosebooleanдаПоказывать кнопку закрытия (✕)
dimBackgroundbooleanдаЗатемнять экран за карточкой
backgroundstringдаЦвет фона карточки
imagestringнетИзображение обложки
titleTextнетЗаголовок
messageTextнетОсновной текст
buttonsButton[]даКнопки под текстом (может быть пустым)
{
"displayType": "sheet",
"sheet": {
"showClose": true,
"dimBackground": true,
"background": "#FFFFFFFF",
"image": "https://example.com/cover.jpg",
"title": { "text": "Your quote is ready", "color": "#000000FF" },
"message": { "text": "Guaranteed buyout for your A110: $68,500.", "color": "#000000FF" },
"buttons": [
{
"text": { "text": "Get guaranteed quote", "color": "#FFFFFFFF" },
"background": "#0E72E5FF",
"border": { "color": "#0E72E5FF", "radius": 12 },
"action": { "type": "url", "url": "pushwoosh://sale" }
}
]
}
}

Колесо фортуны со взвешенными сегментами и центральной кнопкой.

ПолеТипОбязательноОписание
showClosebooleanдаПоказывать кнопку закрытия (✕)
backgroundstring | string[]даЦвет фона карточки или точки градиента
winIndexnumberдаИндекс (начиная с 0) выигрышного сегмента
spinButtonButton (no action)даЦентральная кнопка
titleTextнетЗаголовок
messageTextнетОсновной текст
rewardRewardдаНаграда за выигрышный спин (резервный вариант для сегментов без собственной награды)
loseTitleTextнетЗаголовок, отображаемый при проигрыше
segmentsSegment[]даСегменты колеса (SDK ожидает 2–12)

Сегмент:

ПолеТипОбязательноОписание
messageTextдаНадпись на сегменте
colorstringнетЦвет сегмента. Опустите, чтобы использовать резервную палитру, применяемую по всему колесу
weightnumberдаОтносительный размер сегмента
rewardRewardнетНаграда для конкретного сегмента
{
"displayType": "spinwheel",
"spinwheel": {
"showClose": true,
"background": ["#1B1B46FF", "#5B2B8FFF", "#B0338AFF"],
"winIndex": 1,
"spinButton": {
"text": { "text": "SPIN", "color": "#1B1B46FF" },
"background": "#F2C94CFF",
"border": { "color": "#D9A02BFF", "radius": 36 }
},
"title": { "text": "Spin for a garage perk", "color": "#FFFFFFFF" },
"message": { "text": "One spin — every slice wins this week.", "color": "#E3D9F2FF" },
"reward": {
"title": { "text": "You won a garage perk!", "color": "#FFFFFFFF" },
"code": "APEXPERK",
"button": {
"text": { "text": "Claim", "color": "#FFFFFFFF" },
"background": "#5B2B8FFF",
"border": { "color": "#5B2B8FFF", "radius": 12 },
"action": { "type": "close" }
}
},
"segments": [
{ "message": { "text": "5% off", "color": "#FFFFFFFF" }, "color": "#5856D6FF", "weight": 1 },
{
"message": { "text": "20% off", "color": "#FFFFFFFF" },
"color": "#30B0C7FF",
"weight": 1,
"reward": {
"title": { "text": "20% off your next service", "color": "#FFFFFFFF" },
"code": "SPIN20",
"button": {
"text": { "text": "Claim service deal", "color": "#FFFFFFFF" },
"background": "#30B0C7FF",
"border": { "color": "#30B0C7FF", "radius": 12 },
"action": { "type": "url", "url": "pushwoosh://service" }
}
}
},
{ "message": { "text": "Free wash", "color": "#FFFFFFFF" }, "color": "#FF2D55FF", "weight": 1 }
]
}
}

Полноэкранные слайды с индикаторами выполнения вверху, похожие на истории в социальных сетях.

ПолеТипОбязательноОписание
showClosebooleanдаПоказывать кнопку закрытия (✕)
loopbooleanдаНачать с первого слайда после последнего
itemsItem[]даСлайды (не менее 1)

Элемент историй:

ПолеТипОбязательноОписание
titleTextнетЗаголовок
messageTextнетПодзаголовок
imagestringнетФоновое изображение слайда
buttonsButton[]даКнопки призыва к действию внизу (может быть пустым)
durationnumberдаПродолжительность слайда в секундах
{
"displayType": "stories",
"stories": {
"showClose": true,
"loop": false,
"items": [
{
"image": "https://example.com/slide-1.jpg",
"title": { "text": "AMG GT R", "color": "#FFFFFFFF" },
"message": { "text": "The Green Hell special", "color": "#FFFFFFFF" },
"buttons": [
{
"text": { "text": "Configure yours", "color": "#FFFFFFFF" },
"background": "#0F0F0FFF",
"border": { "color": "#0F0F0FFF", "radius": 26 },
"action": { "type": "url", "url": "pushwoosh://product/n6fx" }
}
],
"duration": 4
},
{
"image": "https://example.com/slide-2.jpg",
"title": { "text": "Alpine A110", "color": "#FFFFFFFF" },
"message": { "text": "The featherweight legend, reborn", "color": "#FFFFFFFF" },
"buttons": [],
"duration": 4
}
]
}
}

Полноэкранное видео с текстом и кнопками поверх него.

ПолеТипОбязательноОписание
showClosebooleanдаПоказывать кнопку закрытия (✕)
loopbooleanдаЗациклить воспроизведение
mutedbooleanдаНачать с выключенным звуком
urlstringдаURL-адрес видео (HLS или MP4)
posterstringнетПостер, отображаемый до начала воспроизведения
fallbackstringнетИзображение, отображаемое, если видео не удалось воспроизвести
titleTextнетЗаголовок
messageTextнетОсновной текст
buttonsButton[]даКнопки призыва к действию внизу (может быть пустым)
{
"displayType": "video",
"video": {
"showClose": true,
"loop": true,
"muted": true,
"url": "https://example.com/reveal.mp4",
"poster": "https://example.com/poster.jpg",
"title": { "text": "The reveal", "color": "#FFFFFFFF" },
"message": { "text": "Watch it move before anyone else.", "color": "#EBEBEBFF" },
"buttons": [
{
"text": { "text": "Shop the lineup", "color": "#FFFFFFFF" },
"background": "#0E72E5FF",
"border": { "color": "#0E72E5FF", "radius": 14 },
"action": { "type": "url", "url": "pushwoosh://sale" }
}
]
}
}

Локализация

Anchor link to

Нативные In-App сообщения используют тот же механизм локализации, что и HTML Rich Media: строковые значения в native-config.json могут содержать плейсхолдеры {{key|type|default}}, а переводы находятся в файле pushwoosh.json рядом с ним, в том же формате, который описан в разделе Добавление pushwoosh.json. Плейсхолдер может находиться в любом строковом поле на любой глубине (заголовок, надпись на кнопке, URL-адрес изображения, URL-адрес действия).

Динамический контент

Anchor link to

Текстовые поля — title, message, text кнопки, reward.title/reward.message и message элемента/сегмента — также принимают динамический контент и синтаксис Liquid: те же сокращения {Tag|modifier|default} и теги Liquid {% %}/{{ }}, которые используются в пушах и email-сообщениях. Pushwoosh обрабатывает их для каждого получателя перед отправкой сообщения, так же, как и для пушей и email.

При создании шаблона в редакторе нативных In-App сообщений в Control Panel вставленные токены отображаются в виде чипов в предпросмотре, а кнопка Сохранить блокируется, если Liquid в текстовом поле не может быть обработан.

Интеграция SDK

Anchor link to

После добавления в приложение модуля SDK для нативных In-App сообщений они будут отображаться автоматически. Для показа сообщений, вызванных пушем, Customer Journey, postEvent или из папки «Входящие», не требуется дополнительный код.

SDK также предоставляет небольшой API для ручного управления:

  • iOS: Pushwoosh.inApp (модуль PushwooshInApp)
  • Android: PushwooshInAppUi (модуль pushwoosh-inapp-ui)
ВозможностьiOSAndroid
Показать конфигурацию напрямую (тестирование/ручное использование)Pushwoosh.inApp.present(config)PushwooshInAppUi.present(configJson)
Наблюдать за жизненным циклом и кликамиdelegate (PWInAppMessageDelegate)delegate (InAppMessageDelegate)
Проверить, отображается ли что-то на экранеisPresentingisPresenting
Закрыть то, что отображается в данный моментdismiss()dismiss()
Приостановить / возобновить отображениеisPausedisPaused
Применить ограничение maxDisplays / cooldownsetFrequencyCapEnabled(_:)setFrequencyCapEnabled(...)

Колбэки делегата (все вызываются в основном потоке): shouldDisplay (верните false, чтобы скрыть одно сообщение до его показа, например, на экране оформления заказа), willPresent, didPresent, didClose и clickedAction (вызывается, когда пользователь нажимает на действие url, перед открытием URL).

Для iOS дополнительно сообщаются rewardRevealed и rewardClaimed для геймифицированных шаблонов scratchcard и spinwheel.

// iOS
Pushwoosh.inApp.delegate = self
Pushwoosh.inApp.setFrequencyCapEnabled(true)
// Android
PushwooshInAppUi.delegate = this
PushwooshInAppUi.setFrequencyCapEnabled(true)