Cómo crear una notificación en Wear OS

En esta página se describe cómo crear notificaciones para un reloj. También se explica cómo proporcionar contenido adicional para cada notificación que se comparte en el reloj desde el teléfono conectado.

Las notificaciones en los relojes tienen la misma estructura que en los teléfonos. Además, a fin de que los usuarios disfruten de una experiencia óptima, Wear OS by Google proporciona API que permiten agregar a las notificaciones funciones específicas para wearables.

Cuando envías notificaciones desde tu app, cada una aparece como una tarjeta en el flujo de notificaciones.

Figura 1: La misma notificación como aparece en un teléfono y en un reloj

Tanto el reloj como el teléfono pueden ser fuentes de notificaciones. Usa la clase NotificationCompat.Builder para crear notificaciones compatibles con wearables. Cuando usas esta clase para compilar notificaciones, el sistema se encarga de mostrarlas correctamente.

Nota: Las notificaciones que usan RemoteViews no cuentan con diseños personalizados, por lo que el wearable solo muestra el texto y los íconos. No obstante, puedes desarrollar una app para wearables que se ejecute en el reloj y, de ese modo, crear notificaciones personalizadas que usen diseños de tarjetas también personalizados.

Importa las clases necesarias

Para importar los paquetes necesarios, agrega esta línea a tu archivo build.gradle:

    compile "com.android.support:support-v13:27.0.2"
    

Ahora que tu proyecto tiene acceso a los paquetes necesarios, importa las clases requeridas desde la biblioteca de compatibilidad:

Kotlin

    import android.support.v4.app.NotificationCompat
    import android.support.v4.app.NotificationManagerCompat
    import android.support.v4.app.NotificationCompat.WearableExtender
    

Java

    import android.support.v4.app.NotificationCompat;
    import android.support.v4.app.NotificationManagerCompat;
    import android.support.v4.app.NotificationCompat.WearableExtender;
    

Crea una notificación con el generador de notificaciones

La biblioteca de compatibilidad v4 te permite crear notificaciones usando las funciones más recientes, como íconos y botones de acción, sin que se pierda la compatibilidad con Android 1.6 (nivel de API 4) y versiones posteriores.

Nota: A partir de Android 8.0 (nivel de API 26), debes crear canales de notificación para cada tipo de notificación que quieras mostrar.

Para crear una notificación con la biblioteca de compatibilidad, sigue estos pasos:

  1. Crea una instancia de NotificationCompat.Builder.

    Kotlin

        val notificationId = 1
        // The channel ID of the notification.
        val id = "my_channel_01"
        // Build intent for notification content
        val viewPendingIntent = Intent(this, ViewEventActivity::class.java).let { viewIntent ->
            viewIntent.putExtra(EXTRA_EVENT_ID, eventId)
            PendingIntent.getActivity(this, 0, viewIntent, 0)
        }
    
        // Notification channel ID is ignored for Android 7.1.1
        // (API level 25) and lower.
        val notificationBuilder = NotificationCompat.Builder(this, id)
                .setSmallIcon(R.drawable.ic_event)
                .setContentTitle(eventTitle)
                .setContentText(eventLocation)
                .setContentIntent(viewPendingIntent)
        

    Java

        int notificationId = 001;
        // The channel ID of the notification.
        String id = "my_channel_01";
        // Build intent for notification content
        Intent viewIntent = new Intent(this, ViewEventActivity.class);
        viewIntent.putExtra(EXTRA_EVENT_ID, eventId);
        PendingIntent viewPendingIntent =
                PendingIntent.getActivity(this, 0, viewIntent, 0);
    
        // Notification channel ID is ignored for Android 7.1.1
        // (API level 25) and lower.
        NotificationCompat.Builder notificationBuilder =
            new NotificationCompat.Builder(this, id)
                .setSmallIcon(R.drawable.ic_event)
                .setContentTitle(eventTitle)
                .setContentText(eventLocation)
                .setContentIntent(viewPendingIntent);
        
  2. Envía la notificación pasando el objeto de notificación con un ID de notificación a notify().

    Kotlin

        NotificationManagerCompat.from(this).apply {
            notify(notificationId, notificationBuilder.build())
        }
        

    Java

        // Get an instance of the NotificationManager service
        NotificationManagerCompat notificationManager =
                NotificationManagerCompat.from(this);
    
        // Issue the notification with notification manager.
        notificationManager.notify(notificationId, notificationBuilder.build());
        

Cuando esta notificación aparece en un teléfono, el usuario puede tocarla para invocar el PendingIntent que especificó el método setContentIntent(). Cuando esta notificación aparece en un wearable, se muestra en el flujo de notificaciones. En el caso de las notificaciones compartidas, el usuario puede hacer clic en la notificación para ver la versión expandida y activar cualquier acción definida, como abrir. Por lo general, estas acciones abren una actividad en tu app para teléfonos.

Construye notificaciones expandidas

Las notificaciones expandidas proporcionan contenido y acciones adicionales considerables para cada notificación. Cuando especificas páginas de contenido y acciones adicionales para una notificación, el usuario puede acceder a ellas dentro de la notificación expandida. Cada notificación expandida sigue el enfoque de material design para Wear OS, por lo que el usuario obtiene una experiencia similar a la de una app.

Si la primera acción en la notificación expandida tiene una RemoteInput (por ejemplo, una acción de responder), las opciones que definas con setChoices() aparecerán dentro de la notificación expandida debajo de la primera acción.

El usuario puede ver la notificación expandida si presiona una notificación cuando se cumple alguna de estas condiciones:

  • Una app genera la notificación en el teléfono sincronizado y compartido con Wear.
  • La notificación no tiene un contentIntent.

Nota: Un color de fondo específico de una app definido para una notificación con el método setColor() solo se muestra cuando se expande la notificación.

Prácticas recomendadas para notificaciones expandidas

Para decidir cuándo usar notificaciones expandidas, sigue estos lineamientos:

  • Todas las notificaciones compartidas desde el teléfono sincronizado al dispositivo Wear usarán notificaciones expandidas.
  • Si se genera una notificación en una app que se ejecuta localmente en Wear, deberías hacer que el objetivo táctil de la notificación inicie el objeto de notificación con el ID de notificación dentro de tu app mediante un llamado a setContentIntent(). Recomendamos no usar notificaciones expandidas para notificaciones que generó una app que se ejecuta localmente en Wear.

Agrega notificaciones expandidas

Las notificaciones expandidas te permiten incluir contenido y acciones adicionales para una notificación. Tú eliges el nivel de detalle que proporcionarán las notificaciones de tu app, pero ten en cuenta que deberías incluir una cantidad moderada de detalles.

Agrega contenido adicional

Para mostrar texto adicional en tu notificación expandida, usa BigTextStyle.

Para agregar imágenes en tu notificación expandida, puedes usar BigPictureStyle. Si deseas agregar más de una imagen, usa el método addPage() junto con BigPictureStyle.

Acción principal

La notificación expandida contendrá una acción principal, que será la primera acción en la notificación, a menos que se especifique una distinta con setContentAction().

Acciones adicionales

Para especificar acciones adicionales, usa addAction() o addActions(). El panel lateral de acciones de la notificación expandida contiene todas las acciones disponibles.

Agrega acciones de notificación

Además de la acción de contenido principal definida por setContentIntent(), puedes agregar otras acciones si pasas un PendingIntent al método addAction().

Por ejemplo, en el siguiente código, se muestra el mismo tipo de notificación anterior, pero se agrega una acción para ver la ubicación del evento en un mapa.

Kotlin

    // Build an intent for an action to view a map
    val mapIntent = Intent(Intent.ACTION_VIEW)
    // The channel ID of the notification.
    val id = "my_channel_01"
    val mapPendingIntent = Intent(Intent.ACTION_VIEW).let { mapIntent ->
        mapIntent.data = Uri.parse("geo:0,0?q=" + Uri.encode(location))
        PendingIntent.getActivity(this, 0, mapIntent, 0)
    }

    val notificationBuilder = NotificationCompat.Builder(this, id)
            .setSmallIcon(R.drawable.ic_event)
            .setContentTitle(eventTitle)
            .setContentText(eventLocation)
            .setContentIntent(viewPendingIntent)
            .addAction(R.drawable.ic_map, getString(R.string.map), mapPendingIntent)
    

Java

    // Build an intent for an action to view a map
    Intent mapIntent = new Intent(Intent.ACTION_VIEW);
    // The channel ID of the notification.
    String id = "my_channel_01";
    Uri geoUri = Uri.parse("geo:0,0?q=" + Uri.encode(location));
    mapIntent.setData(geoUri);
    PendingIntent mapPendingIntent =
            PendingIntent.getActivity(this, 0, mapIntent, 0);

    NotificationCompat.Builder notificationBuilder =
            new NotificationCompat.Builder(this, id)
            .setSmallIcon(R.drawable.ic_event)
            .setContentTitle(eventTitle)
            .setContentText(eventLocation)
            .setContentIntent(viewPendingIntent)
            .addAction(R.drawable.ic_map,
                    getString(R.string.map), mapPendingIntent);
    

En un teléfono, la acción aparece como un botón adicional anexado a la notificación. En un wearable, la acción aparece en la notificación expandida después del texto del contenido. Cuando el usuario presiona la acción, se invoca el intent asociado en el teléfono.

Sugerencia: Si tus notificaciones incluyen una acción de "Respuesta" (por ejemplo, para una app de mensajes), puedes mejorar el comportamiento si habilitas las respuestas de entrada de voz directamente desde el wearable. Para obtener más información, consulta Agrega entradas de voz como una acción de notificación.

Agrega una acción intercalada

La acción intercalada permite a los usuarios realizar acciones en una notificación desde dentro de la tarjeta de flujo de notificaciones. En Wear, la acción intercalada aparece como un botón adicional en la parte inferior de la notificación.

Las acciones intercaladas son opcionales, pero se recomiendan cuando es probable que los usuarios realicen una acción en una notificación después de ver el contenido en la tarjeta de flujo de notificaciones (sin ir a la notificación expandida). Algunos ejemplos de casos prácticos relevantes para las acciones intercaladas en una notificación son responder un mensaje de texto, detener una actividad de entrenamiento y archivar un mensaje de correo electrónico.

Una notificación puede proporcionar solo una acción intercalada. Para que aparezca como un botón adicional en la notificación, define el método setHintDisplayActionInline() en "true". Cuando un usuario presiona la acción intercalada, el sistema invoca el intent que especificaste en la acción de notificación.

En el fragmento de código siguiente se agrega una sugerencia para mostrar una acción en formato intercalado y se usa el método addAction para agregar esa acción a la notificación.

Kotlin

    //Wear OS requires a hint to display the reply action inline.
    val actionExtender = NotificationCompat.Action.WearableExtender()
            .setHintLaunchesActivity(true)
            .setHintDisplayActionInline(true)
    wearableExtender.addAction(actionBuilder.extend(actionExtender).build())
    

Java

    //Wear OS requires a hint to display the reply action inline.
    Action.WearableExtender actionExtender =
        new Action.WearableExtender()
            .setHintLaunchesActivity(true)
            .setHintDisplayActionInline(true);
    wearableExtender.addAction(actionBuilder.extend(actionExtender).build());
    

Agrega funciones específicas de wearables a una notificación

Si alguna vez necesitas agregar funciones específicas de wearables a una notificación, por ejemplo, ocultar el ícono de la app en la notificación para wearables o permitir que los usuarios dicten una respuesta de texto con entrada de voz, puedes usar la clase NotificationCompat.WearableExtender para especificar las opciones. Para usar esta API, realiza lo siguiente:

  1. Crea una instancia de WearableExtender y configura las opciones específicas de wearables para la notificación.
  2. Crea una instancia de NotificationCompat.Builder y configura las propiedades que desees para tu notificación con los pasos que explicamos anteriormente en esta lección.
  3. Llama a extend() en la notificación y pasa el WearableExtender. Esto permite aplicar las opciones de wearables a la notificación.
  4. Llama a build() para compilar la notificación.

Nota: Si usas el NotificationManager del marco de trabajo, algunas funciones de NotificationCompat.WearableExtender dejan de funcionar, por lo que debes asegurarte de usar NotificationCompat.

Puedes sincronizar las cancelaciones de notificaciones en los dispositivos del usuario. Para habilitar la sincronización de una cancelación, usa el método setDismissalId(). Para cada notificación, pasa un ID único general, como una string, cuando llames al método setDismissalId(). Cuando se cancela la notificación, las demás notificaciones con el mismo ID de cancelación también se cancelan en los relojes y en el teléfono complementario. Para obtener un ID de cancelación, usa getDismissalId().

Nota: El método setBackground() no se admite en Wear 2.0. Puedes usar NotificationCompat.BigPictureStyle para las notificaciones que incluyen imágenes.

El método setHintHideIcon() tampoco se admite en Wear 2.0.

Especifica acciones exclusivas de wearables

Si quieres que las acciones disponibles en el wearable difieran de las acciones del teléfono, usa WearableExtender.addAction(). Una vez que agregas una acción con este método, el wearable no muestra ninguna otra acción agregada con NotificationCompat.Builder.addAction(). Las acciones que se agregaron con WearableExtender.addAction() aparecen solo en el wearable y no en el teléfono.

Agrega entradas de voz como una acción de notificación

Las acciones de voz son una parte importante de la experiencia con dispositivos wearable. Para desarrollar una acción que admita la entrada de voz, crea una instancia de RemoteInput.Builder que puedas agregar a tu acción de notificación. Este constructor de clase acepta una string que el sistema usa como la clave para la entrada de voz, que más tarde utilizarás para recuperar el texto de la entrada en tu app para teléfonos.

Por ejemplo, a continuación se muestra cómo crear un objeto RemoteInput que brinda una etiqueta personalizada para el mensaje de entrada de voz:

Kotlin

    // Key for the string that's delivered in the action's intent
    const val EXTRA_VOICE_REPLY = "extra_voice_reply"
    ...
    val remoteInput = resources.getString(R.string.reply_label).let { replyLabel ->
        RemoteInput.Builder(EXTRA_VOICE_REPLY)
                .setLabel(replyLabel)
                .build()
    }
    

Java

    // Key for the string that's delivered in the action's intent
    private static final String EXTRA_VOICE_REPLY = "extra_voice_reply";

    String replyLabel = getResources().getString(R.string.reply_label);

    RemoteInput remoteInput = new RemoteInput.Builder(EXTRA_VOICE_REPLY)
            .setLabel(replyLabel)
            .build();
    

Agrega respuestas de texto predefinidas

Además de permitir la entrada de voz, puedes brindar hasta cinco respuestas de texto para que el usuario elija si quiere enviar respuestas rápidas. Llama a setChoices() y pásale un arreglo de strings.

Por ejemplo, puedes definir algunas respuestas en un arreglo de recursos:

res/values/strings.xml

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <string-array name="reply_choices">
            <item>Yes</item>
            <item>No</item>
            <item>Maybe</item>
        </string-array>
    </resources>
    

A continuación, amplía el arreglo de strings y agrégalo a la clase RemoteInput:

Kotlin

    // Key for the string that's delivered in the action's intent
    const val EXTRA_VOICE_REPLY = "extra_voice_reply"
    ...
    val remoteInput = resources.getString(R.string.reply_label).let { replyLabel ->
        resources.getStringArray(R.array.reply_choices).let { replyChoices ->
            RemoteInput.Builder(EXTRA_VOICE_REPLY)
                    .setLabel(replyLabel)
                    .setChoices(replyChoices)
                    .build()
        }
    }
    

Java

    public static final String EXTRA_VOICE_REPLY = "extra_voice_reply";
    ...
    String replyLabel = getResources().getString(R.string.reply_label);
    String[] replyChoices = getResources().getStringArray(R.array.reply_choices);

    RemoteInput remoteInput = new RemoteInput.Builder(EXTRA_VOICE_REPLY)
            .setLabel(replyLabel)
            .setChoices(replyChoices)
            .build();
    

Recibe la entrada de voz en formato de string

Para recibir el mensaje transcrito del usuario en la actividad que declaraste en el intent de la acción de respuesta, llama a getResultsFromIntent() y pasa el intent de la acción "Respuesta". Este método muestra una Bundle que contiene la respuesta de texto. Luego, puedes enviar una consulta a Bundle para obtener la respuesta.

Nota: No uses Intent.getExtras() para obtener el resultado de voz, ya que la entrada de voz se almacena como ClipData. El método getResultsFromIntent() brinda una forma conveniente de recibir una secuencia de caracteres sin tener que procesar ClipData por tu cuenta.

El siguiente código muestra un método que acepta un intent y muestra la respuesta de voz, que se identifica con la clave EXTRA_VOICE_REPLY que se usa en los ejemplos anteriores:

Kotlin

    /**
     * Obtain the intent that started this activity by calling
     * Activity.getIntent() and pass it into this method to
     * get the associated voice input string.
     */

    private fun getMessageText(intent: Intent): CharSequence? =
            RemoteInput.getResultsFromIntent(intent)?.run {
                getCharSequence(EXTRA_VOICE_REPLY)
            }
    

Java

    /**
     * Obtain the intent that started this activity by calling
     * Activity.getIntent() and pass it into this method to
     * get the associated voice input string.
     */

    private CharSequence getMessageText(Intent intent) {
        Bundle remoteInput = RemoteInput.getResultsFromIntent(intent);
        if (remoteInput != null) {
            return remoteInput.getCharSequence(EXTRA_VOICE_REPLY);
        }
        return null;
    }
    

Kotlin

    // Create an intent for the reply action
    val actionPendingIntent = Intent(this, ActionActivity::class.java).let { actionIntent ->
        PendingIntent.getActivity(this, 0, actionIntent,
                PendingIntent.FLAG_UPDATE_CURRENT)
    }
    // Create the action
    val action = NotificationCompat.Action.Builder(
            R.drawable.ic_action,
            getString(R.string.label),
            actionPendingIntent
    ).build()

    // Build the notification and add the action via WearableExtender
    var notification = NotificationCompat.Builder(context)
            .setSmallIcon(R.drawable.ic_message)
            .setContentTitle(getString(R.string.title))
            .setContentText(getString(R.string.content))
            .extend(NotificationCompat.WearableExtender().addAction(action))
            .build()
    

Java

    // Create an intent for the reply action
    Intent actionIntent = new Intent(this, ActionActivity.class);
    PendingIntent actionPendingIntent =
            PendingIntent.getActivity(this, 0, actionIntent,
                    PendingIntent.FLAG_UPDATE_CURRENT);

    // Create the action
    NotificationCompat.Action action =
            new NotificationCompat.Action.Builder(R.drawable.ic_action,
                    getString(R.string.label), actionPendingIntent)
                    .build();

    // Build the notification and add the action via WearableExtender
    Notification notification =
            new NotificationCompat.Builder(context)
                    .setSmallIcon(R.drawable.ic_message)
                    .setContentTitle(getString(R.string.title))
                    .setContentText(getString(R.string.content))
                    .extend(new WearableExtender().addAction(action))
                    .build();
    

Inicia notificaciones desde apps independientes para wearables

Crear notificaciones desde una app independiente para relojes es igual a crear notificaciones compartidas. Las notificaciones que provienen de una app independiente para Wear tienen un aspecto similar a las compartidas, pero su comportamiento es levemente distinto. Si no se definió ningún contentIntent, o si la notificación se comparte desde un teléfono sincronizado, al presionar la notificación, se abre una notificación expandida. Mientras que, si la notificación se origina en una app independiente para reloj, al presionarla, se activa el contentIntent para abrir tu app para Wear. Para obtener más información sobre cómo crear notificaciones desde una app independiente y cómo imitar el comportamiento de la notificación expandida, consulta el ejemplo de notificaciones de Wear.

De forma predeterminada, las notificaciones se comparten desde la app de un teléfono complementario al reloj sincronizado. Si compilas una app independiente para relojes y tienes una app para teléfonos complementaria, estas pueden crear notificaciones duplicadas. Para obtener información sobre cómo solucionar el problema de las notificaciones duplicadas, consulta Modo puente para notificaciones.