Синтаксис нативных шаблонов 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+ для banner, carousel и sheet)
- Android: SDK 6.10.0 или новее (6.10.1+ для banner, carousel и sheet)
Не все типы отображения пока доступны на обеих платформах. Прежде чем использовать определенный формат, проверьте Поддержку платформ.
Поддержка платформ
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 | ✅ | Пока недоступно |
| 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Эти небольшие объекты повторно используются в нескольких типах отображения.
Текст
Anchor link to| Поле | Тип | Обязательно | Описание |
|---|---|---|---|
text | string | да | Текстовое содержимое |
color | string | да | Цвет текста |
{ "text": "Spin for a garage perk", "color": "#FFFFFFFF" }Граница
Anchor link to| Поле | Тип | Обязательно | Описание |
|---|---|---|---|
color | string | да | Цвет границы |
radius | number | да | Радиус скругления углов в пунктах |
{ "color": "#0E72E5FF", "radius": 12 }Обложка
Anchor link toНеобязательное изображение поверх фонового цвета. Используется в fullscreen и scratchcard.
| Поле | Тип | Обязательно | Описание |
|---|---|---|---|
image | string | нет | URL изображения обложки |
background | string | да | Цвет фона, отображаемый под изображением (или вместо него) |
{ "image": "https://example.com/cover.jpg", "background": "#1A1A1EFF" }Действие
Anchor link toРазличаемое объединение по type:
| Вариант | Поля | Описание |
|---|---|---|
{ "type": "close" } | None | Закрывает In-App сообщение |
{ "type": "url", "url": string } | url required | Открывает URL или диплинк |
{ "type": "url", "url": "pushwoosh://sale" }Кнопка
Anchor link to| Поле | Тип | Обязательно | Описание |
|---|---|---|---|
text | Text | да | Надпись на кнопке |
background | string | да | Цвет заливки кнопки |
border | Border | да | Граница кнопки |
action | Action | да | Действие, выполняемое при нажатии |
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" }}Награда
Anchor link toПанель с призом, отображаемая в scratchcard и spinwheel. Действительная награда имеет title или code.
| Поле | Тип | Обязательно | Описание |
|---|---|---|---|
title | Text | нет | Заголовок награды |
message | Text | нет | Описание награды |
code | string | нет | Промокод, отображаемый с кнопкой копирования |
button | Button | нет | Кнопка подтверждения с собственным действием |
{ "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 tobanner
Anchor link toКомпактная панель, закрепленная у верхнего или нижнего края экрана.
| Поле | Тип | Обязательно | Описание |
|---|---|---|---|
showClose | boolean | да | Показывать кнопку закрытия (✕) |
position | top | bottom | да | Край экрана |
background | string | да | Цвет фона панели |
image | string | нет | Миниатюра слева |
title | Text | нет | Однострочный заголовок, усеченный многоточием |
message | Text | нет | Основной текст, до 2 строк |
action | Action | да | Выполняется при нажатии на саму панель |
autoDismiss | number | нет | Автоматически закрыть через указанное количество секунд. Опустите, чтобы оставить до закрытия вручную |
{ "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 }}carousel
Anchor link toПолноэкранный набор карточек с возможностью пролистывания и точками-индикаторами страниц.
| Поле | Тип | Обязательно | Описание |
|---|---|---|---|
showClose | boolean | да | Показывать кнопку закрытия (✕) |
items | Item[] | да | Карточки (не менее 1) |
Элемент карусели:
| Поле | Тип | Обязательно | Описание |
|---|---|---|---|
title | Text | нет | Заголовок карточки |
message | Text | нет | Подзаголовок карточки |
image | string | нет | Изображение карточки |
action | Action | нет | Выполняется при нажатии на карточку |
{ "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Изображение обложки от края до края с текстом и кнопками поверх него.
| Поле | Тип | Обязательно | Описание |
|---|---|---|---|
showClose | boolean | да | Показывать кнопку закрытия (✕) |
cover | Cover | да | Фоновое изображение и цвет |
title | Text | нет | Заголовок |
message | Text | нет | Основной текст |
buttons | Button[] | да | Кнопки внизу (может быть пустым) |
{ "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" } } ] }}modal
Anchor link toКарточка по центру.
| Поле | Тип | Обязательно | Описание |
|---|---|---|---|
showClose | boolean | да | Показывать кнопку закрытия (✕) |
dimBackground | boolean | да | Затемнить экран за карточкой |
background | string | да | Цвет фона карточки |
image | string | нет | Изображение обложки |
title | Text | нет | Заголовок |
message | Text | нет | Основной текст |
buttons | Button[] | да | Кнопки под текстом (может быть пустым) |
{ "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" } } ] }}Плавающее окно видео «картинка в картинке», закрепленное в углу экрана.
| Поле | Тип | Обязательно | Описание |
|---|---|---|---|
showClose | boolean | да | Показывать кнопку закрытия (✕) |
position | bottom-right | bottom-left | top-right | top-left | да | Угол экрана |
loop | boolean | да | Зациклить воспроизведение |
muted | boolean | да | Начать с выключенным звуком |
url | string | да | URL видео |
poster | string | нет | Постер, отображаемый до начала воспроизведения |
fallback | string | нет | Изображение, отображаемое, если видео не удалось воспроизвести |
width | number | да | Ширина окна в процентах от ширины экрана, в диапазоне 15–70 |
aspectRatio | number | да | Соотношение высоты и ширины окна |
borderRadius | number | нет | Радиус скругления углов окна в пунктах |
action | Action | нет | Выполняется при нажатии на само окно |
На 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Карточка с наградой, скрытой под стираемым слоем фольги.
| Поле | Тип | Обязательно | Описание |
|---|---|---|---|
showClose | boolean | да | Показывать кнопку закрытия (✕) |
background | string | string[] | да | Цвет фона карточки или точки градиента |
revealThreshold | number | да | Доля фольги, которую необходимо стереть (0–1), прежде чем откроется награда |
cover | Cover | да | Слой фольги. Без image на фоновом цвете отображается подсказка «сотрите здесь» |
revealButton | Button (no action) | нет | Кнопка «Открыть сразу» |
title | Text | нет | Заголовок |
message | Text | нет | Основной текст |
reward | Reward | да | Приз, скрытый под фольгой |
{ "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" } } } }}sheet
Anchor link toКарточка, закрепленная у нижнего края, с маркером для перетаскивания.
| Поле | Тип | Обязательно | Описание |
|---|---|---|---|
showClose | boolean | да | Показывать кнопку закрытия (✕) |
dimBackground | boolean | да | Затемнить экран за карточкой |
background | string | да | Цвет фона карточки |
image | string | нет | Изображение обложки |
title | Text | нет | Заголовок |
message | Text | нет | Основной текст |
buttons | Button[] | да | Кнопки под текстом (может быть пустым) |
{ "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" } } ] }}spinwheel
Anchor link toКолесо фортуны со взвешенными сегментами и центральной кнопкой.
| Поле | Тип | Обязательно | Описание |
|---|---|---|---|
showClose | boolean | да | Показывать кнопку закрытия (✕) |
background | string | string[] | да | Цвет фона карточки или точки градиента |
winIndex | number | да | Индекс (начиная с 0) выигрышного сегмента |
spinButton | Button (no action) | да | Центральная кнопка |
title | Text | нет | Заголовок |
message | Text | нет | Основной текст |
reward | Reward | да | Награда за выигрышное вращение (резервный вариант для сегментов без собственной награды) |
loseTitle | Text | нет | Заголовок, отображаемый при проигрыше |
segments | Segment[] | да | Сегменты колеса (SDK ожидает 2–12) |
Сегмент:
| Поле | Тип | Обязательно | Описание |
|---|---|---|---|
message | Text | да | Надпись на сегменте |
color | string | нет | Цвет сегмента. Опустите, чтобы использовать резервную палитру, применяемую по всему колесу |
weight | number | да | Относительный размер сегмента |
reward | Reward | нет | Награда для конкретного сегмента |
{ "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 } ] }}stories
Anchor link toПолноэкранные слайды с индикаторами выполнения вверху, похожие на истории в социальных сетях.
| Поле | Тип | Обязательно | Описание |
|---|---|---|---|
showClose | boolean | да | Показывать кнопку закрытия (✕) |
loop | boolean | да | Начать с первого слайда после последнего |
items | Item[] | да | Слайды (не менее 1) |
Элемент историй:
| Поле | Тип | Обязательно | Описание |
|---|---|---|---|
title | Text | нет | Заголовок |
message | Text | нет | Подзаголовок |
image | string | нет | Фоновое изображение слайда |
buttons | Button[] | да | Кнопки призыва к действию внизу (может быть пустым) |
duration | number | да | Продолжительность слайда в секундах |
{ "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 } ] }}video
Anchor link toПолноэкранное видео с текстом и кнопками поверх него.
| Поле | Тип | Обязательно | Описание |
|---|---|---|---|
showClose | boolean | да | Показывать кнопку закрытия (✕) |
loop | boolean | да | Зациклить воспроизведение |
muted | boolean | да | Начать с выключенным звуком |
url | string | да | URL видео (HLS или MP4) |
poster | string | нет | Постер, отображаемый до начала воспроизведения |
fallback | string | нет | Изображение, отображаемое, если видео не удалось воспроизвести |
title | Text | нет | Заголовок |
message | Text | нет | Основной текст |
buttons | Button[] | да | Кнопки призыва к действию внизу (может быть пустым) |
{ "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 {% %}/{{ }}, которые используются в push-уведомлениях и email-сообщениях. Pushwoosh обрабатывает их для каждого получателя перед отправкой сообщения, так же, как и для push-уведомлений и email.
При создании шаблона в редакторе нативных In-App сообщений в Control Panel вставленные токены отображаются в виде чипов в предпросмотре, а кнопка Сохранить блокируется, если Liquid в текстовом поле не может быть проанализирован.
Интеграция SDK
Anchor link toПосле добавления модуля SDK для нативных In-App сообщений в ваше приложение, сообщения будут отображаться автоматически. Не требуется дополнительный код для показа сообщений, вызванных push-уведомлением, Customer Journey, postEvent или из папки «Входящие».
SDK также предоставляет небольшой API для ручного управления:
- iOS:
Pushwoosh.inApp(модульPushwooshInApp) - Android:
PushwooshInAppUi(модульpushwoosh-inapp-ui)
| Возможность | iOS | Android |
|---|---|---|
| Показать конфигурацию напрямую (тестирование/ручное использование) | Pushwoosh.inApp.present(config) | PushwooshInAppUi.present(configJson) |
| Наблюдать за жизненным циклом и кликами | delegate (PWInAppMessageDelegate) | delegate (InAppMessageDelegate) |
| Проверить, отображается ли что-либо на экране | isPresenting | isPresenting |
| Закрыть то, что отображается в данный момент | dismiss() | dismiss() |
| Приостановить / возобновить отображение | isPaused | isPaused |
Применить ограничение maxDisplays / cooldown | setFrequencyCapEnabled(_:) | setFrequencyCapEnabled(...) |
Колбэки делегата (все вызываются в основном потоке): shouldDisplay (верните false, чтобы скрыть одно сообщение до его показа, например, на экране оформления заказа), willPresent, didPresent, didClose и clickedAction (вызывается, когда пользователь нажимает на действие url, перед открытием URL).
iOS дополнительно сообщает о rewardRevealed и rewardClaimed для геймифицированных шаблонов scratchcard и spinwheel.
// iOSPushwoosh.inApp.delegate = selfPushwoosh.inApp.setFrequencyCapEnabled(true)// AndroidPushwooshInAppUi.delegate = thisPushwooshInAppUi.setFrequencyCapEnabled(true)