Configurando o Pushwoosh InboxKit para iOS
Disponível desde o SDK do iOS 7.0.40.
O Pushwoosh InboxKit oferece uma tela de caixa de entrada moderna em UIKit sobre o backend de caixa de entrada existente. Seis layouts de célula padrão cobrem os formatos comuns de cartões de conteúdo — de banners simples a carrosséis de imagens, vídeo em linha e passes do Apple Wallet — botões de CTA em linha lidam com as interações mais comuns, e toda a superfície está aberta para subclassificação se você precisar de um visual personalizado.

Feed padrão do InboxKit com cartões de banner, com legenda, clássico, carrossel, vídeo e Apple Wallet.
Quando usar o InboxKit
Anchor link toUse o InboxKit para qualquer nova integração com iOS. É o substituto recomendado para o módulo mais antigo em Objective-C PushwooshInboxUI.
O InboxKit oferece a você:
- Seis tipos de célula integrados — banner, com legenda, clássico, carrossel, vídeo e Apple Wallet — selecionados por mensagem através do
displayTypedo payload, ou forçados a partir do código viaattributes.forceCellKind. Veja Tipos de cartão para a lista completa. (O cartão Apple Wallet é exclusivo para iOS.) - Botões de CTA em linha com um enum tipado
PushwooshInboxButtonAction(openURL,dismiss,markRead,custom). O SDK lida com os três primeiros automaticamente; seu delegate roteiacustompara sua própria lógica. - Suporte à fixação: mensagens com
actionParams["pinned"] == trueflutuam para o topo do feed e renderizam um glifo de pino. - Deslizar para excluir, puxar para atualizar, marcar como lido automaticamente ao desaparecer — tudo alternável via
PushwooshInboxKitAttributes. - Armazenamento persistente: exclusões e estado de leitura sobrevivem a uma reinicialização do processo, mesmo que a chamada de rede ainda não tenha sido confirmada.
- Uma classe base aberta
PushwooshInboxCellpara layouts totalmente personalizados.
O contrato do servidor permanece inalterado — o mesmo backend de caixa de entrada do Pushwoosh, payloads e ferramentas do painel funcionam como antes.
Escolha seu método de integração
Anchor link to- Configurar o InboxKit com o Swift Package Manager — recomendado para novos projetos.
- Configurar o InboxKit com o CocoaPods — para projetos que já usam o CocoaPods.
Tipos de cartão
Anchor link toO InboxKit escolhe um layout de célula por mensagem. O resolvedor padrão lê displayType do payload do push — coloque-o dentro do objeto data, que o SDK entrega sob actionParams. Quando displayType está ausente, o resolvedor recorre a uma heurística: imagem + sem título → banner, imagem + título → com legenda, caso contrário, clássico. Para forçar um layout para todo o feed a partir do código, defina attributes.forceCellKind.
Cada layout rico degrada-se graciosamente: se o payload necessário estiver ausente ou malformado, o cartão volta para classic em vez de renderizar um espaço reservado vazio (e um WARN é registrado).
displayType | Layout | Campo de payload obrigatório | Degrada para |
|---|---|---|---|
banner | Imagem de sangria total, sem texto | imagem (inbox_image ou data.image) | classic quando não há imagem |
captioned | Imagem no topo, título + corpo abaixo | imagem (inbox_image ou data.image) | classic quando não há imagem |
classic | Avatar inicial colorido + título + corpo | — | — |
carousel | Galeria de múltiplas imagens deslizável | data.carousel (array de slides) | classic quando não há slides |
video | Pôster com ícone de play, player em tela cheia ao tocar | data.video (url + poster opcional) | classic quando não há descritor |
wallet | Botão “Adicionar à Carteira da Apple” (somente iOS) | data.wallet (URL do .pkpass) | classic quando não há URL do passe |






Os cartões de banner, com legenda e clássicos são controlados pelos campos de mensagem padrão (imagem, título, corpo) mais o array opcional buttons — veja Adicionar botões de CTA em linha. Os cartões de carrossel, vídeo e Apple Wallet carregam dados estruturados extras dentro de data, documentados abaixo.
Cartão de carrossel
Anchor link toUm carrossel renderiza várias imagens de uma única mensagem — uma galeria deslizável com legendas por slide e destinos de toque opcionais. Os slides ficam em data.carousel. Cada slide precisa de uma image; title (sobreposição de legenda) e url (deep link aberto ao tocar) são opcionais. Um slide sem imagem é descartado; um toque em um slide sem url recai para a ação de linha padrão da mensagem.
{ "request": { "application": "XXXXX-XXXXX", "auth": "API_TOKEN", "notifications": [{ "send_date": "now", "ios_title": "New arrivals", "content": "Swipe through this week's drops", "inbox_days": 7, "data": { "displayType": "carousel", "carousel": [ { "image": "https://cdn.example.com/inbox/1.jpg", "title": "New in", "url": "myapp://product/1" }, { "image": "https://cdn.example.com/inbox/2.jpg", "title": "On sale", "url": "myapp://product/2" }, { "image": "https://cdn.example.com/inbox/3.jpg" } ] }, "platforms": [1] }] }}Cartão de vídeo
Anchor link toUm cartão de vídeo mostra uma imagem de pôster com um ícone de play; tocá-lo abre um player em tela cheia (com som, mesmo com o interruptor de silêncio ativado). O descritor fica em data.video: url é obrigatório e deve ser um stream ou arquivo http/https; poster é uma imagem de pré-visualização opcional.
{ "request": { "application": "XXXXX-XXXXX", "auth": "API_TOKEN", "notifications": [{ "send_date": "now", "ios_title": "Watch the reveal", "content": "Tap to play", "inbox_days": 7, "data": { "displayType": "video", "video": { "url": "https://cdn.example.com/inbox/clip.mp4", "poster": "https://cdn.example.com/inbox/poster.jpg" } }, "platforms": [1] }] }}Cartão Apple Wallet
Anchor link toO cartão Apple Wallet mostra uma imagem de herói opcional, título e corpo acima do botão oficial Adicionar à Carteira da Apple. Tocar no botão baixa o .pkpass e apresenta a folha do sistema para adicionar passes. Use-o para entregar cupons, cartões de fidelidade, ingressos ou cartões de embarque diretamente da caixa de entrada. O cartão é exclusivo para iOS / Mac Catalyst — em outras plataformas, a mensagem é renderizada como um cartão clássico.
A URL do passe fica em data.wallet, seja como uma string simples ou como um objeto com um campo pass. Um data.image opcional adiciona a imagem de herói. O botão se esconde automaticamente quando não há URL de passe ou o dispositivo não pode adicionar passes.
{ "request": { "application": "XXXXX-XXXXX", "auth": "API_TOKEN", "notifications": [{ "send_date": "now", "ios_title": "Your loyalty card is ready", "content": "Add it to Apple Wallet in one tap", "inbox_days": 7, "data": { "displayType": "wallet", "image": "https://cdn.example.com/inbox/loyalty.png", "wallet": "https://passes.example.com/v1/passes/pass.com.example.loyalty/abc123?token=…" }, "platforms": [1] }] }}O resultado é reportado ao seu delegate:
extension MyInboxHost: PushwooshInboxKitDelegate {
func inboxKit(_ vc: PushwooshInboxKitViewController, didAddWalletPassFor message: PWInboxMessageProtocol) { // O passe agora está na Carteira do usuário — mostre uma confirmação se desejar. }
func inboxKit(_ vc: PushwooshInboxKitViewController, didFailToAddWalletPassFor message: PWInboxMessageProtocol, error: Error?) { // O download falhou — exiba uma nova tentativa, registre em log, etc. }}Ambos os callbacks são opcionais (eles carregam implementações vazias padrão). Um usuário cancelando a folha do sistema não é nem sucesso nem falha, então nenhum callback é disparado nesse caso.
Acessibilidade
Anchor link toAs células do InboxKit estão prontas para o VoiceOver desde o início. Os cartões de banner, com legenda e clássicos expõem seu título, corpo e data através dos rótulos subjacentes, e os botões de CTA em linha leem seus próprios títulos. Os cartões ricos adicionam semântica explícita:
- Vídeo — o pôster é exposto como um único elemento de botão rotulado “Reproduzir vídeo” (atributos
.button+.startsMediaSession), então o VoiceOver o anuncia como um controle de mídia em vez de uma imagem simples. - Carrossel — cada slide é um elemento de botão cujo rótulo de acessibilidade é a legenda do slide, ou “Slide” quando não tem nenhuma. O indicador de página anuncia a posição atual como “n de total”.
- Apple Wallet — o botão Adicionar à Carteira da Apple é o
PKAddPassButtonpadrão da Apple, que carrega seu próprio rótulo de VoiceOver localizado.
Para testes de UI e automação, dois accessibilityIdentifiers estáveis são definidos: inboxkit.video.play no pôster do vídeo e inboxkit.wallet.add no botão da Carteira.
Ler dados personalizados de uma mensagem
Anchor link toPara fazer um push aparecer na caixa de entrada, a solicitação createMessage da API de Mensagens deve incluir inbox_image, inbox_date ou inbox_days — sem um desses campos, o push é entregue como uma notificação regular e nunca chega ao feed da caixa de entrada. Dados personalizados de formato livre vão sob a chave data, que o SDK entrega ao cliente como o parâmetro u:
{ "request": { "application": "XXXXX-XXXXX", "auth": "API_TOKEN", "notifications": [{ "send_date": "now", "ios_title": "Summer sale", "content": "30% off everything — limited time only", "inbox_image": "https://cdn.example.com/inbox/summer.png", "inbox_days": 7, "data": { "displayType": "captioned", "promo_id": "SUMMER2026", "screen": "promo_details" }, "platforms": [1] }] }}O SDK expõe esse objeto na mensagem da caixa de entrada através de actionParams. Leia-o do delegate quando o usuário tocar na linha ou em um CTA em linha:
extension MyInboxHost: PushwooshInboxKitDelegate {
func inboxKit(_ vc: PushwooshInboxKitViewController, didSelect message: PWInboxMessageProtocol) -> Bool { guard let params = message.actionParams as? [String: Any] else { return true }
// O objeto `data` personalizado chega sob a chave "u" — // seja como um dicionário aninhado ou como uma string codificada em JSON, // dependendo de como o payload foi construído anteriormente. let custom: [String: Any]? = { if let dict = params["u"] as? [String: Any] { return dict } if let raw = params["u"] as? String, let bytes = raw.data(using: .utf8), let parsed = try? JSONSerialization.jsonObject(with: bytes) as? [String: Any] { return parsed } return nil }()
if let promoId = custom?["promo_id"] as? String { navigateToPromo(promoId) return false // nós lidamos com o toque; o SDK não deve executar a ação padrão } return true }}A mesma busca actionParams["u"] funciona dentro de inboxKit(_:didTapButton:onMessage:) para botões de CTA em linha. Para os casos de CTA tipados (openURL, dismiss, markRead), o SDK já executa a ação padrão — retorne true para manter esse comportamento, ou false para suprimi-lo e executar o seu próprio.
Adicionar botões de CTA em linha
Anchor link toUma mensagem pode carregar até três botões de chamada para ação (CTA) em linha. Os botões ficam ao lado de outros dados personalizados dentro de data como um array buttons. O SDK os renderiza automaticamente dentro das células com legenda e clássicas:
{ "request": { "application": "XXXXX-XXXXX", "auth": "API_TOKEN", "notifications": [{ "send_date": "now", "ios_title": "New promo card", "content": "Tap a button to claim or save", "inbox_image": "https://cdn.example.com/inbox/promo.png", "inbox_days": 7, "data": { "displayType": "captioned", "promo_id": "SUMMER2026", "buttons": [ { "title": "Claim", "url": "https://example.com/promo/SUMMER2026" }, { "title": "Read", "action": "markRead" }, { "title": "Save", "action": "custom", "tag": "save_promo" } ] }, "platforms": [1] }] }}Cada objeto de botão tem estes campos:
| Campo | Tipo | Quando |
|---|---|---|
title | string | Obrigatório. Rótulo visível do botão. |
url | string | Uma URL analisável e não vazia produz uma ação openURL. O SDK a abre via UIApplication.shared.open, a menos que seu delegate a suprima. |
action | string | Token de ação explícito: dismiss (remove a mensagem do feed), markRead (marca a mensagem como lida) ou custom (tratado pelo host). Não diferencia maiúsculas de minúsculas. |
| Qualquer outra coisa | any | Quando action é custom, todas as chaves no objeto do botão, exceto title e action, são encaminhadas para o seu delegate como o payload personalizado — combine uma chave com o profissional de marketing (por exemplo, tag) e despache com base nela. |
Prioridade de resolução: primeiro o token action explícito, depois url se não estiver vazio, caso contrário, o botão cai em custom carregando o payload completo (menos title e action).
Intercepte os toques do seu delegate. A propriedade button.action é o enum tipado PushwooshInboxButtonAction:
extension MyInboxHost: PushwooshInboxKitDelegate {
func inboxKit(_ vc: PushwooshInboxKitViewController, didTapButton button: PushwooshInboxButton, onMessage message: PWInboxMessageProtocol) -> Bool { switch button.action { case .openURL(let url): // O comportamento padrão está bom — deixe o SDK abrir a URL. return true
case .dismiss, .markRead: // O SDK lida com ambos. Retorne false se quiser substituir. return true
case .custom(let payload): // Botão personalizado definido pelo profissional de marketing. Despache com base em uma chave que vocês combinaram. if let tag = payload["tag"] as? String { switch tag { case "save_promo": saveCurrentPromoLocally(message: message) default: break } } return true // ignorado para custom — o SDK nunca executa uma ação padrão aqui } }}