Sintaxis de plantillas nativas in-app
Los in-apps nativos son renderizados directamente por el SDK. No se utiliza ningún WebView. En lugar de una página index.html, el recurso ZIP lleva un archivo native-config.json que describe el mensaje como datos estructurados (tipo de diseño, textos, colores, imágenes, botones). El SDK lee este archivo y dibuja la vista nativa correspondiente, lo que proporciona animaciones más fluidas y un mejor rendimiento que una página web incrustada.
Esta guía documenta el esquema de native-config.json: campos, tipos y ejemplos para cada tipo de visualización. Para el formato clásico basado en HTML, consulte Sintaxis de plantillas de Rich Media.
Requisitos previos
Anchor link toLos in-apps nativos requieren:
- iOS: SDK 7.2.0 o posterior (7.2.1+ para banner, carrusel y hoja)
- Android: SDK 6.10.0 o posterior (6.10.1+ para banner, carrusel y hoja)
No todos los tipos de visualización están disponibles en ambas plataformas todavía. Consulte Soporte de plataforma antes de depender de un formato específico.
Soporte de plataforma
Anchor link to| Tipo de visualización | 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 | ✅ | Aún no disponible |
| scratchcard | ✅ | Aún no disponible |
| spinwheel | ✅ | Aún no disponible |
Estructura de la plantilla
Anchor link toUna plantilla nativa in-app es un archivo ZIP, igual que una plantilla de Rich Media normal, excepto que la raíz contiene un archivo native-config.json en lugar de index.html:
<template>.zip├── native-config.json ← requerido, diseño y contenido├── pushwoosh.json ← opcional, localización (ver más abajo)Las imágenes y videos referenciados desde native-config.json (image, poster, fallback, url en pip/video) deben ser URLs HTTPS absolutas. El SDK los carga a través de la red. No lee archivos locales del archivo.
La configuración en sí es un único objeto JSON:
{ "displayType": "<type>", "<type>": { /* bloque de contenido para este tipo */ } }displayType selecciona uno de los diez formatos a continuación. El objeto bajo la clave correspondiente contiene el contenido de ese formato. Una configuración con un displayType desconocido, un bloque de contenido faltante o una lista requerida vacía (items para carousel/stories, segments para spinwheel) no es válida. El SDK omite mostrarla en lugar de renderizar un diseño roto.
Los ajustes de entrega (fechas de inicio/fin y limitación de frecuencia) no forman parte de native-config.json. Se configuran de la misma manera que para cualquier otro in-app, en el paso de Ajustes de visualización de la campaña.
La limitación de frecuencia necesita adicionalmente una activación explícita del lado del SDK para tener efecto en los in-apps nativos. Consulte Integración del SDK.
Colores
Anchor link toCada valor de color es una cadena hexadecimal de CSS: #RGB, #RGBA, #RRGGBB o #RRGGBBAA. El # inicial es obligatorio en las cuatro formas.
Bloques de construcción compartidos
Anchor link toEstos objetos más pequeños se reutilizan en varios tipos de visualización.
Texto
Anchor link to| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
text | string | sí | El contenido del texto |
color | string | sí | Color del texto |
{ "text": "Spin for a garage perk", "color": "#FFFFFFFF" }Borde
Anchor link to| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
color | string | sí | Color del borde |
radius | number | sí | Radio de la esquina, en puntos |
{ "color": "#0E72E5FF", "radius": 12 }Cubierta
Anchor link toUna imagen opcional sobre un color de fondo. Usado por fullscreen y scratchcard.
| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
image | string | no | URL de la imagen de cubierta |
background | string | sí | Color de fondo que se muestra debajo (o en lugar de) la imagen |
{ "image": "https://example.com/cover.jpg", "background": "#1A1A1EFF" }Acción
Anchor link toUna unión discriminada en type:
| Variante | Campos | Descripción |
|---|---|---|
{ "type": "close" } | Ninguno | Cierra el in-app |
{ "type": "url", "url": string } | url requerido | Abre una URL o un deep link |
{ "type": "url", "url": "pushwoosh://sale" }Botón
Anchor link to| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
text | Text | sí | Etiqueta del botón |
background | string | sí | Color de relleno del botón |
border | Border | sí | Borde del botón |
action | Action | sí | Acción que se activa al tocar |
spinButton (spinwheel) y revealButton (scratchcard) usan la misma forma sin action. Su comportamiento (girar la rueda, revelar la tarjeta) está incorporado.
{ "text": { "text": "Book a test drive", "color": "#FFFFFFFF" }, "background": "#0E72E5FF", "border": { "color": "#0E72E5FF", "radius": 12 }, "action": { "type": "url", "url": "pushwoosh://sale" }}Recompensa
Anchor link toEl panel de premios que muestran scratchcard y spinwheel. Una recompensa válida tiene un title o un code.
| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
title | Text | no | Título de la recompensa |
message | Text | no | Descripción de la recompensa |
code | string | no | Código promocional, renderizado con un botón de copiar |
button | Button | no | Botón de confirmación con su propia acción |
{ "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" } }}Tipos de visualización
Anchor link tobanner
Anchor link toUna barra compacta anclada al borde superior o inferior de la pantalla.
| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
showClose | boolean | sí | Mostrar un botón de cierre (✕) |
position | top | bottom | sí | Borde de la pantalla |
background | string | sí | Color de fondo de la barra |
image | string | no | Miniatura a la izquierda |
title | Text | no | Título de una sola línea, truncado con puntos suspensivos |
message | Text | no | Texto del cuerpo, hasta 2 líneas |
action | Action | sí | Se activa cuando se toca la propia barra |
autoDismiss | number | no | Cerrar automáticamente después de este número de segundos. Omitir para mantenerlo hasta que se cierre |
{ "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 toUn conjunto de tarjetas a pantalla completa que se pueden deslizar con puntos indicadores de página.
| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
showClose | boolean | sí | Mostrar un botón de cierre (✕) |
items | Item[] | sí | Tarjetas (al menos 1) |
Elemento del carrusel:
| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
title | Text | no | Título de la tarjeta |
message | Text | no | Subtítulo de la tarjeta |
image | string | no | Imagen de la tarjeta |
action | Action | no | Se activa cuando se toca la tarjeta |
{ "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 toUna imagen de cubierta de borde a borde con texto y botones encima.
| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
showClose | boolean | sí | Mostrar un botón de cierre (✕) |
cover | Cover | sí | Imagen y color de fondo |
title | Text | no | Título |
message | Text | no | Texto del cuerpo |
buttons | Button[] | sí | Botones en la parte inferior (puede estar vacío) |
{ "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 toUna tarjeta centrada.
| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
showClose | boolean | sí | Mostrar un botón de cierre (✕) |
dimBackground | boolean | sí | Atenuar la pantalla detrás de la tarjeta |
background | string | sí | Color de fondo de la tarjeta |
image | string | no | Imagen de cubierta |
title | Text | no | Título |
message | Text | no | Texto del cuerpo |
buttons | Button[] | sí | Botones debajo del texto (puede estar vacío) |
{ "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" } } ] }}Una ventana de video flotante de imagen en imagen anclada a una esquina de la pantalla.
| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
showClose | boolean | sí | Mostrar un botón de cierre (✕) |
position | bottom-right | bottom-left | top-right | top-left | sí | Esquina de la pantalla |
loop | boolean | sí | Repetir la reproducción |
muted | boolean | sí | Empezar silenciado |
url | string | sí | URL del video |
poster | string | no | Póster que se muestra antes de que comience la reproducción |
fallback | string | no | Imagen que se muestra si el video no se puede reproducir |
width | number | sí | Ancho de la ventana como porcentaje del ancho de la pantalla, limitado a 15–70 |
aspectRatio | number | sí | Relación altura-ancho de la ventana |
borderRadius | number | no | Radio de la esquina de la ventana, en puntos |
action | Action | no | Se activa cuando se toca la propia ventana |
No hay botones configurables en pip. Los controles de la ventana (expandir a pantalla completa, silenciar, cerrar) son proporcionados por el sistema.
{ "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 toUna tarjeta con la recompensa oculta bajo una capa de lámina rascable.
| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
showClose | boolean | sí | Mostrar un botón de cierre (✕) |
background | string | string[] | sí | Color de fondo de la tarjeta, o paradas de gradiente |
revealThreshold | number | sí | Fracción de la lámina que debe rascarse (0–1) antes de que se revele la recompensa |
cover | Cover | sí | La capa de lámina. Sin una image, se muestra una pista de “rasca aquí” en el color de fondo |
revealButton | Button (no action) | no | Botón “Revelar instantáneamente” |
title | Text | no | Título |
message | Text | no | Texto del cuerpo |
reward | Reward | sí | El premio oculto bajo la lámina |
{ "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 toUna tarjeta fijada al borde inferior, con un asa para arrastrar.
| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
showClose | boolean | sí | Mostrar un botón de cierre (✕) |
dimBackground | boolean | sí | Atenuar la pantalla detrás de la hoja |
background | string | sí | Color de fondo de la hoja |
image | string | no | Imagen de cubierta |
title | Text | no | Título |
message | Text | no | Texto del cuerpo |
buttons | Button[] | sí | Botones debajo del texto (puede estar vacío) |
{ "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 toUna rueda de la fortuna con segmentos ponderados y un botón central.
| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
showClose | boolean | sí | Mostrar un botón de cierre (✕) |
background | string | string[] | sí | Color de fondo de la tarjeta, o paradas de gradiente |
winIndex | number | sí | Índice (base 0) del segmento ganador |
spinButton | Button (no action) | sí | Botón central |
title | Text | no | Título |
message | Text | no | Texto del cuerpo |
reward | Reward | sí | Recompensa por el giro ganador (alternativa para segmentos sin la suya propia) |
loseTitle | Text | no | Título que se muestra en una pérdida |
segments | Segment[] | sí | Segmentos de la rueda (el SDK espera 2–12) |
Segmento:
| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
message | Text | sí | Etiqueta del segmento |
color | string | no | Color del segmento. Omitir para una paleta alternativa aplicada alrededor de la rueda |
weight | number | sí | Tamaño relativo del segmento |
reward | Reward | no | Recompensa específica del segmento |
{ "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 toDiapositivas a pantalla completa con barras de progreso en la parte superior, similar a las historias de las redes sociales.
| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
showClose | boolean | sí | Mostrar un botón de cierre (✕) |
loop | boolean | sí | Reiniciar desde la primera diapositiva después de la última |
items | Item[] | sí | Diapositivas (al menos 1) |
Elemento de las historias:
| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
title | Text | no | Título |
message | Text | no | Subtítulo |
image | string | no | Imagen de fondo de la diapositiva |
buttons | Button[] | sí | Botones de CTA en la parte inferior (puede estar vacío) |
duration | number | sí | Duración de la diapositiva, en segundos |
{ "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 toVideo a pantalla completa con texto y botones encima.
| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
showClose | boolean | sí | Mostrar un botón de cierre (✕) |
loop | boolean | sí | Repetir la reproducción |
muted | boolean | sí | Empezar silenciado |
url | string | sí | URL del video (HLS o MP4) |
poster | string | no | Póster que se muestra antes de que comience la reproducción |
fallback | string | no | Imagen que se muestra si el video no se puede reproducir |
title | Text | no | Título |
message | Text | no | Texto del cuerpo |
buttons | Button[] | sí | Botones de CTA en la parte inferior (puede estar vacío) |
{ "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" } } ] }}Localización
Anchor link toLos in-apps nativos reutilizan exactamente el mismo mecanismo de localización que los Rich Media HTML: los valores de cadena en native-config.json pueden llevar marcadores de posición {{key|type|default}}, y las traducciones se encuentran en un archivo pushwoosh.json junto a él, en el mismo formato descrito en Añadir pushwoosh.json. Un marcador de posición puede aparecer en cualquier campo de cadena, a cualquier profundidad (un título, una etiqueta de botón, una URL de imagen, una URL de acción).
Contenido dinámico
Anchor link toLos campos de texto — title, message, text del botón, reward.title/reward.message, y message del elemento/segmento — también aceptan Contenido dinámico y sintaxis Liquid: el mismo atajo {Tag|modifier|default} y las etiquetas Liquid {% %}/{{ }} utilizadas en el contenido de push y correo electrónico. Pushwoosh los resuelve por destinatario antes de que se envíe el mensaje, de la misma manera que lo hace para push y correo electrónico.
Al construir una plantilla en el editor nativo in-app del Panel de Control, los tokens insertados se renderizan como chips en la vista previa en vivo, y Guardar se bloquea si el Liquid de un campo de texto no se analiza correctamente.
Integración del SDK
Anchor link toUna vez que agregue el módulo SDK nativo in-app a su aplicación, los mensajes se mostrarán automáticamente. No se requiere código adicional para mostrar mensajes activados por un push, Customer Journey, postEvent o la bandeja de entrada.
El SDK también expone una pequeña API para el control manual:
- iOS:
Pushwoosh.inApp(móduloPushwooshInApp) - Android:
PushwooshInAppUi(módulopushwoosh-inapp-ui)
| Capacidad | iOS | Android |
|---|---|---|
| Mostrar una configuración directamente (pruebas/uso manual) | Pushwoosh.inApp.present(config) | PushwooshInAppUi.present(configJson) |
| Observar el ciclo de vida y los clics | delegate (PWInAppMessageDelegate) | delegate (InAppMessageDelegate) |
| Comprobar si algo está en pantalla | isPresenting | isPresenting |
| Descartar lo que se muestra actualmente | dismiss() | dismiss() |
| Pausar / reanudar la visualización | isPaused | isPaused |
Aplicar la limitación de maxDisplays / cooldown | setFrequencyCapEnabled(_:) | setFrequencyCapEnabled(...) |
Callbacks del delegado (todos se activan en el hilo principal): shouldDisplay (devuelve false para suprimir un mensaje antes de que se muestre, por ejemplo, en una pantalla de pago), willPresent, didPresent, didClose y clickedAction (se activa cuando el usuario toca una acción de url, antes de que se abra la URL).
iOS informa adicionalmente de rewardRevealed y rewardClaimed para las plantillas gamificadas scratchcard y spinwheel.
// iOSPushwoosh.inApp.delegate = selfPushwoosh.inApp.setFrequencyCapEnabled(true)// AndroidPushwooshInAppUi.delegate = thisPushwooshInAppUi.setFrequencyCapEnabled(true)