Pular para o conteúdo

Sintaxe de modelos de in-app nativos

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

In-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 todo tipo de exibição está disponível 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✅✅ 6.11.0+
pip✅Ainda não disponível
scratchcard✅Ainda não disponível
spinwheel✅Ainda não disponível

Estrutura do modelo

Anchor link to

Um modelo de in-app nativo é um arquivo ZIP, igual a 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 ZIP.

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 limitação 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.

A limitação de frequência adicionalmente precisa de um opt-in explícito do lado do SDK para ter efeito em in-apps nativos. Consulte Integração do SDK.

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

Esses objetos menores são reutilizados em vários tipos de exibição.

CampoTipoObrigatórioDescrição
textstringsimO conteúdo do texto
colorstringsimCor do texto
{ "text": "Gire para um benefício de garagem", "color": "#FFFFFFFF" }
CampoTipoObrigatórioDescrição
colorstringsimCor da borda
radiusnumbersimRaio do canto, em pontos
{ "color": "#0E72E5FF", "radius": 12 }

Uma imagem opcional sobre uma cor de fundo. Usado por fullscreen e scratchcard.

CampoTipoObrigatórioDescrição
imagestringnãoURL da imagem de capa
backgroundstringsimCor de fundo mostrada sob (ou em vez de) a imagem
{ "image": "https://example.com/cover.jpg", "background": "#1A1A1EFF" }

Uma união discriminada em type:

VarianteCamposDescrição
{ "type": "close" }NenhumFecha o in-app
{ "type": "url", "url": string }url obrigatórioAbre uma URL ou deep link
{ "type": "url", "url": "pushwoosh://sale" }
CampoTipoObrigatórioDescrição
textTextsimRótulo do botão
backgroundstringsimCor de preenchimento do botão
borderBordersimBorda do botão
actionActionsimAção disparada ao tocar

spinButton (spinwheel) e revealButton (scratchcard) usam a mesma forma sem action. Seu comportamento (girar a roda, revelar o cartão) é embutido.

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

Recompensa

Anchor link to

O painel de prêmios mostrado por scratchcard e spinwheel. Uma recompensa válida tem um title ou um code.

CampoTipoObrigatórioDescrição
titleTextnãoTítulo da recompensa
messageTextnãoDescrição da recompensa
codestringnãoCódigo promocional, renderizado com um botão de copiar
buttonButtonnãoBotão de confirmação com sua própria ação
{
"title": { "text": "20% de desconto em detalhamento", "color": "#111111FF" },
"message": { "text": "Válido para qualquer agendamento de detalhamento completo este mês.", "color": "#555555FF" },
"code": "APEX20",
"button": {
"text": { "text": "Agendar detalhamento", "color": "#FFFFFFFF" },
"background": "#B3227CFF",
"border": { "color": "#B3227CFF", "radius": 12 },
"action": { "type": "url", "url": "pushwoosh://detailing" }
}
}

Tipos de exibição

Anchor link to

Uma barra compacta ancorada na borda superior ou inferior da tela.

CampoTipoObrigatórioDescrição
showClosebooleansimMostrar um botão de fechar (✕)
positiontop | bottomsimBorda da tela
backgroundstringsimCor de fundo da barra
imagestringnãoMiniatura à esquerda
titleTextnãoTítulo de uma linha, truncado com reticências
messageTextnãoTexto do corpo, até 2 linhas
actionActionsimDisparado quando a própria barra é tocada
autoDismissnumbernãoFechar 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 acabou de chegar", "color": "#FFFFFFFF" },
"message": { "text": "O ícone peso-pena — toque para ver a montagem", "color": "#FFFFFFFF" },
"action": { "type": "url", "url": "pushwoosh://product/x6f" },
"autoDismiss": 6
}
}

Um conjunto de cartões de tela cheia, deslizáveis, com pontos indicadores de página.

CampoTipoObrigatórioDescrição
showClosebooleansimMostrar um botão de fechar (✕)
itemsItem[]simCartões (pelo menos 1)

Item do carrossel:

CampoTipoObrigatórioDescrição
titleTextnãoTítulo do cartão
messageTextnãoSubtítulo do cartão
imagestringnãoImagem do cartão
actionActionnãoDisparado 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": "V8 biturbo de 585 cv — acabou de chegar", "color": "#FFFFFFFF" },
"action": { "type": "url", "url": "pushwoosh://product/n6fx" }
},
{
"image": "https://example.com/card-2.jpg",
"title": { "text": "Alpine A110", "color": "#FFFFFFFF" },
"message": { "text": "Ícone peso-pena — alocação limitada", "color": "#FFFFFFFF" },
"action": { "type": "url", "url": "pushwoosh://product/x6f" }
}
]
}
}

fullscreen

Anchor link to

Uma imagem de capa de ponta a ponta com texto e botões por cima.

CampoTipoObrigatórioDescrição
showClosebooleansimMostrar um botão de fechar (✕)
coverCoversimImagem e cor de fundo
titleTextnãoTítulo
messageTextnãoTexto do corpo
buttonsButton[]simBotões na parte inferior (pode estar vazio)
{
"displayType": "fullscreen",
"fullscreen": {
"showClose": true,
"cover": { "image": "https://example.com/hero.jpg", "background": "#1A1A1EFF" },
"title": { "text": "Puro Maranello", "color": "#FFFFFFFF" },
"message": { "text": "O cavalo empinado, reimaginado.", "color": "#EBEBEBFF" },
"buttons": [
{
"text": { "text": "Reserve agora", "color": "#FFFFFFFF" },
"background": "#0E72E5FF",
"border": { "color": "#0E72E5FF", "radius": 8 },
"action": { "type": "url", "url": "pushwoosh://sale" }
},
{
"text": { "text": "Agora não", "color": "#FFFFFFFF" },
"background": "#00000000",
"border": { "color": "#FFFFFF99", "radius": 8 },
"action": { "type": "close" }
}
]
}
}

Um cartão centralizado.

CampoTipoObrigatórioDescrição
showClosebooleansimMostrar um botão de fechar (✕)
dimBackgroundbooleansimEscurecer a tela atrás do cartão
backgroundstringsimCor de fundo do cartão
imagestringnãoImagem de capa
titleTextnãoTítulo
messageTextnãoTexto do corpo
buttonsButton[]simBotões abaixo do texto (pode estar vazio)
{
"displayType": "modal",
"modal": {
"showClose": true,
"dimBackground": true,
"background": "#FFFFFFFF",
"image": "https://example.com/cover.jpg",
"title": { "text": "O GT R chegou", "color": "#4B5057FF" },
"message": { "text": "585 cv — agora no showroom.", "color": "#4B5057FF" },
"buttons": [
{
"text": { "text": "Agendar um test drive", "color": "#FFFFFFFF" },
"background": "#0E72E5FF",
"border": { "color": "#0E72E5FF", "radius": 12 },
"action": { "type": "url", "url": "pushwoosh://sale" }
},
{
"text": { "text": "Agora não", "color": "#4B5057FF" },
"background": "#FFFFFFFF",
"border": { "color": "#4B5057FF", "radius": 12 },
"action": { "type": "close" }
}
]
}
}

Uma janela de vídeo picture-in-picture flutuante ancorada em um canto da tela.

CampoTipoObrigatórioDescrição
showClosebooleansimMostrar um botão de fechar (✕)
positionbottom-right | bottom-left | top-right | top-leftsimCanto da tela
loopbooleansimRepetir a reprodução
mutedbooleansimIniciar sem som
urlstringsimURL do vídeo
posterstringnãoPôster mostrado antes do início da reprodução
fallbackstringnãoImagem mostrada se o vídeo falhar ao reproduzir
widthnumbersimLargura da janela como porcentagem da largura da tela, limitada entre 15–70
aspectRationumbersimProporção altura/largura da janela
borderRadiusnumbernãoRaio do canto da janela, em pontos
actionActionnãoDisparado 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 to

Um cartão com a recompensa escondida sob uma camada de papel alumínio raspável.

CampoTipoObrigatórioDescrição
showClosebooleansimMostrar um botão de fechar (✕)
backgroundstring | string[]simCor de fundo do cartão, ou paradas de gradiente
revealThresholdnumbersimFração do papel alumínio que deve ser raspada (0–1) antes que a recompensa seja revelada
coverCoversimA camada de papel alumínio. Sem uma image, uma dica “raspe aqui” é mostrada na cor de fundo
revealButtonButton (sem action)nãoBotão “Revelar instantaneamente”
titleTextnãoTítulo
messageTextnãoTexto do corpo
rewardRewardsimO prêmio escondido sob o papel alumínio
{
"displayType": "scratchcard",
"scratchcard": {
"showClose": true,
"background": ["#3A1C71FF", "#B3227CFF", "#E0503AFF"],
"revealThreshold": 0.55,
"cover": { "background": "#C9CDD6FF" },
"revealButton": {
"text": { "text": "Revelar sem raspar", "color": "#3A1C71FF" },
"background": "#F2DFF5FF",
"border": { "color": "#F2DFF5FF", "radius": 10 }
},
"title": { "text": "Sua recompensa de fidelidade", "color": "#FFFFFFFF" },
"message": { "text": "Raspe o papel alumínio para revelar o benefício de garagem desta semana.", "color": "#F2DFF5FF" },
"reward": {
"title": { "text": "20% de desconto em detalhamento", "color": "#111111FF" },
"message": { "text": "Válido para qualquer agendamento de detalhamento completo este mês.", "color": "#555555FF" },
"code": "APEX20",
"button": {
"text": { "text": "Agendar detalhamento", "color": "#FFFFFFFF" },
"background": "#B3227CFF",
"border": { "color": "#B3227CFF", "radius": 12 },
"action": { "type": "url", "url": "pushwoosh://detailing" }
}
}
}
}

Um cartão fixado na borda inferior, com uma alça de arrasto.

CampoTipoObrigatórioDescrição
showClosebooleansimMostrar um botão de fechar (✕)
dimBackgroundbooleansimEscurecer a tela atrás da folha
backgroundstringsimCor de fundo da folha
imagestringnãoImagem de capa
titleTextnãoTítulo
messageTextnãoTexto do corpo
buttonsButton[]simBotões abaixo do texto (pode estar vazio)
{
"displayType": "sheet",
"sheet": {
"showClose": true,
"dimBackground": true,
"background": "#FFFFFFFF",
"image": "https://example.com/cover.jpg",
"title": { "text": "Sua cotação está pronta", "color": "#000000FF" },
"message": { "text": "Compra garantida para seu A110: $68,500.", "color": "#000000FF" },
"buttons": [
{
"text": { "text": "Obter cotação garantida", "color": "#FFFFFFFF" },
"background": "#0E72E5FF",
"border": { "color": "#0E72E5FF", "radius": 12 },
"action": { "type": "url", "url": "pushwoosh://sale" }
}
]
}
}

Uma roda da fortuna com segmentos ponderados e um botão central.

CampoTipoObrigatórioDescrição
showClosebooleansimMostrar um botão de fechar (✕)
backgroundstring | string[]simCor de fundo do cartão, ou paradas de gradiente
winIndexnumbersimÍndice (base 0) do segmento vencedor
spinButtonButton (sem action)simBotão central
titleTextnãoTítulo
messageTextnãoTexto do corpo
rewardRewardsimRecompensa pela rodada vencedora (fallback para segmentos sem a sua própria)
loseTitleTextnãoTítulo mostrado em uma perda
segmentsSegment[]simSegmentos da roda (SDK espera 2–12)

Segmento:

CampoTipoObrigatórioDescrição
messageTextsimRótulo do segmento
colorstringnãoCor do segmento. Omita para uma paleta de fallback aplicada ao redor da roda
weightnumbersimTamanho relativo do segmento
rewardRewardnãoRecompensa específica do 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": "Gire para um benefício de garagem", "color": "#FFFFFFFF" },
"message": { "text": "Uma rodada — toda fatia ganha esta semana.", "color": "#E3D9F2FF" },
"reward": {
"title": { "text": "Você ganhou um benefício de garagem!", "color": "#FFFFFFFF" },
"code": "APEXPERK",
"button": {
"text": { "text": "Resgatar", "color": "#FFFFFFFF" },
"background": "#5B2B8FFF",
"border": { "color": "#5B2B8FFF", "radius": 12 },
"action": { "type": "close" }
}
},
"segments": [
{ "message": { "text": "5% de desconto", "color": "#FFFFFFFF" }, "color": "#5856D6FF", "weight": 1 },
{
"message": { "text": "20% de desconto", "color": "#FFFFFFFF" },
"color": "#30B0C7FF",
"weight": 1,
"reward": {
"title": { "text": "20% de desconto no seu próximo serviço", "color": "#FFFFFFFF" },
"code": "SPIN20",
"button": {
"text": { "text": "Resgatar oferta de serviço", "color": "#FFFFFFFF" },
"background": "#30B0C7FF",
"border": { "color": "#30B0C7FF", "radius": 12 },
"action": { "type": "url", "url": "pushwoosh://service" }
}
}
},
{ "message": { "text": "Lavagem grátis", "color": "#FFFFFFFF" }, "color": "#FF2D55FF", "weight": 1 }
]
}
}

Slides de tela cheia com barras de progresso na parte superior, semelhantes às histórias de redes sociais.

CampoTipoObrigatórioDescrição
showClosebooleansimMostrar um botão de fechar (✕)
loopbooleansimReiniciar do primeiro slide após o último
itemsItem[]simSlides (pelo menos 1)

Item de histórias:

CampoTipoObrigatórioDescrição
titleTextnãoTítulo
messageTextnãoSubtítulo
imagestringnãoImagem de fundo do slide
buttonsButton[]simBotões de CTA na parte inferior (pode estar vazio)
durationnumbersimDuraçã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": "O especial do Inferno Verde", "color": "#FFFFFFFF" },
"buttons": [
{
"text": { "text": "Configure o seu", "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": "A lenda peso-pena, renascida", "color": "#FFFFFFFF" },
"buttons": [],
"duration": 4
}
]
}
}

Vídeo em tela cheia com texto e botões por cima.

CampoTipoObrigatórioDescrição
showClosebooleansimMostrar um botão de fechar (✕)
loopbooleansimRepetir a reprodução
mutedbooleansimIniciar sem som
urlstringsimURL do vídeo (HLS ou MP4)
posterstringnãoPôster mostrado antes do início da reprodução
fallbackstringnãoImagem mostrada se o vídeo falhar ao reproduzir
titleTextnãoTítulo
messageTextnãoTexto do corpo
buttonsButton[]simBotõ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": "A revelação", "color": "#FFFFFFFF" },
"message": { "text": "Assista-o em movimento antes de qualquer um.", "color": "#EBEBEBFF" },
"buttons": [
{
"text": { "text": "Compre a linha", "color": "#FFFFFFFF" },
"background": "#0E72E5FF",
"border": { "color": "#0E72E5FF", "radius": 14 },
"action": { "type": "url", "url": "pushwoosh://sale" }
}
]
}
}

Localização

Anchor link to

In-apps nativos reutilizam o mesmo mecanismo de localização exato que os Rich Media HTML: valores de string em native-config.json podem carregar placeholders {{key|type|default}}, e as traduções residem 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 to

Campos de texto — title, message, text do botão, reward.title/reward.message e message do item/segmento — também aceitam Conteúdo dinâmico e Sintaxe Liquid: o mesmo atalho {Tag|modifier|default} e as 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 do SDK

Anchor link to

Depois 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 pela caixa de entrada.

O SDK também expõe uma pequena API para controle manual:

  • iOS: Pushwoosh.inApp (módulo PushwooshInApp)
  • Android: PushwooshInAppUi (módulo pushwoosh-inapp-ui)
CapacidadeiOSAndroid
Mostrar uma configuração diretamente (teste/uso manual)Pushwoosh.inApp.present(config)PushwooshInAppUi.present(configJson)
Observar ciclo de vida e cliquesdelegate (PWInAppMessageDelegate)delegate (InAppMessageDelegate)
Verificar se algo está na telaisPresentingisPresenting
Dispensar o que estiver sendo exibido no momentodismiss()dismiss()
Pausar / retomar exibiçãoisPausedisPaused
Aplicar limitação de maxDisplays / cooldownsetFrequencyCapEnabled(_:)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 de url, antes que a URL seja aberta).

O iOS adicionalmente relata rewardRevealed e rewardClaimed para os modelos gamificados scratchcard e spinwheel.

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