Guia de instruções: integração às Notificações do Graph (Android)

Notificações do Graph permitem que seu aplicativo envie e gerencie notificações direcionadas a usuários em vários dispositivos.

Com o SDK do lado do cliente do Project Rome no Android, o aplicativo Android pode se registrar para receber notificações publicadas de seu servidor de aplicativo direcionado a um usuário conectado. O SDK permite que o cliente do aplicativo receba novos conteúdos de notificações de entrada, gerencie o estado das notificações existentes e recupere o histórico de notificações. Para obter mais informações sobre as Notificações e como elas permitem a entrega da notificação centrada em humanos, confira Visão geral de Notificações do Microsoft Graph

Todos os recursos no SDK do Project Rome, incluindo Notificações do Graph e muito mais, são criados sobre uma plataforma subjacente chamada de Plataforma de dispositivos Conectados. Este guia foi projetado para orientar você durante as etapas necessárias para começar a usar a Plataforma de Dispositivos Conectados e explicar como consumir APIs no SDK para implementar Notificações do Graph – recursos específicos.

Confira a página Referência de API para obter links para os documentos de referência relevantes para cenários de notificação.

Essa etapas a seguir fará referência a código do aplicativo de exemplo do Project Rome para Android.

Para todos os recursos de dispositivos conectados, você precisará de um IDE de desenvolvimento de aplicativo Android e de um dispositivo Android com uma das arquiteturas compatíveis (armeabi-v7a, arm64-v8a, x86 ou x86_64) ou de um emulador. O sistema deve estar executando o Android 4.4.2 ou posterior.

Configuração preliminar para a Plataforma de Dispositivos Conectados e Notificações

Antes de implementar a conectividade remota, existem algumas etapas, que você precisará seguir para conceder a capacidade de se conectar a dispositivos remotos a seu aplicativo Android, bem como enviar e receber notificações.

Registrar seu aplicativo

A autenticação da MSA (Conta Microsoft) ou do AAD (Azure Active Directory) é necessária para quase todos os recursos do SDK do Project Rome (exceto pela API de compartilhamento por proximidade). Se você ainda não tiver uma conta Microsoft e quiser usar uma, registre-se em account.microsoft.com.

Observação

Não há suporte para contas do AAD (Azure Active Directory) com as APIs de retransmissão do dispositivo.

Usando seu método de autenticação escolhido, você deve registrar seu aplicativo com a Microsoft seguindo as instruções no Portal de Registro de Aplicativo. Se você não tiver uma conta de desenvolvedor Microsoft, precisará criá-la.

Ao registrar um aplicativo usando uma MSA, você deverá receber uma cadeia de caracteres de ID do cliente. Salve para uso posterior. Isso permitirá que o aplicativo acesse recursos da Plataforma de Dispositivos Conectados da Microsoft. Se você estiver usando o AAD, confira Bibliotecas de autenticação do Azure Active Directory para obter instruções sobre como obter a cadeia de caracteres de ID do cliente.

Adicionar o SDK

Insira as referências de repositório a seguir no arquivo build.gradle na raiz do seu projeto.

allprojects {
    repositories {
        jcenter()
    }
}

Em seguida, insira a dependência a seguir para o arquivo build.gradle que está na pasta do projeto.

dependencies { 
    ...
    implementation 'com.microsoft.connecteddevices:connecteddevices-sdk:+'
}

No arquivo AndroidManifest.xml do projeto, adicione as seguintes permissões dentro do elemento <manifest> (se eles ainda não estão presentes). Isso dá ao aplicativo permissão para se conectar à Internet e para habilitar a descoberta de Bluetooth no dispositivo.

Observe que as permissões de Bluetooth são necessárias apenas para usar a descoberta de Bluetooth; elas não são necessárias para os outros recursos da Plataforma de Dispositivos Conectados. Além disso, ACCESS_COARSE_LOCATION só é necessário nos SDKs do Android 21 e posterior. Nos SDKs do Android 23 e versões posteriores, o desenvolvedor também precisa solicitar ao usuário que permita acesso à localização em runtime.

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

Em seguida, vá para as classes de atividade em que você deseja que a funcionalidade de dispositivos conectados resida. Importe os pacotes a seguir.

import com.microsoft.connecteddevices;
import com.microsoft.connecteddevices.remotesystems;
import com.microsoft.connecteddevices.remotesystems.commanding;

Configurar a autenticação e o gerenciamento de contas

A plataforma de dispositivos conectados exige que um token OAuth válido seja usado no processo de registro. Você pode usar seu método preferido para gerar e gerenciar os tokens OAuth. No entanto, para ajudar os desenvolvedores a começarem a usar a plataforma, incluímos um provedor de autenticação como parte do aplicativo de exemplo do Android que gera e gerencia os tokens de atualização para sua conveniência.

Caso queira você mesmo implementar a interface ConnectedDevicesAccountManager, anote as seguintes informações:

Se você estiver usando uma MSA, precisará incluir os seguintes escopos em sua solicitação de entrada: "wl.offline_access", "ccs.ReadWrite", "dds.read", "dds.register", "wns.connect", "asimovrome.telemetry" e "https://activity.windows.com/UserActivity.ReadWrite.CreatedByApp".

Se você estiver usando uma conta do AAD, precisará solicitar os seguintes públicos-alvo: "https://cdpcs.access.microsoft.com", "https://cs.dds.microsoft.com", "https://wns.windows.com/" e "https://activity.microsoft.com".

Observação

Não há suporte para contas do AAD (Azure Active Directory) com as APIs de retransmissão do dispositivo.

Não importa se você está usando a implementação ConnectedDevicesAccountManager fornecida ou não, se estiver usando o AAD, precisará especificar as seguintes permissões no registro do seu aplicativo no portal do Azure (portal.azure.com > Azure Active Directory > Registros de aplicativo):

  • Serviço de Feed de Atividades da Microsoft
    • Entregar e modificar as notificações de usuário para este aplicativo
    • Ler e gravar atividade do aplicativo para o feed de atividades dos usuários
  • Serviço de Notificação do Windows
    • Conecte seu dispositivo ao Serviço de Notificação do Windows
  • Serviço de Diretório do Dispositivos da Microsoft
    • Veja sua lista de dispositivos
    • Ser adicionado à sua lista de dispositivos e aplicativos
  • Serviço de Comando da Microsoft
    • Comunicar-se com dispositivos de usuário
    • Ler dispositivos de usuário

Registrar seu aplicativo para notificações por push

Registrar o aplicativo com o Google para suporte a Firebase Cloud Messaging. Não se esqueça de anotar a ID do remetente e a chave do servidor que você receber; você precisará deles mais tarde.

Depois de registrado, você precisa associar a funcionalidade de notificação por push com a plataforma de dispositivos conectados em seu aplicativo.

mNotificationRegistration = new ConnectedDevicesNotificationRegistration();
mNotificationRegistration.setType(ConnectedDevicesNotificationType.FCM);
mNotificationRegistration.setToken(token);
mNotificationRegistration.setAppId(Secrets.FCM_SENDER_ID);
mNotificationRegistration.setAppDisplayName("SampleApp");

Registrar o aplicativo no Centro de Desenvolvimento do Microsoft Windows para experiências entre dispositivos

Importante

Essa etapa só é necessária se você deseja usar os recursos do Project Rome para acessar dados de ou para fazer solicitações de dispositivos não Windows. Se direcionar somente a dispositivos Windows, você não precisará concluir esta etapa.

Vá para o Painel do Centro de Desenvolvimento, navegue para Experiências entre Dispositivos no painel de navegação esquerdo e selecione configurar um novo aplicativo entre dispositivos, conforme mostrado abaixo. Painel do Centro de Desenvolvimento – Experiências entre dispositivos

O processo de integração do Centro de Desenvolvimento requer as seguintes etapas:

  • Selecionar as plataformas compatíveis – selecione as plataformas em que o aplicativo terá uma presença e será habilitado para experiências entre dispositivos. No caso de integração de Notificações do Graph, você pode selecionar do Windows, do Android e do iOS. Experiências entre dispositivos – Plataformas com suporte

  • Fornecer IDs do aplicativo – forneça IDs do aplicativo para cada plataforma em que seu aplicativo tem uma presença. Para aplicativos Android, isso é o nome do pacote que você atribuiu ao aplicativo quando criou o projeto. O nome do pacote pode ser encontrado no console do Firebase, em Visão Geral do Projeto -> Geral. Você pode adicionar IDs diferentes (até dez) por plataforma, caso você tenha várias versões do mesmo aplicativo ou até mesmo diferentes aplicativos que deseje que sejam capazes de receber as mesmas notificações enviadas pelo seu servidor de aplicativo, destinadas ao mesmo usuário. Experiências entre dispositivos – IDs do aplicativo

  • Forneça ou selecione as IDs do aplicativo dos registros de aplicativo na MSA e/ou no AAD. Essas IDs de cliente correspondentes ao registro do aplicativo na MSA ou no AAD foram obtidas nas etapas anteriores de registro do aplicativo no AAD ou na MSA acima. Experiências entre dispositivos – registros de aplicativo na MSA e no AAD

  • As Notificações do Graph e outras funcionalidades da Plataforma de Dispositivos Conectados aproveitam cada das plataformas de notificação nativas em plataformas principais para enviar notificações para baixo até os pontos de extremidade de cliente do aplicativo, ou seja, WNS (para UWP do Windows), FCM (para Android) e APNS (para iOS). Forneça suas credenciais para essas plataformas de notificação para habilitar as Notificações do Graph a entregar as notificações para seu servidor de aplicativo quando você publicar notificações direcionadas ao usuário. Para o Android, habilitar o serviço Cloud Messaging é um pré-requisito para usar as Notificações do Microsoft Graph. Além disso, observe que a ID do remetente necessária corresponde à ID do remetente do Firebase Cloud Messaging e a chave da API corresponde à chave do servidor herdado. Ambas podem ser encontradas em Console do Firebase -> Projeto -> Configurações, na guia Mensagens da nuvem, conforme mostrado na captura de tela. Experiências entre dispositivos – credenciais de push

  • A última etapa é verificar o domínio de aplicativo entre dispositivos, que serve como um processo de verificação para comprovar que seu aplicativo tem a propriedade desse domínio, que age como uma identidade do aplicativo entre dispositivos para o aplicativo registrado por você. Experiências entre dispositivos – Verificação de domínio

Inicializar um canal de Notificação do Graph

O SDK do Project Rome permite que seu aplicativo assine diferentes canais para receber e gerenciar diferentes tipos de dados do usuário – incluindo Notificações do Graph, Atividades do Usuário e muito mais. Todos eles são armazenados e sincronizados no UserDataFeed. UserNotification é o tipo de classe e de dados correspondente a uma notificação direcionada ao usuário enviada por meio das Notificações do Graph. Para integrar com o gráfico de notificação e começar a receber UserNotification publicada pelo seu servidor de aplicativo, você primeiro precisará inicializar o feed de dados do usuário criando um UserNotificationChannel. Você deve tratar isso como a etapa de inicialização da plataforma acima: ela deve ser verificada e possivelmente refeita sempre que o aplicativo vem ao primeiro plano (mas não antes da inicialização da plataforma).

Os métodos a seguir inicializam um UserNotificationChannel.

private UserNotificationChannel mNotificationChannel;
private UserDataFeed mUserDataFeed;

// ...

/**
 * Initializes the UserNotificationFeed.
 */
public void initializeUserNotificationFeed() {

    // define what scope of data this app needs
    SyncScope[] scopes = { UserNotificationChannel.getSyncScope() };

    // Get a reference to the UserDataFeed. This method is defined below
    mUserDataFeed = getUserDataFeed(scopes, new EventListener<UserDataFeed, Void>() {
        @Override
        public void onEvent(UserDataFeed userDataFeed, Void aVoid) {
            if (userDataFeed.getSyncStatus() == UserDataSyncStatus.SYNCHRONIZED) {
                // log synchronized.
            } else {
                // log synchronization not completed.
            }
        }
    });

    // this method is defined below
    mNotificationChannel = getUserNotificationChannel();
}

// instantiate the UserDataFeed
private UserDataFeed getUserDataFeed(SyncScope[] scopes, EventListener<UserDataFeed, Void> listener) {
    UserAccount[] accounts = AccountProviderBroker.getSignInHelper().getUserAccounts();
    if (accounts.length <= 0) {
        // notify the user that sign-in is required
        return null;
    }

    // use the initialized Platform instance, along with the cross-device app ID.
    UserDataFeed feed = UserDataFeed.getForAccount(accounts[0], PlatformBroker.getPlatform(), Secrets.APP_HOST_NAME);
    feed.addSyncStatusChangedListener(listener);
    feed.addSyncScopes(scopes);
    // sync data with the server
    feed.startSync();
    return feed;
}

// use the UserDataFeed reference to create a UserActivityChannel
@Nullable
private UserNotificationChannel getUserNotificationChannel() {
    UserNotificationChannel channel = null;
    try {
        // create a UserNotificationChannel for the signed in account
        channel = new UserNotificationChannel(mUserDataFeed);
    } catch (Exception e) {
        e.printStackTrace();
        // handle exception
    }
    return channel;
}

Neste ponto, você deve ter uma referência a UserNotificationChannel em mNotificationChannel.

Criar um UserNotificationReader para receber UserNotifications de entrada e acessar o histórico de UserNotification

Como mostramos anteriormente, a notificação do Google Cloud Messaging inicial que chega ao aplicativo cliente contém apenas um toque shoulder. Você precisará passar esse conteúdo de toque shoulder para a Plataforma de Dispositivos Conectados, a fim de disparar o SDK para executar uma sincronização completa com o servidor de Dispositivos Conectados, que contém todas as UserNotifications publicadas pelo seu servidor de aplicativo. Isso efetuará pull do conteúdo de notificação completo publicado pelo seu servidor de aplicativo correspondente a este toque shoulder (e, caso alguma notificação tenha sido publicada anteriormente, mas não recebida nesse cliente do aplicativo devido à conectividade do dispositivo ou outros problemas, o pull dela será efetuado também). Com essas sincronizações em tempo real executadas constantemente pelo SDK, o cliente do aplicativo pode ter acesso a um cache local do feed de dados UserNotification deste usuário conectado. Nesse caso, um UserNotificationReader permite o acesso do cliente do aplicativo a esse feed de dados – para receber o conteúdo da notificação mais recente por meio do ouvinte de eventos ou para acessar a coleção UserNotification completa que pode ser usada como modelo de exibição do histórico de notificações do usuário.

Receber UserNotifications

Primeiro, você precisa instanciar um UserNotificationReader e obter todos os UserNotifications existentes já no leitor se você está interessado em consumir essas informações para a experiência que você está tentando habilitar. É seguro pressupor sempre que o servidor de aplicativo já publicou notificações para esse usuário conectado, considerando que esse ponto de extremidade de dispositivo específico pode não ser o único ou o primeiro ponto de extremidade em que o usuário instalou o aplicativo.

private static UserNotificationReader mReader;
private static final ArrayList<UserNotification> mHistoricalNotifications = new ArrayList<>();
// Instantiate UserNotificationReader
UserNotificationReaderOptions options = new UserNotificationReaderOptions();
mReader = mNotificationChannel.createReaderWithOptions(options);
// Read any previously published UserNotifications that have not expired yet
mReader.readBatchAsync(Long.MAX_VALUE).thenAccept(new AsyncOperation.ResultConsumer<UserNotification[]>() {
    @Override
    public void accept(UserNotification[] userNotifications) throws Throwable {
        synchronized (mHistoricalNotifications) {
            for (UserNotification notification : userNotifications) {
                if (notification.getReadState() == UserNotificationReadState.UNREAD) {
                    mHistoricalNotifications.add(notification);
                }
            }
        }
 
        if (RunnableManager.getHistoryUpdated() != null) {
            activity.runOnUiThread(RunnableManager.getHistoryUpdated());
        }
    }
});

Agora, adicione um ouvinte de eventos que é disparado quando a Plataforma de Dispositivos Conectados conclui uma sincronização e tem novas alterações sobre as quais notificá-lo. No caso de Notificações do Graph, novas alterações podem ser novas UserNotifications de entrada publicadas pelo seu servidor de aplicativo ou exclusões, atualizações e expirações de UserNotification que ocorreram do servidor ou de outros pontos de extremidade registrados dos quais o mesmo usuário fez logon.

Dica

É nesse ouvinte de eventos que você pode manipular a lógica de negócios principal e "consumir" o conteúdo da sua notificação com base em seus cenários. Se você está usando a mensagem de dados do Google Cloud Messaging para construir uma notificação visual na bandeja de notificação no nível do sistema operacional ou então se você usa o conteúdo na notificação para atualizar alguma interface do usuário no aplicativo, este é o lugar para fazê-lo.

mReader.addDataChangedListener(new EventListener<UserNotificationReader, Void>() {
    @Override
    public void onEvent(UserNotificationReader userNotificationReader, Void aVoid) {
        userNotificationReader.readBatchAsync(Long.MAX_VALUE).thenAccept(new AsyncOperation.ResultConsumer<UserNotification[]>() {
        @Override
        public void accept(UserNotification[] userNotifications) throws Throwable {
            boolean updatedNew = false;
            boolean updatedHistorical = false;
            synchronized (sHistoricalNotifications) {
                for (final UserNotification notification : userNotifications) {
                    if (notification.getStatus() == UserNotificationStatus.ACTIVE && notification.getReadState() == UserNotificationReadState.UNREAD) {
                        switch (notification.getUserActionState()) {
                            case NO_INTERACTION:
                                // Brand new notification
                                // Insert business logic to construct a new visual notification in Android notification tray for the user to see
                                // ...
                            case DISMISSED:
                                // Existing notification that is marked as dismissed
                                // An app client receive this type of changes because another app client logged in by the same user has marked the notification as dismissed and the change is fanned-out to everywhere
                                // This state sync across app clients on different devices enable universal dismiss of notifications and other scenarios across multiple devices owned by the same user
                                // Insert business logic to dismiss the corresponding visual notification inside Android system notification tray, to make sure users don’t have to deal with redundant information across devices, and potentially insert this notification in your app’s notification history view
                                // ...
                            default:
                                // Unexpected
                        }
                    } else {
                        // ...
                    }
                }
            }
        }
    });
}
});

Atualizar o estado de uma UserNotification existente

Na seção anterior, mencionamos que, às vezes, uma alteração de UserNotification recebida por meio do leitor poderia ser uma atualização de estado em uma UserNotification existente – independentemente de ela estar sendo marcada como ignorada ou como lida. Nesse caso, o cliente do aplicativo pode decidir o que fazer, assim como habilitar a dispensa universal, removendo a notificação visual correspondente nesse dispositivo específico. Dando um passo para trás, seu cliente de aplicativo costuma ser aquele primeiro que iniciou esta atualização de alteração UserNotification – de um dispositivo diferente. Você pode escolher a hora para atualizar o estado das UserNotifications, mas geralmente eles são atualizados quando a notificação visual correspondente é manipulada pelo usuário nesse dispositivo ou a notificação é subsequentemente manipulada pelo usuário em alguma experiência no aplicativo habilitada por você. Aqui está um exemplo de como seria o fluxo: o servidor de aplicativos publica uma notificação direcionada ao usuário A, o qual recebe essa notificação no computador e telefone nos quais os clientes do aplicativo estão instalados. O usuário clica na notificação no PC e busca no aplicativo para desempenhar a tarefa correspondente. O cliente do aplicativo neste PC, em seguida, chamará no SDK da Plataforma de Dispositivos Conectados para atualizar o estado da UserNotification correspondente para que essa atualização seja sincronizada em todos os dispositivos deste usuário. Os outros clientes de aplicativo, ao receber esse estado de atualização em tempo real, removerão em seguida o alerta visual/mensagem/notificação do sistema correspondente do centro de notificações/bandeja de notificação/central de ações do dispositivo. É assim que as notificações são ignoradas universalmente em todos os dispositivos do usuário.

Dica

A classe UserNotification atualmente fornece 2 tipos de atualizações de estado – você pode modificar o UserNotificationReadState ou o UserNotificationUserActionState e definir sua própria lógica para o que deve acontecer quando as notificações são atualizadas. Por exemplo, você pode marcar UserActionState como Ativado ou Ignorado dinamizar esse valor para implementar a dispensa universal. Como alternativa ou simultaneamente, você pode marcar ReadState como lido ou não lido e, com base nisso, determinar quais notificações devem aparecer na exibição de histórico de notificações no aplicativo. O snippet de código mostra como marcar o UserNotificationUserActionState de uma notificação como Ignorado.

public void dismissNotification(int position) {
    final UserNotification notification = mNewNotifications.get(position);
          
    notification.setUserActionState(UserNotificationUserActionState.DISMISSED);
    notification.saveAsync();
}