Seu ambiente servidor e o FCM

O lado do servidor do Firebase Cloud Messaging consiste em dois componentes:

  • O back-end do FCM fornecido pelo Google.
  • Seu servidor do app ou outro ambiente servidor confiável em que sua lógica de servidor é executada, como o Cloud Functions para Firebase ou outros ambientes de nuvem gerenciados pelo Google.

O servidor do app ou ambiente de servidor confiável envia solicitações de mensagens para o back-end do FCM, que, em seguida, encaminha as mensagens para apps de cliente em execução nos dispositivos dos usuários.

Requisitos do ambiente servidor confiável

Seu ambiente de servidor do app precisa atender aos critérios a seguir:

  • Capacidade de enviar solicitações de mensagens formatadas corretamente para o back-end do FCM.
  • Capacidade de gerenciar solicitações e reenviá-las usando o recuo exponencial.
  • Capacidade de armazenar com segurança as credenciais de autorização do servidor e os tokens de registro do cliente.
  • Para o protocolo XMPP, se usado, o servidor precisa ser capaz de gerar IDs de mensagem para identificar exclusivamente cada mensagem enviada (o back-end HTTP do FCM gera IDs de mensagem e os retorna na resposta). Os IDs de mensagem XMPP precisam ser únicos por ID de emissor.

Escolher uma opção de servidor

Você precisará decidir como interagir com os servidores FCM: usando o SDK Admin do Firebase ou os protocolos brutos. Devido ao suporte a várias linguagens de programação famosas e aos métodos convenientes para lidar com autenticação e autorização, o SDK Admin do Firebase é o método recomendado.

Opções para interagir com os servidores do FCM incluem o seguinte:

  • O SDK Admin do Firebase, que tem suporte a Node, Java, Python, C# e Go.
  • A API FCM HTTP v1, que é a opção de protocolo mais atualizada, com autorização mais segura e recursos flexíveis de mensagens entre plataformas. O SDK Admin do Firebase é baseado nesse protocolo e oferece todas as vantagens dele. Os novos recursos geralmente são adicionados apenas à API HTTP v1. Por isso, recomendamos o uso dela na maioria dos casos de uso.
  • O protocolo HTTP legado. Para novos projetos, recomendamos o uso da API HTTP v1 do FCM em vez do protocolo legado.
  • O protocolo de servidor XMPP legado. Para novos projetos, recomendamos o uso da API HTTP v1 do FCM em vez do protocolo legado.

SDK Admin do Firebase para FCM

A API do Admin FCM manipula a autenticação com o back-end e facilita o envio de mensagens e o gerenciamento de assinaturas de tópicos. Com o SDK Admin do Firebase, você pode:

  • enviar mensagens para dispositivos individuais;
  • enviar mensagens para tópicos e declarações de condição que correspondam a um ou mais tópicos;
  • assinar e cancelar a assinatura de dispositivos de e para tópicos;
  • criar payloads de mensagens adaptados a diferentes plataformas de destino.

O SDK Admin para Node.js fornece métodos para enviar mensagens a grupos de dispositivos.

Para configurar o SDK Admin do Firebase, consulte Adicionar o SDK Admin do Firebase ao seu servidor. Se você já tem um projeto do Firebase, comece pela etapa Adicionar o SDK. Além disso, ative a API Cloud Messaging na página de configurações do Cloud Messaging do seu projeto. Em seguida, depois que o SDK Admin do Firebase for instalado, comece a escrever a lógica para criar solicitações de envio.

Protocolos do servidor do FCM

Atualmente, o FCM oferece estes protocolos de servidor brutos:

O servidor de aplicativos pode usar esses protocolos separadamente ou em conjunto. Como é o mais atualizado e o mais flexível para enviar mensagens para várias plataformas, a API FCM HTTP v1 é recomendada sempre que possível. Se os seus requisitos incluem mensagens upstream de dispositivos para o servidor, você precisará implementar o protocolo XMPP.

As diferenças entre as messages XMPP e HTTP são:

  • Mensagens upstream/downstream
    • HTTP: somente downstream, da nuvem para o dispositivo.
    • XMPP: upstream e downstream (do dispositivo para a nuvem e da nuvem para o dispositivo).
  • Mensagens (síncronas e assíncronas)
    • HTTP: síncrona. Servidores de app enviam mensagens como solicitações HTTP POST e aguardam uma resposta. Esse mecanismo é síncrono e impede o remetente de enviar outra mensagem até que a resposta seja recebida.
    • XMPP: assíncrona. Servidores de app enviam/recebem mensagens para/de todos os seus dispositivos em velocidade máxima de linha em conexões XMPP persistentes. O servidor de conexão XMPP envia notificações de falha ou confirmação (no formato de mensagens ACK e NACK do XMPP codificadas em JSON) de maneira assíncrona.
  • JSON
    • HTTP: mensagens JSON enviadas como HTTP POST.
    • HTTP: mensagens JSON incluídas em mensagens XMPP.
  • Texto simples
    • HTTP: mensagens de texto simples enviadas como HTTP POST.
    • XMPP: incompatível.
  • Envio de transmissão downstream para vários tokens de registro.
    • HTTP: compatível em formato de mensagem JSON.
    • XMPP: incompatível.

Como implementar o protocolo do servidor HTTP

Para enviar uma mensagem, o servidor do app emite uma solicitação POST com um cabeçalho HTTP e um corpo HTTP composto por pares de chave-valor JSON. Para detalhes sobre as opções de cabeçalho e corpo, consulte Criar solicitações de envio do servidor de apps.

Como implementar o protocolo do servidor XMPP

O payload JSON para mensagens FCM é semelhante ao protocolo HTTP, com estas exceções:

  • Não são permitidos vários destinatários.
  • O FCM adiciona o campo message_id, que é obrigatório. Esse ID identifica exclusivamente a mensagem em uma conexão XMPP. A ACK ou NACK do FCM usa o message_id para identificar uma mensagem enviada dos servidores do app ao FCM. Dessa forma, é importante que esse message_id não seja exclusivo (por ID do remetente), mas esteja sempre presente.
  • O XMPP usa a chave do servidor para autorizar uma conexão permanente ao FCM. Consulte Autorizar solicitações de envio para mais informações.

Além das mensagens normais do FCM, são enviadas mensagens de controle indicadas pelo campo message_type no objeto JSON. O valor pode ser “ack”, “nack” ou “control” (veja os formatos abaixo). Qualquer mensagem do FCM com um message_type desconhecido pode ser ignorado pelo seu servidor.

Seu servidor de app precisa enviar uma mensagem ACK para cada mensagem de dispositivo recebida do FCM. Ele nunca precisará enviar uma mensagem NACK. Se você não enviar uma ACK para uma mensagem, o FCM a reenviará na próxima vez em que uma nova conexão de XMPP for estabelecida, a menos que a mensagem expire antes.

O FCM também envia uma ACK ou uma NACK para cada mensagem do servidor ao dispositivo. Se nenhum valor for recebido, isso significará que a conexão TCP fechou no meio da operação e seu servidor precisará reenviar as mensagens. Consulte Controle de fluxo para detalhes.

Consulte Referência do protocolo para ver uma lista de todos os parâmetros de mensagem.

Formato da solicitação

Mensagem com payload — mensagem de notificação

Esta é uma estrofe de XMPP para uma mensagem de notificação:

<message id="">
  <gcm xmlns="google:mobile:data">
  {
     "to":"REGISTRATION_ID",  // "to" replaces "registration_ids"
     "notification": {
        "title": "Portugal vs. Denmark”,
        "body”: "5 to 1”
      },
      "time_to_live":"600"
  }
  </gcm>
</message>

Mensagem com payload — mensagem de dados

Esta é uma estrofe de XMPP que contém a mensagem JSON de um servidor de app para o FCM:

<message id="">
  <gcm xmlns="google:mobile:data">
  {
      "to":"REGISTRATION_ID",  // "to" replaces "registration_ids"
      "message_id":"m-1366082849205" // new required field
      "data":
      {
          "hello":"world",
      }
      "time_to_live":"600",
  }
  </gcm>
</message>

Formato da resposta

Uma resposta FCM pode ter três formatos. O primeiro é uma mensagem “ack” normal. Porém, se a resposta tiver um erro, a mensagem poderá ter dois formatos diferentes, como descrito abaixo.

Mensagem ACK

Esta é uma estrofe de XMPP contendo a mensagem ACK/NACK do FCM para o servidor de app:

<message id="">
  <gcm xmlns="google:mobile:data">
  {
      "from":"REGID",
      "message_id":"m-1366082849205"
      "message_type":"ack"
  }
  </gcm>
</message>

Mensagem NACK

"Um erro de NACK é uma mensagem normal de XMPP em que a mensagem de status message_type é "nack". Uma mensagem NACK contém:

  • um código de erro NACK;
  • uma descrição de erro NACK.

Veja alguns exemplos abaixo.

Registro incorreto:

<message>
  <gcm xmlns="google:mobile:data">
  {
    "message_type":"nack",
    "message_id":"msgId1",
    "from":"SomeInvalidRegistrationToken",
    "error":"BAD_REGISTRATION",
    "error_description":"Invalid token on 'to' field: SomeInvalidRegistrationId"
  }
  </gcm>
</message>

JSON inválido:

<message>
 <gcm xmlns="google:mobile:data">
 {
   "message_type":"nack",
   "message_id":"msgId1",
   "from":"bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
   "error":"INVALID_JSON",
   "error_description":"InvalidJson: JSON_TYPE_ERROR : Field \"time_to_live\" must be a JSON java.lang.Number: abc"
 }
 </gcm>
</message>

Taxa de mensagens do dispositivo excedida:

<message id="...">
  <gcm xmlns="google:mobile:data">
  {
    "message_type":"nack",
    "message_id":"msgId1",
    "from":"REGID",
    "error":"DEVICE_MESSAGE_RATE_EXCEEDED",
    "error_description":"Downstream message rate exceeded for this registration id"
  }
  </gcm>
</message>

Consulte a Referência do servidor para ver uma lista completa dos códigos de erro de NACK. A menos que seja indicado de outra forma, uma mensagem NACK não deve ser repetida. Códigos de erro NACK inesperados devem ser tratados da mesma maneira que INTERNAL_SERVER_ERROR.

Erro de estrofe

Em certos casos, também pode aparecer um erro de estrofe. Um erro de estrofe contém:

  • o código do erro de estrofe;
  • a descrição do erro de estrofe (texto livre).

Por exemplo:

<message id="3" type="error" to="123456789@fcm.googleapis.com/ABC">
  <gcm xmlns="google:mobile:data">
     {"random": "text"}
  </gcm>
  <error code="400" type="modify">
    <bad-request xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"/>
    <text xmlns="urn:ietf:params:xml:ns:xmpp-stanzas">
      InvalidJson: JSON_PARSING_ERROR : Missing Required Field: message_id\n
    </text>
  </error>
</message>

Mensagens de controle

Periodicamente, o FCM precisa fechar uma conexão para realizar o balanceamento de carga. Antes de fechar a conexão, o FCM envia uma mensagem CONNECTION_DRAINING para indicar que a conexão está sendo diminuída e será fechada em breve. A palavra “draining” refere-se ao encerramento do fluxo de mensagens que entram em uma conexão, mas permitindo que o que já está no pipeline continue lá. Ao receber uma mensagem de CONNECTION_DRAINING, é preciso começar imediatamente a enviar mensagens a outra conexão do FCM e abrir uma nova conexão, se necessário. Entretanto, você precisa manter a conexão original aberta e continuar recebendo as mensagens que podem ser transmitidas por meio da conexão (e reconhecê-las). O FCM gerencia o início do fechamento de uma conexão quando adequado.

A mensagem CONNECTION_DRAINING tem a seguinte aparência:

<message>
  <data:gcm xmlns:data="google:mobile:data">
  {
    "message_type":"control"
    "control_type":"CONNECTION_DRAINING"
  }
  </data:gcm>
</message>

CONNECTION_DRAINING atualmente é o único control_type compatível.

Controle de fluxo

Toda mensagem enviada ao FCM recebe uma resposta ACK ou NACK. As mensagens que não receberam uma dessas respostas serão consideradas pendentes. Se a contagem de mensagens pendentes chegar a 100, o servidor de app interromperá o envio de novas mensagens e aguardará até que o FCM reconheça algumas das mensagens pendentes existentes, como ilustrado na figura 1:

Diagrama detalhado do fluxo de controle entre o FCM e o servidor do app

Figura 1. Fluxo de mensagem/ack.

Por outro lado, para evitar a sobrecarga do servidor de app, o FCM interromperá o envio se houver muitas mensagens não reconhecidas. Portanto, o servidor de app precisa reconhecer as mensagens upstream recebidas do aplicativo cliente via FCM o mais rápido possível para manter um fluxo constante de recebimento de mensagens. O limite de mensagens pendentes mencionado acima não se aplica a essas ACKs. Mesmo que a contagem de mensagens pendentes chegue a 100, o servidor de app continua enviando ACKs para mensagens recebidas do FCM para evitar o bloqueio da entrega de novas mensagens upstream.

As ACKs são válidas apenas dentro do contexto de uma conexão. Se a conexão fechar antes de uma mensagem ser reconhecida, o servidor de app precisará aguardar até que o FCM reenvie a mensagem upstream antes de reconhecê-la novamente. De modo semelhante, todas as mensagens pendentes que não tiverem recebido uma ACK/NACK do FCM até o encerramento da conexão precisarão ser reenviadas.