Sintaxe de modelos nativos de in-app
In-apps nativos são renderizados diretamente pelo SDK. Nenhum WebView está envolvido. Em vez de uma página index.html, o recurso ZIP carrega um arquivo native-config.json que descreve a mensagem como dados estruturados (tipo de layout, textos, cores, imagens, botões). O SDK lê este arquivo e desenha a visualização nativa correspondente, o que proporciona animações mais suaves e melhor desempenho do que uma página da web incorporada.
Este guia documenta o esquema native-config.json: campos, tipos e exemplos para cada tipo de exibição. Para o formato clássico baseado em HTML, consulte Sintaxe de modelos de Rich Media.
Pré-requisitos
Anchor link toIn-apps nativos exigem:
- iOS: SDK 7.2.0 ou posterior (7.2.1+ para banner, carrossel e folha)
- Android: SDK 6.10.0 ou posterior (6.10.1+ para banner, carrossel e folha)
Nem todos os tipos de exibição estão disponíveis em ambas as plataformas ainda. Verifique o Suporte de plataforma antes de depender de um formato específico.
Suporte de plataforma
Anchor link to| Tipo de exibição | 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 | ✅ | Ainda não disponível |
| pip | ✅ | Ainda não disponível |
| scratchcard | ✅ | Ainda não disponível |
| spinwheel | ✅ | Ainda não disponível |
Estrutura do modelo
Anchor link toUm modelo de in-app nativo é um arquivo ZIP, o mesmo que um modelo de Rich Media regular, exceto que a raiz contém um arquivo native-config.json em vez de index.html:
<template>.zip├── native-config.json ← obrigatório, layout e conteúdo├── pushwoosh.json ← opcional, localização (veja abaixo)Imagens e vídeos referenciados de native-config.json (image, poster, fallback, url em pip/video) devem ser URLs HTTPS absolutas. O SDK os carrega pela rede. Ele não lê arquivos locais do arquivo.
A configuração em si é um único objeto JSON:
{ "displayType": "<type>", "<type>": { /* bloco de conteúdo para este tipo */ } }displayType seleciona um dos dez formatos abaixo. O objeto sob a chave correspondente contém o conteúdo desse formato. Uma configuração com um displayType desconhecido, um bloco de conteúdo ausente ou uma lista obrigatória vazia (items para carousel/stories, segments para spinwheel) é inválida. O SDK ignora a exibição em vez de renderizar um layout quebrado.
As configurações de entrega (datas de início/fim e limite de frequência) não fazem parte do native-config.json. Elas são configuradas da mesma forma que para qualquer outro in-app, na etapa de Configurações de exibição da campanha.
O limite de frequência adicionalmente precisa de uma adesão explícita do lado do SDK para ter efeito em in-apps nativos. Consulte Integração com o SDK.
Cores
Anchor link toCada valor de cor é uma string hexadecimal CSS: #RGB, #RGBA, #RRGGBB ou #RRGGBBAA. O # inicial é obrigatório em todas as quatro formas.
Blocos de construção compartilhados
Anchor link toEsses objetos menores são reutilizados em vários tipos de exibição.
Texto
Anchor link to| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
text | string | sim | O conteúdo do texto |
color | string | sim | Cor do texto |
{ "text": "Spin for a garage perk", "color": "#FFFFFFFF" }Borda
Anchor link to| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
color | string | sim | Cor da borda |
radius | number | sim | Raio do canto, em pontos |
{ "color": "#0E72E5FF", "radius": 12 }Capa
Anchor link toUma imagem opcional sobre uma cor de fundo. Usado por fullscreen e scratchcard.
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
image | string | não | URL da imagem de capa |
background | string | sim | Cor de fundo mostrada sob (ou em vez de) a imagem |
{ "image": "https://example.com/cover.jpg", "background": "#1A1A1EFF" }Ação
Anchor link toUma união discriminada em type:
| Variante | Campos | Descrição |
|---|---|---|
{ "type": "close" } | Nenhum | Fecha o in-app |
{ "type": "url", "url": string } | url obrigatório | Abre uma URL ou deep link |
{ "type": "url", "url": "pushwoosh://sale" }Botão
Anchor link to| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
text | Text | sim | Rótulo do botão |
background | string | sim | Cor de preenchimento do botão |
border | Border | sim | Borda do botão |
action | Action | sim | Ação disparada ao tocar |
spinButton (spinwheel) e revealButton (scratchcard) usam a mesma forma sem action. O comportamento deles (girar a roda, revelar o cartão) é embutido.
{ "text": { "text": "Book a test drive", "color": "#FFFFFFFF" }, "background": "#0E72E5FF", "border": { "color": "#0E72E5FF", "radius": 12 }, "action": { "type": "url", "url": "pushwoosh://sale" }}Recompensa
Anchor link toO painel de prêmios mostrado por scratchcard e spinwheel. Uma recompensa válida tem um title ou um code.
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
title | Text | não | Título da recompensa |
message | Text | não | Descrição da recompensa |
code | string | não | Código promocional, renderizado com um botão de cópia |
button | Button | não | Botão de confirmação com sua própria ação |
{ "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 exibição
Anchor link tobanner
Anchor link toUma barra compacta ancorada na borda superior ou inferior da tela.
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
showClose | boolean | sim | Mostrar um botão de fechar (✕) |
position | top | bottom | sim | Borda da tela |
background | string | sim | Cor de fundo da barra |
image | string | não | Miniatura à esquerda |
title | Text | não | Título de uma linha, truncado com reticências |
message | Text | não | Texto do corpo, até 2 linhas |
action | Action | sim | Disparado quando a própria barra é tocada |
autoDismiss | number | não | Fechar automaticamente após este número de segundos. Omita para mantê-lo até ser fechado |
{ "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 toUm conjunto de cartões deslizáveis em tela cheia com pontos indicadores de página.
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
showClose | boolean | sim | Mostrar um botão de fechar (✕) |
items | Item[] | sim | Cartões (pelo menos 1) |
Item do carrossel:
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
title | Text | não | Título do cartão |
message | Text | não | Subtítulo do cartão |
image | string | não | Imagem do cartão |
action | Action | não | Disparado quando o cartão é tocado |
{ "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 toUma imagem de capa de ponta a ponta com texto e botões por cima.
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
showClose | boolean | sim | Mostrar um botão de fechar (✕) |
cover | Cover | sim | Imagem e cor de fundo |
title | Text | não | Título |
message | Text | não | Texto do corpo |
buttons | Button[] | sim | Botões na parte inferior (pode estar vazio) |
{ "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 toUm cartão centralizado.
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
showClose | boolean | sim | Mostrar um botão de fechar (✕) |
dimBackground | boolean | sim | Escurecer a tela atrás do cartão |
background | string | sim | Cor de fundo do cartão |
image | string | não | Imagem de capa |
title | Text | não | Título |
message | Text | não | Texto do corpo |
buttons | Button[] | sim | Botões abaixo do texto (pode estar vazio) |
{ "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" } } ] }}Uma janela de vídeo picture-in-picture flutuante ancorada a um canto da tela.
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
showClose | boolean | sim | Mostrar um botão de fechar (✕) |
position | bottom-right | bottom-left | top-right | top-left | sim | Canto da tela |
loop | boolean | sim | Repetir a reprodução |
muted | boolean | sim | Iniciar sem som |
url | string | sim | URL do vídeo |
poster | string | não | Pôster mostrado antes do início da reprodução |
fallback | string | não | Imagem mostrada se o vídeo falhar ao reproduzir |
width | number | sim | Largura da janela como porcentagem da largura da tela, limitada entre 15–70 |
aspectRatio | number | sim | Proporção altura/largura da janela |
borderRadius | number | não | Raio do canto da janela, em pontos |
action | Action | não | Disparado quando a própria janela é tocada |
Não há botões configuráveis em pip. Os controles da janela (expandir para tela cheia, silenciar, fechar) são fornecidos pelo 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 toUm cartão com a recompensa escondida sob uma camada de folha raspável.
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
showClose | boolean | sim | Mostrar um botão de fechar (✕) |
background | string | string[] | sim | Cor de fundo do cartão, ou paradas de gradiente |
revealThreshold | number | sim | Fração da folha que deve ser raspada (0–1) antes que a recompensa seja revelada |
cover | Cover | sim | A camada de folha. Sem uma image, uma dica “raspe aqui” é mostrada na cor de fundo |
revealButton | Button (sem action) | não | Botão “Revelar instantaneamente” |
title | Text | não | Título |
message | Text | não | Texto do corpo |
reward | Reward | sim | O prêmio escondido sob a folha |
{ "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 toUm cartão fixado na borda inferior, com uma alça de arrasto.
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
showClose | boolean | sim | Mostrar um botão de fechar (✕) |
dimBackground | boolean | sim | Escurecer a tela atrás da folha |
background | string | sim | Cor de fundo da folha |
image | string | não | Imagem de capa |
title | Text | não | Título |
message | Text | não | Texto do corpo |
buttons | Button[] | sim | Botões abaixo do texto (pode estar vazio) |
{ "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 toUma roda da fortuna com segmentos ponderados e um botão central.
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
showClose | boolean | sim | Mostrar um botão de fechar (✕) |
background | string | string[] | sim | Cor de fundo do cartão, ou paradas de gradiente |
winIndex | number | sim | Índice (base 0) do segmento vencedor |
spinButton | Button (sem action) | sim | Botão central |
title | Text | não | Título |
message | Text | não | Texto do corpo |
reward | Reward | sim | Recompensa pela rodada vencedora (fallback para segmentos sem a sua própria) |
loseTitle | Text | não | Título mostrado em uma perda |
segments | Segment[] | sim | Segmentos da roda (SDK espera 2–12) |
Segmento:
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
message | Text | sim | Rótulo do segmento |
color | string | não | Cor do segmento. Omita para uma paleta de fallback aplicada ao redor da roda |
weight | number | sim | Tamanho relativo do segmento |
reward | Reward | não | Recompensa específica do 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 toSlides em tela cheia com barras de progresso no topo, semelhantes às histórias de redes sociais.
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
showClose | boolean | sim | Mostrar um botão de fechar (✕) |
loop | boolean | sim | Reiniciar do primeiro slide após o último |
items | Item[] | sim | Slides (pelo menos 1) |
Item de stories:
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
title | Text | não | Título |
message | Text | não | Subtítulo |
image | string | não | Imagem de fundo do slide |
buttons | Button[] | sim | Botões de CTA na parte inferior (pode estar vazio) |
duration | number | sim | Duração do slide, em 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 toVídeo em tela cheia com texto e botões por cima.
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
showClose | boolean | sim | Mostrar um botão de fechar (✕) |
loop | boolean | sim | Repetir a reprodução |
muted | boolean | sim | Iniciar sem som |
url | string | sim | URL do vídeo (HLS ou MP4) |
poster | string | não | Pôster mostrado antes do início da reprodução |
fallback | string | não | Imagem mostrada se o vídeo falhar ao reproduzir |
title | Text | não | Título |
message | Text | não | Texto do corpo |
buttons | Button[] | sim | Botões de CTA na parte inferior (pode estar vazio) |
{ "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" } } ] }}Localização
Anchor link toIn-apps nativos reutilizam o mesmo mecanismo de localização que o Rich Media HTML: valores de string em native-config.json podem carregar placeholders {{key|type|default}}, e as traduções ficam em um arquivo pushwoosh.json ao lado dele, no mesmo formato descrito em Adicionando pushwoosh.json. Um placeholder pode aparecer em qualquer campo de string, em qualquer profundidade (um título, um rótulo de botão, uma URL de imagem, uma URL de ação).
Conteúdo dinâmico
Anchor link toCampos de texto — title, message, text do botão, reward.title/reward.message e message de item/segmento — também aceitam Conteúdo dinâmico e sintaxe Liquid: a mesma abreviação {Tag|modifier|default} e tags Liquid {% %}/{{ }} usadas no conteúdo de push e e-mail. O Pushwoosh resolve isso por destinatário antes que a mensagem seja enviada, da mesma forma que faz para push e e-mail.
Ao construir um modelo no editor de in-app nativo do Painel de Controle, os tokens inseridos são renderizados como chips na visualização ao vivo, e Salvar é bloqueado se o Liquid de um campo de texto não for analisado corretamente.
Integração com o SDK
Anchor link toDepois de adicionar o módulo SDK de in-app nativo ao seu aplicativo, as mensagens são exibidas automaticamente. Nenhum código extra é necessário para mostrar mensagens acionadas por um push, Customer Journey, postEvent ou a caixa de entrada.
O SDK também expõe uma pequena API para controle manual:
- iOS:
Pushwoosh.inApp(móduloPushwooshInApp) - Android:
PushwooshInAppUi(módulopushwoosh-inapp-ui)
| Capacidade | iOS | Android |
|---|---|---|
| Mostrar uma configuração diretamente (teste/uso manual) | Pushwoosh.inApp.present(config) | PushwooshInAppUi.present(configJson) |
| Observar ciclo de vida e cliques | delegate (PWInAppMessageDelegate) | delegate (InAppMessageDelegate) |
| Verificar se algo está na tela | isPresenting | isPresenting |
| Dispensar o que estiver sendo exibido no momento | dismiss() | dismiss() |
| Pausar / retomar exibição | isPaused | isPaused |
Aplicar limite de maxDisplays / cooldown | setFrequencyCapEnabled(_:) | setFrequencyCapEnabled(...) |
Callbacks do delegate (todos disparados na thread principal): shouldDisplay (retorne false para suprimir uma mensagem antes que ela seja exibida, por exemplo, em uma tela de checkout), willPresent, didPresent, didClose e clickedAction (disparado quando o usuário toca em uma ação url, antes que a URL seja aberta).
O iOS adicionalmente relata rewardRevealed e rewardClaimed para os modelos gamificados scratchcard e spinwheel.
// iOSPushwoosh.inApp.delegate = selfPushwoosh.inApp.setFrequencyCapEnabled(true)// AndroidPushwooshInAppUi.delegate = thisPushwooshInAppUi.setFrequencyCapEnabled(true)