Android Dev Summit, October 23-24: two days of technical content, directly from the Android team. Sign-up for livestream updates.

Criar uma notificação no Wear OS

Nesta página você aprende como criar notificações para um smartwatch e 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 para 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 cartões personalizados criando um app de wearables que é executado no smartwatch.

Importar as classes necessárias

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

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

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

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;
    

Usar o criador de notificações

A biblioteca de suporte v4 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 posterior.

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 com a Biblioteca de Suporte:

  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 passando 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(). Quando a notificação aparece em um wearable, ela aparece no stream de notificações. Quando há ponte, o usuário pode tocar na notificação para vê-la 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 "Responder"), o que for definido com setChoices() aparecerá abaixo da primeira ação.

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

  • A notificação foi gerada por um app no smartphone pareado e tem ponte com 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 em ponte 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. Caso queira adicionar mais de uma imagem à notificação expandida, use o método addPage() junto ao 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 outras ações, use addAction() ou addActions(). A gaveta de ações 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(), é possível adicionar outras ações passando 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, o intent associado é invocado 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 uma ação in-line como um botão extra na notificação, defina o método setHintDisplayActionInline() como verdadeiro. Quando o usuário tocar na ação in-line, o sistema invocará o intent especificado 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

Caso precise adicionar recursos específicos de wearable a uma notificação, como ocultar o ícone do app da notificação wearable ou permitir que os usuários ditem uma resposta com entrada de texto por voz, 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 passe 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 do NotificationCompat.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, passe um ID globalmente exclusivo, como uma string, ao 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 relacionado. 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 incluem imagens.

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

Especificar ações exclusivas de wearable

Caso queira que as ações disponíveis no wearable sejam diferentes das ações do smartphone, use WearableExtender.addAction(). Ao adicionar uma ação com esse método, o wearable não exibe nenhuma outra ação adicionada com NotificationCompat.Builder.addAction(). As ações adicionadas com WearableExtender.addAction() aparecem somente no wearable, e não 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 que seja compatível com a entrada de texto por voz, crie uma instância de RemoteInput.Builder que possa ser adicionada à ação da 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 passe uma matriz de string.

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 string 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 no intent da ação de resposta, chame getResultsFromIntent(), passando o 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. A entrada de texto por voz é armazenada como ClipData. O método getResultsFromIntent() oferece 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 um 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 em ponte. As notificações provenientes de um app Wear independente são semelhantes às notificações em ponte, mas se comportam de maneira um pouco diferente. Se nenhum contentIntent for definido ou se a notificação estiver em ponte com um smartphone pareado, tocar nela abrirá uma notificação expandida. Por outro lado, se a notificação for proveniente de um app de smartwatch independente, tocar na notificação ativará o contentIntent para abrir o app Wear. Para saber como criar notificações de um app independente e imitar o comportamento da notificação expandida, veja o exemplo Notificações do Wear (link em inglês).

Por padrão, as notificações são colocadas em ponte de um app em um smartphone complementar 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 bridge para notificações.