expo-notifications
Permissões, canais, tratamento em primeiro plano e registro de token push - o cookbook expo-notifications para aplicativos Expo SDK 57 que precisam de alertas locais e push remotos.
Busque em todas as páginas da documentação
Permissões, canais, tratamento em primeiro plano e registro de token push - o cookbook expo-notifications para aplicativos Expo SDK 57 que precisam de alertas locais e push remotos.
Cartão de receita de referência rápida - pronto para copiar e colar.
npx expo install expo-notifications expo-device expo-constants// src/notifications/setup.ts - importe na entrada do aplicativo
import * as Notifications from "expo-notifications";
import { Platform } from "react-native";
Notifications.setNotificationHandler({
handleNotification: async () => ({
shouldShowBanner: true,
shouldShowList: true,
shouldPlaySound: true,
shouldSetBadge: true,
}),
});
export async function ensureAndroidChannel() {
if (Platform.OS !== "android") return;
await Notifications.setNotificationChannelAsync("default", {
name: "Default",
importance: Notifications.AndroidImportance.DEFAULT,
});
}
export async function requestNotificationPermission(): Promise<boolean> {
const { status: existing } = await Notifications.getPermissionsAsync();
if (existing === "granted") return true;
const { status } = await Notifications.requestPermissionsAsync();
return status === "granted";
}// src/notifications/pushToken.ts
import Constants from "expo-constants";
import * as Device from "expo-device";
import * as Notifications from "expo-notifications";
import { Platform } from "react-native";
export async function getExpoPushToken(): Promise<string | null> {
if (!Device.isDevice) return null;
const granted = await requestNotificationPermission();
if (!granted) return null;
const projectId =
Constants.expoConfig?.extra?.eas?.projectId ??
Constants.easConfig?.projectId;
if (!projectId) {
throw new Error("EAS projectId faltando - execute npx eas init");
}
const token = await Notifications.getExpoPushTokenAsync({ projectId });
return token.data;
}Quando usar:
Quando evitar:
Portão de permissão, canal Android, registro de token e listener de toque para navegação.
npx expo install expo-notifications expo-device expo-constants// app/(tabs)/settings/notifications.tsx
import { useState } from "react";
import { Pressable, Text, View } from "react-native";
import {
ensureAndroidChannel,
requestNotificationPermission,
} from "@/notifications/setup";
import { registerPushToken } from "@/notifications/registerPushToken";
export default function NotificationSettingsScreen() {
const [status, setStatus] = useState<"idle" | "granted" | "denied">("idle");
async function enableNotifications() {
await ensureAndroidChannel();
const granted = await requestNotificationPermission();
if (!granted) {
setStatus("denied");
return;
}
await registerPushToken();
setStatus("granted");
}
return (
<View style={{ padding: 24, gap: 12 }}>
<Text>Receba alertas quando os motoristas chegarem ao local.</Text>
<Pressable onPress={enableNotifications}>
<Text style={{ color: "#2563eb", fontWeight: "600" }}>
Habilitar notificações
</Text>
</Pressable>
{status === "denied" && (
<Text>Abra Configurações para permitir notificações para este aplicativo.</Text>
)}
</View>
);
}// src/notifications/registerPushToken.ts
import { getExpoPushToken } from "./pushToken";
export async function registerPushToken() {
const token = await getExpoPushToken();
if (!token) return;
await fetch(`${process.env.EXPO_PUBLIC_API_URL}/devices/push-token`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ token, platform: "expo" }),
});
}// app/_layout.tsx
import { useEffect } from "react";
import * as Notifications from "expo-notifications";
import { router, Stack } from "expo-router";
import "@/notifications/setup";
export default function RootLayout() {
useEffect(() => {
const sub = Notifications.addNotificationResponseReceivedListener(
(response) => {
const orderId = response.notification.request.content.data?.orderId;
if (typeof orderId === "string") {
router.push(`/orders/${orderId}`);
}
}
);
return () => sub.remove();
}, []);
return <Stack />;
}O que isso demonstra:
getExpoPushTokenAsync.data.orderId.| Etapa | API | Notas |
|---|---|---|
| Verificar atual | getPermissionsAsync() | undetermined na primeira inicialização |
| Explicar valor | Tela no aplicativo | Necessário para narrativa de Revisão de App |
| Solicitar | requestPermissionsAsync() | iOS mostra folha do sistema uma vez por instalação |
| Android 13+ | Igual + canal | Permissão de tempo de execução POST_NOTIFICATIONS |
HIGH apenas para alertas urgentes.scheduleNotificationAsync ou exibição remota.| Estado | Comportamento | Configuração |
|---|---|---|
| Primeiro Plano | Banner controlado por setNotificationHandler | shouldShowBanner: true |
| Segundo Plano | O sistema operacional exibe de acordo com as configurações do canal | O manipulador padrão ainda se aplica a dados apenas no Android |
| Encerrado | O toque abre o aplicativo; use getLastNotificationResponseAsync | Navegação de inicialização a frio |
Instalar → getExpoPushTokenAsync → POST /devices
Reinstalar → novo token → atualizar linha do servidor
Logout → EXCLUIR token do servidor + desregistrar opcional
Troca de conta → registrar novo token sob novo userIddeviceId, não apenas userId.getExpoPushTokenAsync - aplicativos de produção geralmente se conectam diretamente ao FCM/APNs via credenciais EAS.| API | Propósito |
|---|---|
setNotificationHandler | Apresentação em primeiro plano |
setNotificationChannelAsync | Configuração de canal Android |
getExpoPushTokenAsync | Token push do Expo |
scheduleNotificationAsync | Alertas locais agendados |
addNotificationReceivedListener | Recebimento em primeiro plano |
addNotificationResponseReceivedListener | Usuário tocou na notificação |
getLastNotificationResponseAsync | Manipulação de toque em inicialização a frio |
getExpoPushTokenAsync lança um erro. Correção: npx eas init e confirme extra.eas.projectId.setNotificationChannelAsync antes da primeira postagem.index.ts ou _layout.tsx no topo.data.token no push pode ser interceptado. Correção: Troque IDs opacos no lado do servidor.| Alternativa | Use Quando | Não Use Quando |
|---|---|---|
expo-notifications local | Lembretes agendados, alertas offline | Marketing orientado por servidor em escala sem backend |
| Expo push + EAS | Novos aplicativos Expo | Você já possui integração direta FCM/APNs |
| FCM/APNs direto | Controle de payload personalizado | Você deseja a configuração Expo mais rápida |
| Apenas no aplicativo (sem push) | O usuário está sempre no aplicativo durante a tarefa | Trabalhadores de campo que executam o aplicativo em segundo plano |
npx expo install expo-notifications expo-device expo-constantsAdicione o plugin de configuração em app.config.ts para ícones e sons personalizados. Reconstrua o binário nativo após as alterações do plugin.
Device.isDevice é falso em simuladores.const last = await Notifications.getLastNotificationResponseAsync();
if (last) navigateFromNotification(last);channelId no conteúdo scheduleNotificationAsync para local; payloads remotos definem channelId no Android.Versões da Stack: Esta página foi escrita para React 19.2.3, React Native 0.86.0 e Expo SDK 57 (
expo~57.0.4).
Revisado por Chris St. John·Última atualização: 16 de jul. de 2026