Saltar al contenido

Configuración de la interfaz de usuario de la bandeja de entrada de Pushwoosh para Android

La interfaz de usuario de la bandeja de entrada de Pushwoosh ofrece una pantalla de bandeja de entrada de Android ya preparada (la “Bandeja de entrada de la aplicación” con el icono de la campana) sobre el backend de la bandeja de entrada de Pushwoosh. Renderiza los mensajes en uno de los cinco tipos de tarjetas, admite botones de CTA en línea y está abierta a la personalización de estilo a través de atributos XML o código.

Requisitos previos

Anchor link to
  • El SDK base de Pushwoosh para Android ya está integrado y enviando notificaciones push.
  • Soporte de Kotlin en el módulo de tu aplicación (apply plugin: 'kotlin-android').

Añadir la librería

Anchor link to

Añade el plugin de Kotlin y los dos módulos de Pushwoosh al build.gradle de tu aplicación:

build.gradle
apply plugin: 'kotlin-android'
dependencies {
implementation 'com.pushwoosh:pushwoosh-inbox:6.+'
implementation 'com.pushwoosh:pushwoosh-inbox-ui:6.+'
}

Fija pushwoosh-inbox y pushwoosh-inbox-ui a la misma versión que tu dependencia existente de com.pushwoosh:pushwoosh. Reemplaza + con la versión actual del SDK de Pushwoosh para Android.

Si tu aplicación utiliza ProGuard para la ofuscación de código, mantén la clase del plugin de la bandeja de entrada:

proguard-rules.pro
-keep public class com.pushwoosh.inbox.PushwooshInboxPlugin {
*;
}

Mostrar la bandeja de entrada

Anchor link to

Presenta la bandeja de entrada como una pantalla independiente, o incrústala como un fragmento dentro de tu propio diseño.

Como una actividad:

startActivity(Intent(this, InboxActivity::class.java))

Como un fragmento:

supportFragmentManager.beginTransaction()
.replace(R.id.inboxContainer, PushwooshInboxUi.createInboxFragment())
.commitAllowingStateLoss()

Tipos de tarjetas

Anchor link to

La interfaz de usuario de la bandeja de entrada resuelve un tipo de tarjeta por mensaje. El resolutor lee displayType del objeto data del payload de la notificación push, que el SDK entrega bajo actionParams. Un displayType que nombra un tipo de tarjeta conocido siempre renderiza ese tipo, recurriendo a classic solo si faltan los campos requeridos del tipo. Esta resolución no depende de la configuración heurística a continuación.

Cuando displayType está ausente, el mensaje se renderiza como una fila simple a menos que optes por la heurística de imagen/texto:

PushwooshInboxStyle.richCardsHeuristicEnabled = true

Con la heurística activada, una imagen sin título renderiza banner, una imagen con título y cuerpo renderiza captioned, y cualquier otra cosa recurre a classic.

displayTypeAparienciaCampo de payload requeridoSe degrada a
bannerImagen a sangre completa, sin textoimage (icono del mensaje o data.attachment)classic cuando no hay imagen
captionedImagen en la parte superior, título + cuerpo debajoimage, title y content del mensajeclassic cuando falta la imagen, el título o el cuerpo
classicIcono + título + cuerpo— (se esperan título, cuerpo e icono)—
carouselGalería de múltiples imágenes deslizabletitle y content del mensaje, data.carousel (1–5 diapositivas)classic cuando no hay diapositivas o no hay título/cuerpo
videoPóster con insignia de reproducción, reproductor a pantalla completa al tocardata.video (url + poster opcional)classic cuando no hay descriptor

La tarjeta de Apple Wallet de InboxKit de iOS no tiene un equivalente en Android. Un mensaje con displayType: "wallet" siempre se renderiza como classic en Android.

Tarjeta de carrusel

Anchor link to

Las diapositivas se encuentran en data.carousel. Cada diapositiva necesita una image. title (superposición de leyenda) y url (se abre al tocar) son opcionales. Una diapositiva sin imagen se descarta, y se muestran como máximo 5 diapositivas.

POST https://api.pushwoosh.com/json/1.3/createMessage
{
"request": {
"application": "XXXXX-XXXXX",
"auth": "API_TOKEN",
"notifications": [{
"send_date": "now",
"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" }
]
},
"platforms": [3]
}]
}
}

Tarjeta de video

Anchor link to

El descriptor se encuentra en data.video: url es obligatorio, poster es una imagen de vista previa opcional. Al tocar el póster se abre un reproductor a pantalla completa.

POST https://api.pushwoosh.com/json/1.3/createMessage
{
"request": {
"application": "XXXXX-XXXXX",
"auth": "API_TOKEN",
"notifications": [{
"send_date": "now",
"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": [3]
}]
}
}

Leer datos personalizados de un mensaje

Anchor link to

Para que una notificación push aparezca en la bandeja de entrada, la solicitud createMessage de la API de Mensajes debe incluir inbox_image, inbox_date o inbox_days. Sin uno de esos campos, la notificación push se entrega como una notificación regular y nunca llega al feed de la bandeja de entrada. Los datos personalizados de formato libre van en data, que el SDK expone como actionParams en InboxMessage:

PushwooshInboxUi.onMessageClickListener = OnInboxMessageClickListener { message ->
val params = message.actionParams?.let { JSONObject(it) }
val promoId = params?.optString("promo_id")
if (!promoId.isNullOrEmpty()) {
navigateToPromo(promoId)
}
}

Añadir botones de CTA en línea

Anchor link to

Un mensaje puede llevar botones de llamada a la acción (CTA) en línea dentro de data.buttons:

POST https://api.pushwoosh.com/json/1.3/createMessage
{
"request": {
"application": "XXXXX-XXXXX",
"auth": "API_TOKEN",
"notifications": [{
"send_date": "now",
"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": [3]
}]
}
}

Cada botón necesita un title. La resolución sigue esta prioridad:

  • action establecido en dismiss o markRead (sin distinción de mayúsculas y minúsculas) ejecuta esa acción.
  • De lo contrario, una url no vacía y analizable se resuelve en una acción openURL.
  • De lo contrario, el toque se resuelve en una acción personalizada, y cada clave extra en el objeto del botón se reenvía a tu listener como su payload.

Intercepta los toques desde PushwooshInboxUi.onButtonClickListener. Devuelve true para permitir que el SDK realice la acción predeterminada del botón, false para suprimirla:

PushwooshInboxUi.onButtonClickListener = OnInboxButtonClickListener { message, button ->
when (val action = button.action) {
is InboxCardButton.Action.OpenUrl -> true
InboxCardButton.Action.Dismiss, InboxCardButton.Action.MarkRead -> true
is InboxCardButton.Action.Custom -> {
when (action.payload.optString("tag")) {
"save_promo" -> saveCurrentPromoLocally(message)
}
true
}
}
}

Personalizar el estilo

Anchor link to

Establece colores, fuentes y estados de vacío/error desde el código a través de PushwooshInboxStyle:

PushwooshInboxStyle.accentColor = ContextCompat.getColor(this, R.color.brand_accent)
PushwooshInboxStyle.titleColor = ContextCompat.getColor(this, R.color.brand_title)
PushwooshInboxStyle.listEmptyText = "Aún no tienes mensajes"
PushwooshInboxStyle.showToolbar = false

O aplica el mismo conjunto de atributos como un tema, listado en attrs.xml: inboxAccentColor, inboxTitleColor, inboxBackgroundColor, inboxDefaultIcon, y el resto de los atributos de color y apariencia. Ambos enfoques, además de una aplicación de muestra completa, se encuentran en el repositorio pushwoosh-inbox-ui-android-sdk InboxSample.

Insignia de mensajes no leídos

Anchor link to
PushwooshInbox.unreadMessagesCount { result ->
if (result.isSuccess) {
val count = result.data
} else {
Log.e("App", "Failed to get unread count", result.exception)
}
}