Criar uma notificação no Wear OS

Esta página descreve como criar notificações para um smartwatch. como inserir mais conteúdo para cada notificação que esteja em ponte com o smartwatch a partir de um smartphone conectado.

As notificações no smartwatch têm a mesma estrutura das notificações no smartphone. Além disso, para proporcionar a melhor experiência ao usuário, o Wear OS by Google tem APIs para adicionar recursos específicos de wearables às notificações.

Quando uma notificação é enviada do seu app, ela aparece como um cartão no stream de notificações.

Figura 1. A mesma notificação exibida no smartphone e no smartwatch.

Tanto o smartwatch quanto o smartphone podem ser fontes de notificações. Use a classe NotificationCompat.Builder para criar notificações de wearables. Quando você cria notificações com essa classe, o sistema cuida da exibição correta das notificações.

Observação: as notificações que usam RemoteViews são removidas dos layouts personalizados, e o wearable só exibe o texto e os ícones. No entanto, é possível criar notificações personalizadas que usam layouts de cards personalizados criando um app de wearables que é executado no smartwatch.

Normalmente, todas as notificações são transmitidas do smartphone para o smartwatch. No entanto, as notificações não são transmitidas nos seguintes casos:

Importar as classes necessárias

Para importar os pacotes necessários, adicione esta linha ao arquivo build.gradle:

    implementation 'androidx.core:core:1.2.0'
    

Agora que seu projeto tem acesso aos pacotes, importe as classes necessárias da Biblioteca de Suporte:

Kotlin

    import androidx.core.app.NotificationCompat
    import androidx.core.app.NotificationManagerCompat
    import androidx.core.app.NotificationCompat.WearableExtender
    

Java

    import androidx.core.app.NotificationCompat;
    import androidx.core.app.NotificationManagerCompat;
    import androidx.core.app.NotificationCompat.WearableExtender;
    

Usar o criador de notificações

A biblioteca Jetpack Core permite criar notificações usando os recursos mais recentes, como botões de ação e ícones, mantendo a compatibilidade com o Android 1.6 (API de nível 4) e mais recentes.

Observação: a partir do Android 8.0 (API de nível 26), é necessário criar canais de notificação para cada tipo de notificação que você quiser exibir.

Para criar uma notificação:

  1. Crie uma instância 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. Emita a notificação transmitindo o objeto de notificação com um ID para 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());
        

Quando essa notificação aparece em um smartphone, o usuário pode tocar nela para invocar o PendingIntent especificado pelo método setContentIntent(), tocando na notificação. Quando a notificação aparece em um wearable, ela aparece no stream de notificações. Para notificações transmitidas, o usuário pode tocar para ver a notificação expandida e ativar qualquer ação definida, como abrir. Normalmente, essa ação abre uma Atividade no app do smartphone.

Construir notificações expandidas

As notificações expandidas mostram mais conteúdo e ações importantes para cada notificação. Quando você especifica outras páginas de conteúdo e ações para uma notificação, esses itens ficam disponíveis para o usuário dentro da notificação expandida. Cada um deles segue o Material Design para Wear OS (link em inglês) para que o usuário tenha uma experiência semelhante ao app.

Se a primeira ação na notificação expandida tiver um RemoteInput (por exemplo, uma ação de resposta), as opções definidas com setChoices() aparecerão na notificação expandida abaixo da primeira ação.

O usuário pode tocar para ver a notificação expandida quando uma das afirmações a seguir for verdadeira:

  • A notificação foi gerada por um app no smartphone pareado e transmitida para o Wear.
  • A notificação não tem um contentIntent.

Observação: uma cor de plano de fundo específica do app definida para uma notificação com o método setColor() é exibida apenas quando você expande a notificação.

Práticas recomendadas para notificações expandidas

Para decidir quando usar notificações expandidas, siga as seguintes instruções:

  • Todas as notificações transmitidas do smartphone pareado ao dispositivo Wear usam notificações expandidas.
  • Se uma notificação for gerada por um app executado localmente no Wear, é recomendado fazer com que a área de toque da notificação inicie um objeto de notificação com um ID dentro do app, chamando setContentIntent(). Recomendamos que você não use notificações expandidas geradas por um app executado localmente no Wear.

Adicionar notificações expandidas

As notificações expandidas permitem que você acrescente conteúdo adicional e ações importantes para notificações. Você pode escolher o nível de detalhe que a notificação do app terá. Entretanto, tenha cuidado com a quantidade de detalhes incluídos em uma notificação.

Adicionar mais conteúdo

Para adicionar texto à notificação expandida, use BigTextStyle.

Para adicionar imagens à notificação expandida, use BigPictureStyle. Se você quiser adicionar mais de uma imagem à notificação expandida, use o método addPage() junto com o BigPictureStyle.

Ação principal

A notificação expandida terá uma ação principal, que será a primeira ação na notificação se nenhuma outra for especificada usando setContentAction().

Outras ações

Para especificar ações adicionais, use addAction() ou addActions(). A gaveta de ação da notificação expandida contém todas as ações disponíveis.

Adicionar ações de notificação

Além da ação de conteúdo principal definida por setContentIntent(), você pode adicionar outras ações transmitindo um PendingIntent para o método addAction().

Por exemplo, o código a seguir mostra o mesmo tipo de notificação acima, mas adiciona uma ação para ver o local do evento em um 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);
    

Em um smartphone, a ação aparece como um outro botão anexado à notificação Em um wearable, a ação aparece na notificação expandida após o texto do conteúdo. Quando o usuário toca na ação, a intent associada é invocada no smartphone.

Dica: se as notificações incluírem uma ação "Responder" (como no caso de um app de mensagens), é possível melhorar o comportamento ativando a entrada de respostas por voz diretamente do wearable. Para mais informações, leia Adicionar entrada de texto por voz como ação de notificação.

Adicionar uma ação in-line

Ações in-line permitem que os usuários realizem ações em uma notificação dentro do card de stream. No Wear, a ação in-line aparece como um botão extra exibido na parte inferior da notificação.

Ações in-line são opcionais, mas são recomendadas para casos em que usuários realizem ações em uma notificação após ver o conteúdo no card de stream de notificações (sem acessar a notificação expandida). Exemplos de bons casos de uso para uma ação in-line em uma notificação incluem: responder a uma mensagem de texto, interromper uma atividade de condicionamento físico ou arquivar uma mensagem de e-mail.

Uma notificação pode fornecer apenas uma ação in-line. Para exibir a ação in-line como um botão adicional na notificação, defina o método setHintDisplayActionInline() como "true". Quando o usuário tocar na ação in-line, o sistema invocará a intent especificada na ação de notificação.

O snippet de código a seguir acrescenta uma sugestão para exibir uma ação in-line e usa o método addAction para adicionar a ação a uma notificação.

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());
    

Adicionar recursos específicos de wearable a uma notificação

Se você precisar adicionar recursos específicos do wearable a uma notificação, como ocultar um ícone de app da notificação wearable ou permitir que os usuários ditem uma resposta com entrada de texto, use a classe NotificationCompat.WearableExtender para especificar as opções. Para usar essa API:

  1. Crie uma instância de um WearableExtender, definindo as opções específicas de wearable para a notificação.
  2. Crie uma instância de NotificationCompat.Builder, definindo as propriedades desejadas para sua notificação conforme descrito anteriormente nesta lição.
  3. Chame extend() na notificação e transmita o WearableExtender. Isso aplica as opções de wearable à notificação.
  4. Chame build() para criar a notificação.

Observação: se você usar o NotificationManager do framework, alguns recursos doNotificationCompat.WearableExtender não funcionarão, então use NotificationCompat.

É possível sincronizar as dispensas (os cancelamentos) de notificações nos dispositivos do usuário. Para permitir que uma dispensa seja sincronizada, use o método setDismissalId(). Para cada notificação, transmita um ID globalmente exclusivo, como uma string, quando você chamar o método setDismissalId(). Quando a notificação for dispensada, todas as outras notificações com o mesmo ID serão dispensadas nos smartwatches e no smartphone associado. Para recuperar um ID de dispensa, use getDismissalId().

Observação:o método setBackground() não é compatível com o Wear 2.0. Você pode usar NotificationCompat.BigPictureStyle para notificações que incluam imagens.

O método setHintHideIcon() também não é compatível com o Wear 2.0.

Especificar ações exclusivas de wearable

Se você quiser que as ações disponíveis no wearable sejam diferentes das ações no smartphone, use WearableExtender.addAction(). Depois de adicionar uma ação com esse método, o wearable não exibirá outras ações adicionadas com NotificationCompat.Builder.addAction(). As ações adicionadas com WearableExtender.addAction() aparecem somente no wearable e não aparecem no smartphone.

Adicionar entrada de texto por voz como ação de notificação

Ações por voz são uma parte importante da experiência com wearable. Para criar uma ação compatível com a entrada de texto por voz, crie uma instância de RemoteInput.Builder que você possa adicionar à sua ação de notificação. O construtor dessa classe aceita uma string que é usada pelo sistema como chave da entrada de texto por voz, que você usará para recuperar o texto da entrada no app do smartphone.

Por exemplo, veja como criar um objeto RemoteInput que fornece um marcador personalizado para a solicitação de entrada de texto por 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();
    

Adicionar respostas de texto predefinidas

Além de permitir a entrada de texto por voz, você pode fornecer até cinco respostas de texto que o usuário pode selecionar para responder rapidamente. Chame setChoices() e transmita uma matriz de strings.

Por exemplo, você pode definir algumas respostas em uma matriz 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>
    

Em seguida, aumente a matriz de strings e adicione-a ao 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();
    

Receber a entrada de texto por voz como uma string

Para receber a mensagem transcrita do usuário na atividade declarada na intent da ação de resposta, chame getResultsFromIntent(), transmitindo a intent da ação "Responder". Esse método retorna um Bundle que contém a resposta de texto. Você pode consultar o Bundle para receber a resposta.

Observação: não use Intent.getExtras() para receber o resultado de voz, porque a entrada de voz é armazenada como ClipData. O método getResultsFromIntent() fornece uma maneira conveniente de receber uma sequência de caracteres sem precisar processar o ClipData.

O código a seguir mostra um método que aceita uma intent e retorna a resposta de texto por voz, que é referenciada pela chave EXTRA_VOICE_REPLY, usada nos exemplos 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();
    

Abrir notificações de apps wearable independentes

Criar notificações de um app de smartwatch independente é o mesmo que criar notificações transmitidas. As notificações provenientes de um app Wear independente são semelhantes às notificações transmitidas, mas se comportam de maneira um pouco diferente. Se nenhuma contentIntent estiver configurada ou se a notificação for feita a partir de um smartphone pareado, tocar na notificação abrirá uma notificação expandida. Se a notificação for originada de um app de smartwatch independente, tocar na notificação acionará o contentIntent para abrir o app Wear. Para saber como criar notificações a partir de um app independente e imitar o comportamento de notificação expandida, consulte a amostra Notificações do Wear (em inglês).

Por padrão, as notificações são transmitidas de um app em um smartphone associado para um smartwatch pareado. Se você criar um app de smartwatch independente e tiver um app de smartphone complementar, eles podem gerar notificações duplicadas. Para mais informações sobre como lidar com problemas de notificações duplicadas, consulte Modo de transmissão para notificações.