Partilhar via


Gestão de registos

Este tópico explica como registar dispositivos com hubs de notificação para receber notificações push. O tópico descreve os registos a um nível elevado e, em seguida, introduz os dois padrões principais para registar dispositivos: registar-se diretamente no hub de notificação e registar-se através de um back-end da aplicação.

O que é o registo de dispositivos

O registo de dispositivos com um Hub de Notificação é efetuado através de um Registo ou Instalação.

Registos

Um registo associa a alça do Serviço de Notificação de Plataforma (PNS) a um dispositivo com etiquetas e, possivelmente, um modelo. O identificador PNS pode ser um ID de registo de tokens de dispositivo ou ChannelURI. As etiquetas são utilizadas para encaminhar notificações para o conjunto correto de identificadores de dispositivos. Para obter mais informações, veja Encaminhamento e Expressões de Etiquetas. Os modelos são utilizados para implementar a transformação por registo. Para obter mais informações, veja Templates (Modelos).

Nota

Os Hubs de Notificação do Azure suportam um máximo de 60 etiquetas por dispositivo.

Instalações

Uma Instalação é um registo melhorado que inclui um saco de propriedades relacionadas com push. É a abordagem mais recente e melhor para registar os seus dispositivos com o SDK .NET do lado do servidor (SDK do Hub de Notificação para operações de back-end). Também pode utilizar a abordagem da API REST dos Hubs de Notificação para registar instalações no próprio dispositivo cliente. Se estiver a utilizar um serviço de back-end, deverá poder utilizar o SDK do Hub de Notificação para operações de back-end.

Seguem-se algumas das principais vantagens da utilização de instalações:

  • Criar ou atualizar uma instalação é totalmente idempotente. Assim, pode repeti-lo sem qualquer preocupação relativamente a registos duplicados.
  • O modelo de instalação suporta um formato de etiqueta especial ($InstallationId:{INSTALLATION_ID}) que permite enviar uma notificação diretamente para o dispositivo específico. Por exemplo, se o código da aplicação definir um ID de instalação para joe93developer este dispositivo específico, um programador pode direcionar este dispositivo ao enviar uma notificação para a $InstallationId:{joe93developer} etiqueta. Isto permite-lhe direcionar um dispositivo específico sem ter de efetuar qualquer codificação adicional.
  • A utilização de instalações também lhe permite fazer atualizações parciais de registo. A atualização parcial de uma instalação é pedida com um método PATCH com a norma JSON-Patch. Isto é útil quando pretende atualizar etiquetas no registo. Não tem de retirar todo o registo e, em seguida, voltar a reenviar todas as etiquetas anteriores.

Uma instalação pode conter as seguintes propriedades. Para obter uma lista completa das propriedades de instalação, veja Criar ou Substituir uma Instalação com a API REST ou Propriedades de Instalação.

// Example installation format to show some supported properties
{
    installationId: "",
    expirationTime: "",
    tags: [],
    platform: "",
    pushChannel: "",
    ………
    templates: {
        "templateName1" : {
            body: "",
            tags: [] },
        "templateName2" : {
            body: "",
            // Headers are for Windows Store only
            headers: {
                "X-WNS-Type": "wns/tile" }
            tags: [] }
    },
    secondaryTiles: {
        "tileId1": {
            pushChannel: "",
            tags: [],
            templates: {
                "otherTemplate": {
                    bodyTemplate: "",
                    headers: {
                        ... }
                    tags: [] }
            }
        }
    }
}

Nota

Por predefinição, os registos e as instalações não expiram.

Os registos e instalações têm de conter uma alça PNS válida para cada dispositivo/canal. Uma vez que as alças PNS só podem ser obtidas numa aplicação cliente no dispositivo, um padrão é registar-se diretamente nesse dispositivo com a aplicação cliente. Por outro lado, considerações de segurança e lógica de negócio relacionadas com etiquetas podem exigir que faça a gestão do registo de dispositivos no back-end da aplicação.

Quando o push é efetuado numa alça expirada pelo PNS, os Hubs de Notificação do Azure limpam automaticamente o registo de instalação/registo associado com base na resposta recebida do servidor PNS. Para limpar os registos expirados de um hub de notificação secundário, adicione lógica personalizada que processa o feedback de cada envio. Em seguida, expire a instalação/registo no hub de notificação secundário.

Nota

A API de Instalações não suporta o serviço Baidu (embora a API de Registos o faça).

Modelos

Se quiser utilizar Modelos, a instalação do dispositivo também contém todos os modelos associados a esse dispositivo num formato JSON (veja exemplo acima). Os nomes dos modelos ajudam a direcionar modelos diferentes para o mesmo dispositivo.

Cada nome de modelo mapeia para um corpo de modelo e um conjunto opcional de etiquetas. Além disso, cada plataforma pode ter propriedades de modelo adicionais. Para a Loja Windows (com WNS), um conjunto adicional de cabeçalhos pode fazer parte do modelo. No caso das APNs, pode definir uma propriedade de expiração para uma constante ou para uma expressão de modelo. Para obter uma lista completa das propriedades de instalação, veja Criar ou Substituir um tópico Instalação com REST .

Mosaicos Secundários para Aplicações da Loja Windows

Para aplicações cliente da Loja Windows, enviar notificações para mosaicos secundários é o mesmo que enviá-las para a principal. Isto também é suportado em instalações. Os mosaicos secundários têm um ChannelUri diferente, que o SDK na sua aplicação cliente processa de forma transparente.

O dicionário SecondaryTiles utiliza o mesmo TileId que é utilizado para criar o objeto SecondaryTiles na sua aplicação da Loja Windows. Tal como acontece com o ChannelUri primário, os ChannelUris dos mosaicos secundários podem mudar a qualquer momento. Para manter as instalações no hub de notificação atualizadas, o dispositivo tem de atualizá-las com os ChannelUris atuais dos mosaicos secundários.

Gestão de registos do dispositivo

Ao gerir o registo de dispositivos a partir de aplicações cliente, o back-end só é responsável pelo envio de notificações. As aplicações cliente mantêm as alças PNS atualizadas e registam etiquetas. A imagem seguinte ilustra este padrão.

Registo a partir do dispositivo

O dispositivo obtém primeiro a alça PNS do PNS e, em seguida, regista-se diretamente no hub de notificação. Depois de o registo ser efetuado com êxito, o back-end da aplicação pode enviar uma notificação direcionada para esse registo. Para obter mais informações sobre como enviar notificações, veja Encaminhamento e Expressões de Etiquetas.

Neste caso, utiliza apenas direitos de escuta para aceder aos seus hubs de notificação a partir do dispositivo. Para obter mais informações, consulte Segurança.

Registar-se a partir do dispositivo é o método mais simples, mas tem algumas desvantagens:

  • Uma aplicação cliente só pode atualizar as respetivas etiquetas quando a aplicação estiver ativa. Por exemplo, se um utilizador tiver dois dispositivos que registam etiquetas relacionadas com equipas desportivas, quando o primeiro dispositivo se registar para uma etiqueta adicional (por exemplo, Seahawks), o segundo dispositivo não receberá as notificações sobre os Seahawks até que a aplicação no segundo dispositivo seja executada uma segunda vez. Geralmente, quando as etiquetas são afetadas por vários dispositivos, a gestão de etiquetas a partir do back-end é uma opção desejável.
  • Uma vez que as aplicações podem ser pirateadas, proteger o registo em etiquetas específicas requer cuidados adicionais, conforme explicado no artigo Segurança.

Código de exemplo para se registar num hub de notificação a partir de um dispositivo com uma instalação

Neste momento, isto só é suportado com a API REST dos Hubs de Notificação.

Também pode utilizar o método PATCH com o padrão JSON-Patch para atualizar a instalação.

class DeviceInstallation
{
    public string installationId { get; set; }
    public string platform { get; set; }
    public string pushChannel { get; set; }
    public string[] tags { get; set; }

    private async Task<HttpStatusCode> CreateOrUpdateInstallationAsync(DeviceInstallation deviceInstallation,
        string hubName, string listenConnectionString)
    {
        if (deviceInstallation.installationId == null)
            return HttpStatusCode.BadRequest;

        // Parse connection string (https://msdn.microsoft.com/library/azure/dn495627.aspx)
        ConnectionStringUtility connectionSaSUtil = new ConnectionStringUtility(listenConnectionString);
        string hubResource = "installations/" + deviceInstallation.installationId + "?";
        string apiVersion = "api-version=2015-04";

        // Determine the targetUri that we will sign
        string uri = connectionSaSUtil.Endpoint + hubName + "/" + hubResource + apiVersion;

        //=== Generate SaS Security Token for Authorization header ===
        // See https://msdn.microsoft.com/library/azure/dn495627.aspx
        string SasToken = connectionSaSUtil.getSaSToken(uri, 60);

        using (var httpClient = new HttpClient())
        {
            string json = JsonConvert.SerializeObject(deviceInstallation);

            httpClient.DefaultRequestHeaders.Add("Authorization", SasToken);

            var response = await httpClient.PutAsync(uri, new StringContent(json, System.Text.Encoding.UTF8, "application/json"));
            return response.StatusCode;
        }
    }

    var channel = await PushNotificationChannelManager.CreatePushNotificationChannelForApplicationAsync();

    string installationId = null;
    var settings = ApplicationData.Current.LocalSettings.Values;

    // If we have not stored an installation ID in application data, create and store as application data.
    if (!settings.ContainsKey("__NHInstallationId"))
    {
        installationId = Guid.NewGuid().ToString();
        settings.Add("__NHInstallationId", installationId);
    }

    installationId = (string)settings["__NHInstallationId"];

    var deviceInstallation = new DeviceInstallation
    {
        installationId = installationId,
        platform = "wns",
        pushChannel = channel.Uri,
        //tags = tags.ToArray<string>()
    };

    var statusCode = await CreateOrUpdateInstallationAsync(deviceInstallation, 
                    "<HUBNAME>", "<SHARED LISTEN CONNECTION STRING>");

    if (statusCode != HttpStatusCode.Accepted)
    {
        var dialog = new MessageDialog(statusCode.ToString(), "Registration failed. Installation Id : " + installationId);
        dialog.Commands.Add(new UICommand("OK"));
        await dialog.ShowAsync();
    }
    else
    {
        var dialog = new MessageDialog("Registration successful using installation Id : " + installationId);
        dialog.Commands.Add(new UICommand("OK"));
        await dialog.ShowAsync();
    }
}

Código de exemplo para se registar num hub de notificação a partir de um dispositivo com um registo

Estes métodos criam ou atualizam um registo para o dispositivo no qual são chamados. Isto significa que, para atualizar a alça ou as etiquetas, tem de substituir todo o registo. Lembre-se de que os registos são transitórios, pelo que deve ter sempre um arquivo fiável com as etiquetas atuais de que um dispositivo específico precisa.

// Initialize the Notification Hub
NotificationHubClient hub = NotificationHubClient.CreateClientFromConnectionString(listenConnString, hubName);

// The Device ID from the PNS
var pushChannel = await PushNotificationChannelManager.CreatePushNotificationChannelForApplicationAsync();

// If you are registering from the client itself, then store this registration ID in device
// storage. Then when the app starts, you can check if a registration ID already exists or not before
// creating.
var settings = ApplicationData.Current.LocalSettings.Values;

// If we have not stored a registration ID in application data, store in application data.
if (!settings.ContainsKey("__NHRegistrationId"))
{
    // make sure there are no existing registrations for this push handle (used for iOS and Android)    
    string newRegistrationId = null;
    var registrations = await hub.GetRegistrationsByChannelAsync(pushChannel.Uri, 100);
    foreach (RegistrationDescription registration in registrations)
    {
        if (newRegistrationId == null)
        {
            newRegistrationId = registration.RegistrationId;
        }
        else
        {
            await hub.DeleteRegistrationAsync(registration);
        }
    }

    newRegistrationId = await hub.CreateRegistrationIdAsync();

    settings.Add("__NHRegistrationId", newRegistrationId);
}

string regId = (string)settings["__NHRegistrationId"];

RegistrationDescription registration = new WindowsRegistrationDescription(pushChannel.Uri);
registration.RegistrationId = regId;
registration.Tags = new HashSet<string>(YourTags);

try
{
    await hub.CreateOrUpdateRegistrationAsync(registration);
}
catch (Microsoft.WindowsAzure.Messaging.RegistrationGoneException e)
{
    settings.Remove("__NHRegistrationId");
}

Gestão de registos a partir de um back-end

A gestão de registos a partir do back-end requer a escrita de código adicional. A aplicação do dispositivo tem de fornecer a alça PNS atualizada para o back-end sempre que a aplicação é iniciada (juntamente com etiquetas e modelos) e o back-end tem de atualizar esta alça no hub de notificação. A imagem seguinte ilustra este design.

Gestão de registos

As vantagens de gerir registos a partir do back-end incluem a capacidade de modificar etiquetas para registos mesmo quando a aplicação correspondente no dispositivo está inativa e para autenticar a aplicação cliente antes de adicionar uma etiqueta ao respetivo registo.

Código de exemplo para se registar num hub de notificação a partir de um back-end com uma instalação

O dispositivo cliente ainda obtém a respetiva alça PNS e propriedades de instalação relevantes como anteriormente e chama uma API personalizada no back-end que pode efetuar o registo e autorizar etiquetas, etc. O back-end pode tirar partido do SDK do Hub de Notificação para operações de back-end.

Também pode utilizar o método PATCH com o padrão JSON-Patch para atualizar a instalação.

// Initialize the Notification Hub
NotificationHubClient hub = NotificationHubClient.CreateClientFromConnectionString(listenConnString, hubName);

// Custom API on the backend
public async Task<HttpResponseMessage> Put(DeviceInstallation deviceUpdate)
{

    Installation installation = new Installation();
    installation.InstallationId = deviceUpdate.InstallationId;
    installation.PushChannel = deviceUpdate.Handle;
    installation.Tags = deviceUpdate.Tags;

    switch (deviceUpdate.Platform)
    {
        case "wns":
            installation.Platform = NotificationPlatform.Wns;
            break;
        case "apns":
            installation.Platform = NotificationPlatform.Apns;
            break;
        case "fcm":
            installation.Platform = NotificationPlatform.Fcm;
            break;
        default:
            throw new HttpResponseException(HttpStatusCode.BadRequest);
    }


    // In the backend we can control if a user is allowed to add tags
    //installation.Tags = new List<string>(deviceUpdate.Tags);
    //installation.Tags.Add("username:" + username);

    await hub.CreateOrUpdateInstallationAsync(installation);

    return Request.CreateResponse(HttpStatusCode.OK);
}

Código de exemplo para se registar num hub de notificação a partir de um back-end com um ID de registo

No back-end da aplicação, pode realizar operações CRUDS básicas em registos. Por exemplo:

var hub = NotificationHubClient.CreateClientFromConnectionString("{connectionString}", "hubName");

// create a registration description object of the correct type, e.g.
var reg = new WindowsRegistrationDescription(channelUri, tags);

// Create
await hub.CreateRegistrationAsync(reg);

// Get by ID
var r = await hub.GetRegistrationAsync<RegistrationDescription>("id");

// update
r.Tags.Add("myTag");

// update on hub
await hub.UpdateRegistrationAsync(r);

// delete
await hub.DeleteRegistrationAsync(r);

O back-end tem de processar a simultaneidade entre as atualizações de registo. O Service Bus oferece um controlo de simultaneidade otimista para a gestão de registos. Ao nível http, isto é implementado com a utilização do ETag em operações de gestão de registos. Esta funcionalidade é utilizada de forma transparente pelos SDKs da Microsoft, que geram uma exceção se uma atualização for rejeitada por motivos de simultaneidade. O back-end da aplicação é responsável por processar estas exceções e repetir a atualização, se necessário.