Saltar al contenido

Sintaxis de plantillas in-app nativas

Los mensajes in-app nativos se renderizan directamente por el SDK. No se utiliza ningún WebView. En lugar de una página index.html, el recurso ZIP contiene 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, consulta Sintaxis de plantillas de Rich Media.

Prerrequisitos

Anchor link to

Los mensajes in-app 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. Consulta 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+
videoAún no disponible
pipAún no disponible
scratchcardAún no disponible
spinwheelAún no disponible

Estructura de la plantilla

Anchor link to

Una plantilla in-app nativa 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 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 mensaje in-app, en el paso de Ajustes de visualización de la campaña.

La limitación de frecuencia necesita además una activación explícita por parte del SDK para tener efecto en los mensajes in-app nativos. Consulta Integración del SDK.

Cada 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 to

Estos objetos más pequeños se reutilizan en varios tipos de visualización.

CampoTipoRequeridoDescripción
textstringEl contenido del texto
colorstringColor del texto
{ "text": "Gira para obtener un beneficio de garaje", "color": "#FFFFFFFF" }
CampoTipoRequeridoDescripción
colorstringColor del borde
radiusnumberRadio de la esquina, en puntos
{ "color": "#0E72E5FF", "radius": 12 }

Una imagen opcional sobre un color de fondo. Usado por fullscreen y scratchcard.

CampoTipoRequeridoDescripción
imagestringnoURL de la imagen de portada
backgroundstringColor de fondo mostrado debajo (o en lugar de) la imagen
{ "image": "https://example.com/cover.jpg", "background": "#1A1A1EFF" }

Una unión discriminada en type:

VarianteCamposDescripción
{ "type": "close" }NingunoCierra el mensaje in-app
{ "type": "url", "url": string }url requeridoAbre una URL o un enlace profundo
{ "type": "url", "url": "pushwoosh://sale" }
CampoTipoRequeridoDescripción
textTextEtiqueta del botón
backgroundstringColor de relleno del botón
borderBorderBorde del botón
actionActionAcción que se dispara 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": "Reservar una prueba de manejo", "color": "#FFFFFFFF" },
"background": "#0E72E5FF",
"border": { "color": "#0E72E5FF", "radius": 12 },
"action": { "type": "url", "url": "pushwoosh://sale" }
}

El panel de premios mostrado por scratchcard y spinwheel. Un premio válido tiene un title o un code.

CampoTipoRequeridoDescripción
titleTextnoEncabezado del premio
messageTextnoDescripción del premio
codestringnoCódigo promocional, renderizado con un botón de copiar
buttonButtonnoBotón de confirmación con su propia acción
{
"title": { "text": "20% de descuento en detallado", "color": "#111111FF" },
"message": { "text": "Válido para cualquier reserva de detallado completo este mes.", "color": "#555555FF" },
"code": "APEX20",
"button": {
"text": { "text": "Reservar detallado", "color": "#FFFFFFFF" },
"background": "#B3227CFF",
"border": { "color": "#B3227CFF", "radius": 12 },
"action": { "type": "url", "url": "pushwoosh://detailing" }
}
}

Tipos de visualización

Anchor link to

Una barra compacta anclada al borde superior o inferior de la pantalla.

CampoTipoRequeridoDescripción
showClosebooleanMostrar un botón de cerrar (✕)
positiontop | bottomBorde de la pantalla
backgroundstringColor de fondo de la barra
imagestringnoMiniatura a la izquierda
titleTextnoTítulo de una sola línea, truncado con puntos suspensivos
messageTextnoTexto del cuerpo, hasta 2 líneas
actionActionSe dispara cuando se toca la propia barra
autoDismissnumbernoSe cierra 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": "El Alpine A110 acaba de llegar", "color": "#FFFFFFFF" },
"message": { "text": "El ícono peso pluma — toca para ver la configuración", "color": "#FFFFFFFF" },
"action": { "type": "url", "url": "pushwoosh://product/x6f" },
"autoDismiss": 6
}
}

Un conjunto de tarjetas a pantalla completa, deslizables, con puntos indicadores de página.

CampoTipoRequeridoDescripción
showClosebooleanMostrar un botón de cerrar (✕)
itemsItem[]Tarjetas (al menos 1)

Elemento del carrusel:

CampoTipoRequeridoDescripción
titleTextnoTítulo de la tarjeta
messageTextnoSubtítulo de la tarjeta
imagestringnoImagen de la tarjeta
actionActionnoSe dispara 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": "V8 biturbo de 585 hp — recién llegado", "color": "#FFFFFFFF" },
"action": { "type": "url", "url": "pushwoosh://product/n6fx" }
},
{
"image": "https://example.com/card-2.jpg",
"title": { "text": "Alpine A110", "color": "#FFFFFFFF" },
"message": { "text": "Ícono peso pluma — asignación limitada", "color": "#FFFFFFFF" },
"action": { "type": "url", "url": "pushwoosh://product/x6f" }
}
]
}
}

fullscreen

Anchor link to

Una imagen de portada de borde a borde con texto y botones superpuestos.

CampoTipoRequeridoDescripción
showClosebooleanMostrar un botón de cerrar (✕)
coverCoverImagen y color de fondo
titleTextnoTítulo
messageTextnoTexto del cuerpo
buttonsButton[]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": "Puro Maranello", "color": "#FFFFFFFF" },
"message": { "text": "El cavallino rampante, reinventado.", "color": "#EBEBEBFF" },
"buttons": [
{
"text": { "text": "Reservar ahora", "color": "#FFFFFFFF" },
"background": "#0E72E5FF",
"border": { "color": "#0E72E5FF", "radius": 8 },
"action": { "type": "url", "url": "pushwoosh://sale" }
},
{
"text": { "text": "Ahora no", "color": "#FFFFFFFF" },
"background": "#00000000",
"border": { "color": "#FFFFFF99", "radius": 8 },
"action": { "type": "close" }
}
]
}
}

Una tarjeta centrada.

CampoTipoRequeridoDescripción
showClosebooleanMostrar un botón de cerrar (✕)
dimBackgroundbooleanAtenuar la pantalla detrás de la tarjeta
backgroundstringColor de fondo de la tarjeta
imagestringnoImagen de portada
titleTextnoTítulo
messageTextnoTexto del cuerpo
buttonsButton[]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": "El GT R ha llegado", "color": "#4B5057FF" },
"message": { "text": "585 hp — ahora en la sala de exposición.", "color": "#4B5057FF" },
"buttons": [
{
"text": { "text": "Reservar una prueba de manejo", "color": "#FFFFFFFF" },
"background": "#0E72E5FF",
"border": { "color": "#0E72E5FF", "radius": 12 },
"action": { "type": "url", "url": "pushwoosh://sale" }
},
{
"text": { "text": "Ahora no", "color": "#4B5057FF" },
"background": "#FFFFFFFF",
"border": { "color": "#4B5057FF", "radius": 12 },
"action": { "type": "close" }
}
]
}
}

Una ventana de video flotante picture-in-picture anclada a una esquina de la pantalla.

CampoTipoRequeridoDescripción
showClosebooleanMostrar un botón de cerrar (✕)
positionbottom-right | bottom-left | top-right | top-leftEsquina de la pantalla
loopbooleanRepetir la reproducción
mutedbooleanEmpezar silenciado
urlstringURL del video
posterstringnoPóster mostrado antes de que comience la reproducción
fallbackstringnoImagen mostrada si el video no se puede reproducir
widthnumberAncho de la ventana como porcentaje del ancho de la pantalla, limitado a 15–70
aspectRationumberRelación alto/ancho de la ventana
borderRadiusnumbernoRadio de la esquina de la ventana, en puntos
actionActionnoSe dispara 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 to

Una tarjeta con el premio oculto bajo una capa de lámina rascable.

CampoTipoRequeridoDescripción
showClosebooleanMostrar un botón de cerrar (✕)
backgroundstring | string[]Color de fondo de la tarjeta, o paradas de gradiente
revealThresholdnumberFracción de la lámina que debe rascarse (0–1) antes de que se revele el premio
coverCoverLa capa de lámina. Sin una image, se muestra una pista de “rasca aquí” sobre el color de fondo
revealButtonButton (no action)noBotón “Revelar instantáneamente”
titleTextnoTítulo
messageTextnoTexto del cuerpo
rewardRewardEl premio oculto bajo la lámina
{
"displayType": "scratchcard",
"scratchcard": {
"showClose": true,
"background": ["#3A1C71FF", "#B3227CFF", "#E0503AFF"],
"revealThreshold": 0.55,
"cover": { "background": "#C9CDD6FF" },
"revealButton": {
"text": { "text": "Revelar sin rascar", "color": "#3A1C71FF" },
"background": "#F2DFF5FF",
"border": { "color": "#F2DFF5FF", "radius": 10 }
},
"title": { "text": "Tu premio de lealtad", "color": "#FFFFFFFF" },
"message": { "text": "Rasca la lámina para revelar el beneficio de garaje de esta semana.", "color": "#F2DFF5FF" },
"reward": {
"title": { "text": "20% de descuento en detallado", "color": "#111111FF" },
"message": { "text": "Válido para cualquier reserva de detallado completo este mes.", "color": "#555555FF" },
"code": "APEX20",
"button": {
"text": { "text": "Reservar detallado", "color": "#FFFFFFFF" },
"background": "#B3227CFF",
"border": { "color": "#B3227CFF", "radius": 12 },
"action": { "type": "url", "url": "pushwoosh://detailing" }
}
}
}
}

Una tarjeta fijada al borde inferior, con un asa para arrastrar.

CampoTipoRequeridoDescripción
showClosebooleanMostrar un botón de cerrar (✕)
dimBackgroundbooleanAtenuar la pantalla detrás de la hoja
backgroundstringColor de fondo de la hoja
imagestringnoImagen de portada
titleTextnoTítulo
messageTextnoTexto del cuerpo
buttonsButton[]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": "Tu cotización está lista", "color": "#000000FF" },
"message": { "text": "Compra garantizada para tu A110: $68,500.", "color": "#000000FF" },
"buttons": [
{
"text": { "text": "Obtener cotización garantizada", "color": "#FFFFFFFF" },
"background": "#0E72E5FF",
"border": { "color": "#0E72E5FF", "radius": 12 },
"action": { "type": "url", "url": "pushwoosh://sale" }
}
]
}
}

Una rueda de la fortuna con segmentos ponderados y un botón central.

CampoTipoRequeridoDescripción
showClosebooleanMostrar un botón de cerrar (✕)
backgroundstring | string[]Color de fondo de la tarjeta, o paradas de gradiente
winIndexnumberÍndice (base 0) del segmento ganador
spinButtonButton (no action)Botón central
titleTextnoTítulo
messageTextnoTexto del cuerpo
rewardRewardPremio por el giro ganador (alternativa para segmentos sin el suyo propio)
loseTitleTextnoEncabezado mostrado en una pérdida
segmentsSegment[]Segmentos de la rueda (el SDK espera 2–12)

Segmento:

CampoTipoRequeridoDescripción
messageTextEtiqueta del segmento
colorstringnoColor del segmento. Omitir para una paleta alternativa aplicada alrededor de la rueda
weightnumberTamaño relativo del segmento
rewardRewardnoPremio específico del segmento
{
"displayType": "spinwheel",
"spinwheel": {
"showClose": true,
"background": ["#1B1B46FF", "#5B2B8FFF", "#B0338AFF"],
"winIndex": 1,
"spinButton": {
"text": { "text": "GIRAR", "color": "#1B1B46FF" },
"background": "#F2C94CFF",
"border": { "color": "#D9A02BFF", "radius": 36 }
},
"title": { "text": "Gira para obtener un beneficio de garaje", "color": "#FFFFFFFF" },
"message": { "text": "Un giro — cada porción gana esta semana.", "color": "#E3D9F2FF" },
"reward": {
"title": { "text": "¡Ganaste un beneficio de garaje!", "color": "#FFFFFFFF" },
"code": "APEXPERK",
"button": {
"text": { "text": "Reclamar", "color": "#FFFFFFFF" },
"background": "#5B2B8FFF",
"border": { "color": "#5B2B8FFF", "radius": 12 },
"action": { "type": "close" }
}
},
"segments": [
{ "message": { "text": "5% de descuento", "color": "#FFFFFFFF" }, "color": "#5856D6FF", "weight": 1 },
{
"message": { "text": "20% de descuento", "color": "#FFFFFFFF" },
"color": "#30B0C7FF",
"weight": 1,
"reward": {
"title": { "text": "20% de descuento en tu próximo servicio", "color": "#FFFFFFFF" },
"code": "SPIN20",
"button": {
"text": { "text": "Reclamar oferta de servicio", "color": "#FFFFFFFF" },
"background": "#30B0C7FF",
"border": { "color": "#30B0C7FF", "radius": 12 },
"action": { "type": "url", "url": "pushwoosh://service" }
}
}
},
{ "message": { "text": "Lavado gratis", "color": "#FFFFFFFF" }, "color": "#FF2D55FF", "weight": 1 }
]
}
}

Diapositivas a pantalla completa con barras de progreso en la parte superior, similar a las historias de las redes sociales.

CampoTipoRequeridoDescripción
showClosebooleanMostrar un botón de cerrar (✕)
loopbooleanReiniciar desde la primera diapositiva después de la última
itemsItem[]Diapositivas (al menos 1)

Elemento de las historias:

CampoTipoRequeridoDescripción
titleTextnoTítulo
messageTextnoSubtítulo
imagestringnoImagen de fondo de la diapositiva
buttonsButton[]Botones de llamada a la acción en la parte inferior (puede estar vacío)
durationnumberDuració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": "El especial del Infierno Verde", "color": "#FFFFFFFF" },
"buttons": [
{
"text": { "text": "Configura el tuyo", "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": "La leyenda peso pluma, renacida", "color": "#FFFFFFFF" },
"buttons": [],
"duration": 4
}
]
}
}

Video a pantalla completa con texto y botones superpuestos.

CampoTipoRequeridoDescripción
showClosebooleanMostrar un botón de cerrar (✕)
loopbooleanRepetir la reproducción
mutedbooleanEmpezar silenciado
urlstringURL del video (HLS o MP4)
posterstringnoPóster mostrado antes de que comience la reproducción
fallbackstringnoImagen mostrada si el video no se puede reproducir
titleTextnoTítulo
messageTextnoTexto del cuerpo
buttonsButton[]Botones de llamada a la acción 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": "La revelación", "color": "#FFFFFFFF" },
"message": { "text": "Míralo moverse antes que nadie.", "color": "#EBEBEBFF" },
"buttons": [
{
"text": { "text": "Comprar la línea", "color": "#FFFFFFFF" },
"background": "#0E72E5FF",
"border": { "color": "#0E72E5FF", "radius": 14 },
"action": { "type": "url", "url": "pushwoosh://sale" }
}
]
}
}

Localización

Anchor link to

Los mensajes in-app nativos reutilizan el mismo mecanismo de localización que los Rich Media HTML: los valores de cadena en native-config.json pueden contener 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).

Integración del SDK

Anchor link to

Una vez que añades el módulo del SDK de in-app nativos a tu aplicación, los mensajes se muestran automáticamente. No se requiere código adicional para mostrar mensajes activados por un push, un 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ódulo PushwooshInApp)
  • Android: PushwooshInAppUi (módulo pushwoosh-inapp-ui)
CapacidadiOSAndroid
Mostrar una configuración directamente (pruebas/uso manual)Pushwoosh.inApp.present(config)PushwooshInAppUi.present(configJson)
Observar el ciclo de vida y los clicsdelegate (PWInAppMessageDelegate)delegate (InAppMessageDelegate)
Comprobar si hay algo en pantallaisPresentingisPresenting
Descartar lo que se esté mostrando actualmentedismiss()dismiss()
Pausar / reanudar la visualizaciónisPausedisPaused
Aplicar la limitación de maxDisplays / cooldownsetFrequencyCapEnabled(_:)setFrequencyCapEnabled(...)

Callbacks del delegado (todos se ejecutan 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 ejecuta 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.

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