Las notificaciones proporcionan información breve y oportuna sobre eventos de tu app cuando no está en uso. En este documento, se muestra cómo crear una notificación con varias funciones. Para obtener una introducción a cómo aparecen las notificaciones en Android, consulta la Descripción general de las notificaciones. Para ver un código de muestra que use notificaciones, consulta la muestra de SociaLite en GitHub.
El código de esta página usa las APIs de NotificationCompat de la biblioteca de AndroidX. Estas APIs te permiten agregar funciones disponibles solo en versiones más recientes de Android, a la vez que proporcionan compatibilidad con Android 9 (nivel de API 28).
Sin embargo, algunas funciones, como la acción de respuesta intercalada, no se ejecutan en versiones anteriores.
Cómo crear una notificación básica
Una notificación en su forma más básica y compacta, también conocida como forma contraída, muestra un ícono, un título y una pequeña cantidad de contenido de texto. En esta sección, se muestra cómo crear una notificación que el usuario puede presionar para iniciar una actividad en tu app.
Figura 1: Una notificación con un ícono, un título y un texto.
Para obtener más detalles sobre cada parte de una notificación, consulta Anatomía de una notificación.
Declara el permiso de tiempo de ejecución
Android 13 (nivel de API 33) y versiones posteriores admiten un permiso de tiempo de ejecución para publicar notificaciones no exentas (incluidos los servicios en primer plano [FGS]) desde una app.
El permiso que debes declarar en el archivo del manifiesto de tu app aparece en el siguiente fragmento de código:
<manifest ...> <uses-permission android:name="android.permission.POST_NOTIFICATIONS"/> <application ...> ... </application> </manifest>
Para obtener más detalles sobre los permisos de tiempo de ejecución, consulta Permiso de tiempo de ejecución de notificaciones.
Cómo definir el contenido de la notificación
Para comenzar, configura el contenido y el canal de la notificación con un objeto NotificationCompat.Builder. En el siguiente ejemplo, se muestra cómo
crear una notificación con lo siguiente:
Un ícono pequeño, establecido por
setSmallIcon()Este es el único contenido visible para el usuario que es obligatorio.Un título, establecido por
setContentTitle().Es el texto del cuerpo, establecido por
setContentText().La prioridad de la notificación, que se establece con
setPriority(). La prioridad determina qué tan intrusiva es la notificación en Android 7.1 y versiones anteriores. En Android 8.0 y versiones posteriores, establece la importancia del canal como se muestra en la siguiente sección.
val textTitle = "Title" val textContent = "Content" val builder = NotificationCompat.Builder(context, CHANNEL_ID) .setSmallIcon(R.drawable.ic_logo) .setContentTitle(textTitle) .setContentText(textContent) .setPriority(NotificationCompat.PRIORITY_DEFAULT)
El constructor NotificationCompat.Builder requiere que proporciones un ID de canal. Esto es necesario para la compatibilidad con Android 8.0 (nivel de API 26) y versiones posteriores, pero se ignora en las versiones anteriores.
De forma predeterminada, el contenido de texto de la notificación se trunca para que quepa en una línea. Puedes mostrar información adicional creando una notificación expandible.
Figura 2: Una notificación expandible en sus formas contraída y expandida
Si quieres que la notificación sea más larga, puedes habilitar una notificación expandible agregando una plantilla de estilo con setStyle(). Por ejemplo, el siguiente código crea un área de texto más grande:
val builder = NotificationCompat.Builder(context, CHANNEL_ID) .setSmallIcon(R.drawable.ic_logo) .setContentTitle("My notification") .setContentText("Much longer text that cannot fit one line...") .setStyle(NotificationCompat.BigTextStyle() .bigText("Much longer text that cannot fit one line...")) .setPriority(NotificationCompat.PRIORITY_DEFAULT)
Para obtener más información sobre otros estilos de notificaciones grandes, como agregar una imagen y controles de reproducción de contenido multimedia, consulta Cómo crear una notificación expandible.
Cómo crear un canal y definir la importancia
Antes de poder entregar la notificación en Android 8.0 y versiones posteriores, registra el canal de notificaciones de tu app en el sistema pasando una instancia de NotificationChannel a createNotificationChannel(). El siguiente código está bloqueado por una condición en la versión SDK_INT:
fun createNotificationChannel(context: Context) { // Create the NotificationChannel, but only on API 26+ because // the NotificationChannel class is not in the Support Library. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { val name = context.getString(R.string.channel_name) val descriptionText = context.getString(R.string.channel_description) val importance = NotificationManager.IMPORTANCE_DEFAULT val channel = NotificationChannel(CHANNEL_ID, name, importance).apply { description = descriptionText } // Register the channel with the system. val notificationManager: NotificationManager = context.getSystemService(NotificationManager::class.java) as NotificationManager notificationManager.createNotificationChannel(channel) } }
Debido a que debes crear el canal de notificaciones antes de publicar notificaciones en Android 8.0 y versiones posteriores, ejecuta este código cuando se inicie la app. Es seguro llamarlo de forma repetida, ya que crear un canal existente no tiene ningún efecto.
El constructor NotificationChannel requiere un nivel de importancia con una constante NotificationManager. Esto determina cómo interrumpir al
usuario. Para admitir Android 7.1 y versiones anteriores, también debes establecer la prioridad con setPriority(), como se muestra en el ejemplo anterior.
Aunque debes establecer la importancia o la prioridad, el sistema no garantiza el comportamiento de la alerta. El sistema puede ajustarlo según otros factores, y el usuario siempre puede personalizar el nivel de importancia del canal.
Para obtener más información sobre el significado de los diferentes niveles, consulta los niveles de importancia de las notificaciones.
Cómo establecer la acción de toque de la notificación
Cada notificación debe responder a una presión, por lo general, para abrir una actividad en tu app que corresponda a la notificación. Para ello, especifica un intent de contenido definido con un objeto PendingIntent y pásalo a setContentIntent().
En el siguiente fragmento, se muestra cómo crear un intent básico para abrir una actividad cuando el usuario presiona la notificación:
// Create an explicit intent for an Activity in your app. val intent = Intent(context, AlertDetails::class.java).apply { flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK } val pendingIntent: PendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE) val builder = NotificationCompat.Builder(context, CHANNEL_ID) .setSmallIcon(R.drawable.ic_logo) .setContentTitle("My notification") .setContentText("Hello World!") .setPriority(NotificationCompat.PRIORITY_DEFAULT) // Set the intent that fires when the user taps the notification. .setContentIntent(pendingIntent) .setAutoCancel(true)
Este código llama a setAutoCancel(), que quita la notificación automáticamente cuando el usuario la presiona.
Los indicadores de intents del ejemplo anterior preservan la experiencia de navegación esperada del usuario después de que abre tu app con la notificación. Es posible que quieras usarlo según el tipo de actividad que inicies, que puede ser una de las siguientes:
Una actividad que existe exclusivamente para respuestas a la notificación. No hay motivos para que el usuario navegue a esta actividad durante el uso normal de la app, por lo que la actividad inicia una tarea nueva en lugar de agregarse a la tarea y pila de actividades existentes de tu app. Este es el tipo de intent que se creó en el ejemplo anterior.
Una actividad que existe en el flujo regular de la app. En este caso, iniciar la actividad crea una pila de actividades para que se conserven las expectativas del usuario respecto de los botones Atrás y Arriba.
Cómo mostrar la notificación
Para que aparezca la notificación, llama a NotificationManagerCompat.notify() y pásale un ID único para la notificación y el resultado de NotificationCompat.Builder.build(). Esto se muestra en el siguiente ejemplo:
with(NotificationManagerCompat.from(context)) { if (ActivityCompat.checkSelfPermission( context, Manifest.permission.POST_NOTIFICATIONS ) != PackageManager.PERMISSION_GRANTED ) { // TODO: Consider calling ActivityCompat#requestPermissions here // to request the missing permissions, and then overriding // public fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, // grantResults: IntArray) // to handle the case where the user grants the permission. See the documentation // for ActivityCompat#requestPermissions for more details. return@with } // notificationId is a unique int for each notification that you must define. notify(notificationId, builder.build())
Guarda el ID de notificación que pasas a NotificationManagerCompat.notify(),
ya que lo necesitas cuando quieras actualizar o
quitar la notificación.
Además, para probar las notificaciones básicas en dispositivos que ejecutan Android 13 y versiones posteriores, activa las notificaciones de forma manual o crea un diálogo para solicitarlas.
Cómo agregar botones de acción
Una notificación puede ofrecer hasta tres botones de acción que permiten al usuario responder con rapidez, por ejemplo, para posponer un recordatorio o responder un mensaje de texto. Sin embargo, estos botones de acción no deben duplicar la acción que se realiza cuando el usuario presiona la notificación.
Figura 3: Una notificación con un botón de acción.
Para agregar un botón de acción, pasa un PendingIntent al método addAction(). Esto es como configurar la acción de presionar predeterminada de la notificación, excepto que, en lugar de iniciar una actividad, puedes hacer otras cosas, como iniciar un BroadcastReceiver que realice un trabajo en segundo plano para que la acción no interrumpa la app que ya está abierta.
Por ejemplo, en el siguiente código, se muestra cómo enviar una transmisión a un receptor específico:
val ACTION_SNOOZE = "snooze" val snoozeIntent = Intent(context, MyBroadcastReceiver::class.java).apply { action = ACTION_SNOOZE putExtra(EXTRA_NOTIFICATION_ID, 0) } val snoozePendingIntent: PendingIntent = PendingIntent.getBroadcast(context, 0, snoozeIntent, PendingIntent.FLAG_IMMUTABLE) val builder = NotificationCompat.Builder(context, CHANNEL_ID) .setSmallIcon(R.drawable.ic_logo) .setContentTitle("My notification") .setContentText("Hello World!") .setPriority(NotificationCompat.PRIORITY_DEFAULT) .setContentIntent(pendingIntent) .addAction(R.drawable.snooze, context.getString(R.string.snooze), snoozePendingIntent)
Para obtener más información sobre cómo compilar un BroadcastReceiver para ejecutar trabajo en segundo plano, consulta la descripción general de las transmisiones.
Si, en cambio, intentas compilar una notificación con botones de reproducción de contenido multimedia, como para pausar y omitir pistas, consulta cómo crear una notificación con controles multimedia.
Cómo agregar una acción de respuesta directa
La acción de respuesta directa, que se introdujo en Android 7.0 (nivel de API 24), permite que los usuarios ingresen texto directamente en la notificación. Luego, el texto se entrega a tu app sin abrir una actividad. Por ejemplo, puedes usar una acción de respuesta directa para permitir que los usuarios respondan mensajes de texto o actualicen listas de tareas desde la notificación.
Figura 4: Cuando se presiona el botón "Responder", se abre la entrada de texto.
La acción de respuesta directa aparece como un botón adicional en la notificación que abre una entrada de texto. Cuando el usuario termina de escribir, el sistema adjunta la respuesta de texto al intent que especificas para la acción de notificación y envía el intent a tu app.
Cómo agregar el botón de respuesta
Para crear una acción de notificación que admita la respuesta directa, sigue estos pasos:
Crea una instancia de RemoteInput.Builder que puedas agregar a tu acción de notificación. El constructor de esta clase acepta una cadena que el sistema usa como clave para la entrada de texto. Luego, tu app usa esa clave para recuperar el texto de la entrada.
// Key for the string that's delivered in the action's intent. val replyLabel: String = context.resources.getString(R.string.reply_label) val remoteInput: RemoteInput = RemoteInput.Builder(KEY_TEXT_REPLY).run { setLabel(replyLabel) build() }
Crea un PendingIntent para la acción de respuesta.
// Build a PendingIntent for the reply action to trigger. val replyPendingIntent: PendingIntent = PendingIntent.getBroadcast(context, conversationId, getMessageReplyIntent(conversationId), PendingIntent.FLAG_MUTABLE)
Adjunta el objeto RemoteInput a una acción con
addRemoteInput().
// Create the reply action and add the remote input. val action: NotificationCompat.Action = NotificationCompat.Action.Builder(R.drawable.reply, context.getString(R.string.reply_label), replyPendingIntent) .addRemoteInput(remoteInput) .build()
Aplica la acción a una notificación y emite la notificación.
// Build the notification and add the action.
val newMessageNotification = NotificationCompat.Builder(context, CHANNEL_ID)
.setSmallIcon(R.drawable.ic_message)
.setContentTitle(context.getString(R.string.title))
.setContentText(context.getString(R.string.content))
.addAction(action)
.build()
// Issue the notification.
NotificationManagerCompat.from(context).notify(notificationId, newMessageNotification)
El sistema le solicita al usuario que ingrese una respuesta cuando activa la acción de notificación, como se muestra en la figura 4.
Cómo recuperar entradas del usuario a partir de la respuesta
Para recibir la entrada del usuario desde la IU de respuesta de la notificación, llama a RemoteInput.getResultsFromIntent() y pásale el Intent que recibió tu BroadcastReceiver:
private fun getMessageText(intent: Intent): CharSequence? { return RemoteInput.getResultsFromIntent(intent)?.getCharSequence(KEY_TEXT_REPLY) }
Después de procesar el texto, llama a NotificationManagerCompat.notify() con el mismo ID y la misma etiqueta, si se usa, para actualizar la notificación. Esto es necesario para ocultar la IU de respuesta directa y confirmar al usuario que su respuesta se recibió y procesó correctamente.
// Build a new notification, which informs the user that the system // handled their interaction with the previous notification. val repliedNotification = NotificationCompat.Builder(context, CHANNEL_ID) .setSmallIcon(R.drawable.message) .setContentText(context.getString(R.string.replied)) .build() // Issue the new notification. NotificationManagerCompat.from(context).notify(notificationId, repliedNotification)
Recupera otros datos
El manejo de otros tipos de datos funciona de manera similar con RemoteInput. En el siguiente
ejemplo, se usa una imagen como entrada.
val replyLabel: String = context.resources.getString(R.string.reply_label) val remoteInput: RemoteInput = RemoteInput.Builder(KEY_REPLY).run { setLabel(replyLabel) // Allow for image data types in the input. // This method can be used again to allow for other data types. setAllowDataType("image/*", true) build() }
Llama a RemoteInput#getDataResultsFromIntent y extrae los datos correspondientes.
class ReplyReceiver : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { val dataResults = RemoteInput.getDataResultsFromIntent(intent, KEY_REPLY) val imageUri: Uri? = dataResults?.get("image/*") as? Uri if (imageUri != null) { // Extract the image context.contentResolver.openInputStream(imageUri)?.use { inputStream -> val bitmap = BitmapFactory.decodeStream(inputStream) // Display the image // ... } } } companion object { const val KEY_REPLY = "key_reply" const val KEY_TEXT_REPLY = "key_text_reply" } }
Cuando trabajes con esta notificación nueva, usa el contexto que se pasa al método onReceive() del receptor.
Llama a setRemoteInputHistory() para agregar la respuesta al final de la notificación. Sin embargo, si estás creando una app de mensajería, crea una notificación de estilo de mensajería y agrega el mensaje nuevo a la conversación.
Para obtener más consejos sobre las notificaciones de las apps de mensajería, consulta la sección sobre las prácticas recomendadas para las apps de mensajería.
Cómo mostrar un mensaje urgente
Es posible que tu app deba mostrar un mensaje urgente y con un plazo determinado, como una llamada telefónica entrante o una alarma que suena. En estas situaciones, puedes asociar un intent de pantalla completa con tu notificación.
Cuando se invoca la notificación, los usuarios ven una de las siguientes opciones, según el estado de bloqueo del dispositivo:
- Si el dispositivo del usuario está bloqueado, aparecerá una actividad de pantalla completa que cubrirá la pantalla de bloqueo.
- Si el dispositivo del usuario está desbloqueado, la notificación aparece en un formato expandido que incluye opciones para administrarla o descartarla.
En el siguiente fragmento de código, se muestra cómo asociar tu notificación con un intent de pantalla completa:
val fullScreenIntent = Intent(context, ImportantActivity::class.java) val fullScreenPendingIntent = PendingIntent.getActivity(context, 0, fullScreenIntent, PendingIntent.FLAG_IMMUTABLE) val builder = NotificationCompat.Builder(context, CHANNEL_ID) .setSmallIcon(R.drawable.ic_logo) .setContentTitle("My notification") .setContentText("Hello World!") .setPriority(NotificationCompat.PRIORITY_DEFAULT) .setFullScreenIntent(fullScreenPendingIntent, true)
Cómo establecer la visibilidad de la pantalla de bloqueo
Para controlar el nivel de detalle visible en la notificación desde la pantalla de bloqueo, llama a setVisibility() y especifica uno de los siguientes valores:
VISIBILITY_PUBLIC: El contenido completo de la notificación se muestra en la pantalla de bloqueo.VISIBILITY_SECRET: No se muestra ninguna parte de la notificación en la pantalla de bloqueo.VISIBILITY_PRIVATE: Solo se muestra información básica, como el ícono de la notificación y el título del contenido, en la pantalla de bloqueo. No se muestra el contenido completo de la notificación.
Cuando configuras VISIBILITY_PRIVATE, también puedes proporcionar una versión alternativa del contenido de la notificación que oculte ciertos detalles. Por ejemplo, una app de SMS podría mostrar una notificación que diga "Tienes 3 mensajes de texto nuevos", pero ocultar el contenido y los remitentes de los mensajes. Para proporcionar esta notificación alternativa, primero créala con NotificationCompat.Builder como de costumbre. Luego, adjunta la notificación alternativa a la normal con setPublicVersion().
Ten en cuenta que el usuario siempre tiene el control definitivo sobre si sus notificaciones son visibles en la pantalla de bloqueo y puede controlarlas según los canales de notificaciones de tu app.
Cómo actualizar una notificación
Para actualizar una notificación después de emitirla, vuelve a llamar a NotificationManagerCompat.notify() y pásale el mismo ID que usaste antes. Si se descarta la notificación anterior, se crea una nueva.
De manera opcional, puedes llamar a setOnlyAlertOnce() para que tu notificación interrumpa al usuario (con sonido, vibración o pistas visuales) solo la primera vez que aparece la notificación y no para actualizaciones posteriores.
Cómo quitar una notificación
Las notificaciones permanecen visibles hasta que alguna de estas acciones tiene lugar:
- El usuario descarta la notificación.
- El usuario presiona la notificación, si llamas a
setAutoCancel()cuando creas la notificación. - Llamas a
cancel()para obtener un ID de notificación específico. Este método también borra las notificaciones en curso. - Llamas a
cancelAll(), que quita todas las notificaciones que emitiste anteriormente. - Transcurre la duración especificada, si estableces un tiempo de espera cuando creas la
notificación, con
setTimeoutAfter(). Si es necesario, puedes cancelar una notificación antes de que transcurra el tiempo de espera especificado.
Prácticas recomendadas para apps de mensajería
Ten en cuenta las prácticas recomendadas que se indican aquí cuando crees notificaciones para tus apps de mensajería y chat.
Usa MessagingStyle
A partir de Android 7.0 (nivel de API 24), Android proporciona una plantilla de estilo de notificación específica para el contenido de mensajes. Con la clase NotificationCompat.MessagingStyle, puedes cambiar varias de las etiquetas que se muestran en la notificación, como el título de la conversación, los mensajes adicionales y la vista de contenido de la notificación.
En el siguiente fragmento de código, se muestra cómo personalizar el estilo de una notificación con la clase MessagingStyle.
val message1 = NotificationCompat.MessagingStyle.Message( messages[0].text, messages[0].time, messages[0].sender ) val message2 = NotificationCompat.MessagingStyle.Message( messages[1].text, messages[1].time, messages[1].sender ) notification = NotificationCompat.Builder(context, CHANNEL_ID) .setSmallIcon(R.drawable.ic_logo) .setStyle( NotificationCompat.MessagingStyle(Person.Builder().setName("Me").build()) .addMessage(message1) .addMessage(message2) ) .build()
A partir de Android 9.0 (nivel de API 28), también se requiere usar la clase Person para obtener una renderización óptima de la notificación y sus avatares.
Cuando uses NotificationCompat.MessagingStyle, haz lo siguiente:
- Llama a
MessagingStyle.setConversationTitle()para establecer un título para los chats en grupo con más de dos personas. Un buen título de conversación podría ser el nombre del chat en grupo o, si no tiene un nombre, una lista de los participantes de la conversación. Sin esto, el mensaje podría confundirse con uno que pertenece a una conversación individual con el remitente del mensaje más reciente de la conversación. - Usa el método
MessagingStyle.setData()para incluir mensajes multimedia, como imágenes. Se admiten los tipos de MIME del patrón image/*.
Usa la Respuesta directa
La respuesta directa permite que un usuario responda un mensaje de forma intercalada.
- Después de que un usuario responda con la acción de respuesta intercalada, usa
MessagingStyle.addMessage()para actualizar la notificación deMessagingStyle, y no la retires ni la canceles. Si no cancelas la notificación, el usuario podrá enviar varias respuestas desde ella. - Para que la acción de respuesta intercalada sea compatible con Wear OS, llama a
Action.WearableExtender.setHintDisplayInlineAction(true). - Usa el método
addHistoricMessage()para proporcionar contexto a una conversación de respuesta directa agregando mensajes históricos a la notificación.
Habilita la Respuesta inteligente
- Para habilitar la Respuesta inteligente, llama a
setAllowGeneratedResponses(true)en la acción de respuesta. Esto hace que las respuestas de Respuesta inteligente estén disponibles para los usuarios cuando la notificación se transfiere a un dispositivo Wear OS. Las respuestas de Respuesta inteligente se generan con un modelo de aprendizaje automático que se ejecuta por completo en el reloj y usa el contexto que proporciona la notificaciónNotificationCompat.MessagingStyle. No se suben datos a Internet para generar las respuestas.
Agrega metadatos de notificación
- Asigna metadatos de notificación para indicarle al sistema cómo controlar las notificaciones de tu app cuando el dispositivo está en modo No interrumpir. Por ejemplo, usa el método
addPerson()osetCategory(Notification.CATEGORY_MESSAGE)para anular el modo No interrumpir.