Ir para o console

Seu ambiente de 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 de 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 de servidor confiável

Seu ambiente de servidor de aplicativos precisa atender aos seguintes critérios:

  • 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 códigos de mensagem para identificar exclusivamente cada mensagem enviada (o back-end HTTP do FCM gera códigos de mensagem e os retorna na resposta). Os códigos de mensagem XMPP precisam ser únicos por código 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 é compatível com 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.
  • O protocolo HTTP legado.
  • O protocolo de servidor XMPP. Observe que, se você quiser usar mensagens upstream dos seus aplicativos clientes, será necessário usar o XMPP.

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 com Adicionar o SDK. Em seguida, depois que o SDK Admin do Firebase for instalado, você poderá começar a criar 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.

Veja a seguir as diferenças entre as mensagens XMPP e HTTP:

  • 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 aplicativo emite uma solicitação POST com um cabeçalho HTTP e um corpo HTTP composto por pares 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 código identifica exclusivamente a mensagem em uma conexão XMPP. A ACK ou a NACK do FCM usa o message_id para identificar uma mensagem enviada a partir de servidores do app ao FCM. Dessa forma, é importante que esse message_id seja exclusivo (por código do remetente) e 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 ignorada pelo 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",
      "delivery_receipt_requested": true/false
  }
  </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":"SomeInvalidRegistrationId",
    "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@gcm.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 canal 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 no momento é o único control_type compatível.

Receber comprovantes de entrega

Para apps cliente Android e Chrome, você poderá receber confirmações de entrega (enviadas do FCM para seu servidor de app) quando um dispositivo confirmar que recebeu uma mensagem enviada pelo FCM.

Para ativar esse recurso, a mensagem que o servidor do app envia para o FCM precisa conter o campo delivery_receipt_requested. Quando esse campo é definido como true, o FCM envia uma confirmação de entrega no momento em que o recebimento da mensagem é confirmado em um dispositivo.

Esta é uma estrofe de XMPP que contém uma mensagem JSON com "delivery_receipt_requested" definido como true:

<message id="">
  <gcm xmlns="google:mobile:data">
  {
      "to":"REGISTRATION_ID",
      "message_id":"m-1366082849205"
      "data":
      {
          "hello":"world",
      }
      "time_to_live":"600",
      "delivery_receipt_requested": true
  }
  </gcm>
</message>

Este é um exemplo de confirmação de entrega que o FCM envia para informar ao servidor de app que um dispositivo recebeu uma mensagem enviada pelo FCM:

<message id="">
  <gcm xmlns="google:mobile:data">
  {
      "category":"com.example.yourapp", // to know which app sent it
      "data":
      {
         “message_status":"MESSAGE_SENT_TO_DEVICE",
         “original_message_id”:”m-1366082849205”
         “device_registration_id”: “REGISTRATION_ID”
      },
      "message_id":"dr2:m-1366082849205",
      "message_type":"receipt",
      "from":"gcm.googleapis.com"
  }
  </gcm>
</message>

Observe o seguinte:

  • O "message_type" está definido como "receipt".
  • O "message_status" está definido como "MESSAGE_SENT_TO_DEVICE", o que indica que o dispositivo recebeu a mensagem. Note que nesse caso, "message_status" não é um campo, mas parte do payload de dados.
  • O código da mensagem de confirmação consiste no código da mensagem original, mas com o prefixo dr2:. O servidor de app precisa usar a mesma conexão para enviar uma ACK de volta com esse código que, neste exemplo, é dr2:m-1366082849205.
  • O código da mensagem original, o token de registro do dispositivo e o status estão dentro do campo "data".
  • Se a conexão entre o FCM e o dispositivo estiver ruim, o Firebase Cloud Messaging poderá enviar várias notificações de entrega duplicadas. Você pode ignorar totalmente essas notificações duplicadas.

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:

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.