14) Cadastro do ExpoPushToken para Notificações

Esta documentação explica como o aplicativo deve obter o ExpoPushToken do aparelho, enviá-lo ao ERP e manter o vínculo atualizado para receber notificações de novos QR Codes.

Endpoint: registrar_push_token Provedor: Expo Push Service Autenticação: APP_KEY + DEVICE_TOKEN Android e iOS

1) Fluxo no app

  1. O app inicia e verifica a permissão para notificações.
  2. O app solicita a permissão ao usuário, caso ainda não tenha sido concedida.
  3. O app obtém o token com Notifications.getExpoPushTokenAsync().
  4. O app chama registrar_push_token usando o DEVICE_TOKEN já salvo no aparelho.
  5. O ERP cadastra o token ou substitui o token anterior do mesmo device.
  6. Quando um novo QR Code for criado, o ERP notifica todos os devices ativos da fazenda.
  7. Ao tocar na notificação, o app abre e executa a sincronização offline.

2) Regra importante

O ExpoPushToken não substitui o DEVICE_TOKEN. O DEVICE_TOKEN continua sendo usado para autenticar e identificar o aparelho no ERP. O ExpoPushToken é apenas o endereço utilizado pelo serviço do Expo para entregar notificações naquele dispositivo.

O app deve reenviar o token ao iniciar, pois ele pode mudar após reinstalação, limpeza dos dados ou atualização da configuração do projeto. O ERP substituirá automaticamente o token anterior.

3) Endpoint — Registrar ExpoPushToken

POST https://agroecologia.grupoekos.com.br/router/action.php

Headers

X-APP-KEY: <APP_KEY_FIXA_DO_APP>
X-DEVICE-TOKEN: <DEVICE_TOKEN_DO_APARELHO>

Body

action=apiG10
f=registrar_push_token
expo_push_token=ExponentPushToken[xxxxxxxxxxxxxxxxxxxxxx]
platform=android

Parâmetros

O endpoint também aceita push_token como nome alternativo de expo_push_token.

Formatos de token aceitos

ExpoPushToken[xxxxxxxxxxxxxxxxxxxxxx]
ExponentPushToken[xxxxxxxxxxxxxxxxxxxxxx]

Resposta — token cadastrado

{
  "success": true,
  "msg": "ExpoPushToken registrado com sucesso.",
  "data": {
    "id": 15,
    "device_id": 381,
    "cliente_id": 664,
    "platform": "android",
    "updated": false,
    "fila": {
      "processadas": 0,
      "enviadas": 0,
      "erros": 0
    }
  }
}

Resposta — token anterior substituído

{
  "success": true,
  "msg": "ExpoPushToken registrado com sucesso.",
  "data": {
    "id": 15,
    "device_id": 381,
    "cliente_id": 664,
    "platform": "android",
    "updated": true,
    "fila": {
      "processadas": 1,
      "enviadas": 1,
      "erros": 0
    }
  }
}

4) Como implementar no app React Native/Expo

Instalação

npx expo install expo-notifications expo-device expo-constants

Exemplo de registro

import { Platform } from 'react-native';
import * as Device from 'expo-device';
import * as Notifications from 'expo-notifications';
import Constants from 'expo-constants';

const API_URL = 'https://agroecologia.grupoekos.com.br/router/action.php';

export async function registrarNotificacoes(
  appKey: string,
  deviceToken: string,
) {
  if (!Device.isDevice) {
    throw new Error('Use um aparelho compatível para testar notificações.');
  }

  if (Platform.OS === 'android') {
    await Notifications.setNotificationChannelAsync('default', {
      name: 'Atualizações do G10',
      importance: Notifications.AndroidImportance.MAX,
      vibrationPattern: [0, 250, 250, 250],
    });
  }

  const permissaoAtual = await Notifications.getPermissionsAsync();
  let status = permissaoAtual.status;

  if (status !== 'granted') {
    const solicitacao = await Notifications.requestPermissionsAsync();
    status = solicitacao.status;
  }

  if (status !== 'granted') {
    return {
      success: false,
      permissionDenied: true,
    };
  }

  const projectId =
    Constants.expoConfig?.extra?.eas?.projectId ??
    Constants.easConfig?.projectId;

  if (!projectId) {
    throw new Error('projectId do Expo/EAS não localizado.');
  }

  const expoPushToken = (
    await Notifications.getExpoPushTokenAsync({ projectId })
  ).data;

  const body = new FormData();
  body.append('action', 'apiG10');
  body.append('f', 'registrar_push_token');
  body.append('expo_push_token', expoPushToken);
  body.append('platform', Platform.OS);

  const response = await fetch(API_URL, {
    method: 'POST',
    headers: {
      'X-APP-KEY': appKey,
      'X-DEVICE-TOKEN': deviceToken,
    },
    body,
  });

  const json = await response.json();

  if (!response.ok || !json.success) {
    throw new Error(json.msg || 'Erro ao registrar token de notificação.');
  }

  return {
    success: true,
    expoPushToken,
    data: json.data,
  };
}

5) Abertura da notificação e sincronização

O ERP envia no campo data as informações do evento. Quando o usuário tocar na notificação, o app deve verificar sincronizar: true, abrir a área principal e executar sincronizacao_offline.

Dados enviados na notificação

{
  "evento": "qrcode_novo",
  "qrcode_id": 1250,
  "tipo_conteudo": "kit_entrega",
  "nome_tabela": "pedidos",
  "id_tabela": 1484,
  "sincronizar": true
}

Exemplo de listener

const subscription = Notifications.addNotificationResponseReceivedListener(
  async (response) => {
    const data = response.notification.request.content.data;

    if (data?.sincronizar === true) {
      // Abrir a tela principal e chamar a sincronização offline.
      await executarSincronizacaoOffline();
    }
  },
);

// Ao desmontar o componente:
subscription.remove();

6) Notificação de novo QR Code

Quando um QR Code novo for criado, todos os devices ativos da fazenda que possuírem token receberão:

Título

Novos QR Codes disponíveis

Mensagem

Abra o aplicativo G10 Cytrus para atualizar as novas informações!

A notificação é apenas um aviso. Os novos dados serão baixados pelo endpoint sincronizacao_offline quando o app realizar a sincronização.

7) Respostas de erro

APP_KEY ausente

{
  "success": false,
  "error": "missing_api_key",
  "msg": "API key não informada.",
  "data": []
}

DEVICE_TOKEN inválido

{
  "success": false,
  "error": "device_token_not_found",
  "msg": "DEVICE_TOKEN não encontrado.",
  "data": []
}

ExpoPushToken ausente

{
  "success": false,
  "error": "missing_expo_push_token",
  "msg": "ExpoPushToken não informado.",
  "data": []
}

ExpoPushToken inválido

{
  "success": false,
  "error": "invalid_expo_push_token",
  "msg": "ExpoPushToken inválido.",
  "data": []
}

Plataforma inválida

{
  "success": false,
  "error": "invalid_platform",
  "msg": "Plataforma inválida. Use android ou ios.",
  "data": []
}

8) Observações para os desenvolvedores

  • Não salvar o ExpoPushToken no lugar do DEVICE_TOKEN.
  • Registrar o token somente após o pareamento e a obtenção do DEVICE_TOKEN.
  • Reenviar o ExpoPushToken ao iniciar o app.
  • Se a permissão for negada, o restante do aplicativo deve continuar funcionando normalmente.
  • Não executar sincronizações paralelas ao tocar repetidamente na notificação.
  • O retorno updated: true indica que o token anterior daquele device foi substituído.
  • Tokens recusados pelo Expo como DeviceNotRegistered são desativados pelo ERP.
  • O campo fila informa quantas notificações pendentes foram processadas após o cadastro.

9) Histórico de alterações

  • 01/09/2026: criado o endpoint registrar_push_token.
  • 01/09/2026: implementada a substituição automática do token anterior do mesmo device.
  • 01/09/2026: integrado o envio de notificações de novos QR Codes pelo Expo Push Service.