Notificação local ou push: quando o aviso do app precisa vir do servidor
Saiba quando uma notificação local resolve, quando só push resolve e como implementar o lembrete local no .NET MAUI com permissão pedida na hora certa, reagendamento e app funcionando sem permissão.
O app da clínica ganhou notificações. O lembrete "sua consulta é daqui a 1 hora" funciona perfeitamente, até com o celular no modo avião. Então a recepção remarca a consulta da dona Lúcia para outro dia, e ela aparece na clínica no horário antigo, guiada pelo lembrete que o próprio app disparou. O aviso "sua consulta foi remarcada" nunca chegou, porque ninguém tinha implementado o caminho do servidor até o celular.
A resposta curta: notificação local só sabe o que o aparelho já sabia quando ela foi agendada. Ela é ótima para lembrar de algo que o app conhece (uma consulta confirmada, um remédio, um treino). Quando a informação nasce no servidor e precisa chegar com o app fechado, o caminho é push, via Firebase Cloud Messaging no Android e APNs no iOS, com infraestrutura e custo próprios. Misturar os dois conceitos é o que cria a expectativa errada.
O que cada tipo de notificação faz por baixo
Uma notificação local é um pedido que o app faz ao sistema operacional: "às 13h de quinta, mostre este texto". No Android, isso costuma ser implementado com o agendador de alarmes do sistema e o gerenciador de notificações, como mostra a documentação do .NET MAUI; no iOS, com o centro de notificações do usuário. Na hora marcada, o sistema mostra o aviso mesmo que o app não esteja aberto. Mas o conteúdo foi decidido no momento do agendamento. Se a consulta mudou depois, o aviso agendado não sabe.
Uma notificação push faz o caminho inverso. O seu servidor manda uma mensagem para o serviço da plataforma (FCM ou APNs), endereçada a um token que identifica aquela instalação do app. O serviço entrega ao aparelho, e o sistema exibe. Para isso você precisa registrar o token de cada instalação no seu backend, guardar credenciais da plataforma no servidor, lidar com tokens que expiram e decidir quem recebe o quê. É outro projeto, não uma opção a mais na mesma API.
Como decidir entre os dois
- O app já tem a informação e o horário é conhecido? Local. Lembrete de consulta confirmada, alarme de medicação, meta diária.
- A informação nasce fora do aparelho? Push. Remarcação, mensagem do médico, resultado de exame pronto.
- Só importa com o app aberto? Nenhum dos dois: atualize a tela em tempo real, como em notificação em tempo real com SignalR.
- O aviso é importante para o negócio? Além da notificação, registre o fato no sistema. Notificação pode ser silenciada ou perdida, como explica o aviso é extra, o registro é que fica.
O que a plataforma exige de uma notificação local
No Android, desde a versão 8, toda notificação precisa de um canal, que a pessoa pode silenciar separadamente nas configurações. A partir do Android 13, mostrar notificação exige a permissão POST_NOTIFICATIONS, pedida em tempo de execução, como câmera ou localização. Alarmes agendados não sobrevivem a uma reinicialização do aparelho, e o modo de economia de energia pode atrasar alarmes que não são exatos. Alarmes exatos, em versões recentes, dependem de uma permissão especial que o sistema ou a pessoa podem negar. No iOS, a permissão também é pedida explicitamente, e há um limite de notificações locais pendentes por app.
Conclusão prática: trate o lembrete local como "melhor esforço com tolerância de alguns minutos" e nunca como o único lugar onde a pessoa fica sabendo de algo.
Como implementar o lembrete local no MAUI
No app da clínica, o lembrete é agendado quando a pessoa confirma a consulta e reconstruído sempre que o app abre, a partir da agenda que veio do servidor.
- Declare a permissão no manifesto do Android e crie o canal de notificação na inicialização.
- Esconda a plataforma atrás de uma interface, com uma implementação por sistema (o exemplo da documentação do MAUI para Android é um bom ponto de partida).
- Peça a permissão no momento do motivo: quando a pessoa toca em "Confirmar consulta" e o app explica que pode avisar uma hora antes.
- Se a permissão for negada, o app continua funcionando e mostra a consulta na agenda, com um aviso discreto.
- Use o id da consulta como id da notificação, para poder cancelar e substituir.
- Ao abrir o app, cancele e reagende todos os lembretes a partir da agenda atualizada. Isso cobre remarcações vistas no servidor e alarmes perdidos na reinicialização.
Permissão no manifesto
<!-- Platforms/Android/AndroidManifest.xml -->
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
A interface e o uso no ViewModel
public interface ILembreteService
{
Task<bool> PedirPermissaoAsync();
void Agendar(int id, string titulo, string mensagem, DateTime quando);
void Cancelar(int id);
}
public partial class AgendaViewModel(IAgendaApi api, ILembreteService lembretes)
{
public string? Aviso { get; private set; }
public async Task ConfirmarConsultaAsync(Consulta consulta)
{
await api.ConfirmarAsync(consulta.Id);
var quando = consulta.Inicio.AddHours(-1);
if (quando <= DateTime.Now) return;
if (!await lembretes.PedirPermissaoAsync())
{
Aviso = "Notificações desativadas. A consulta continua na aba Agenda.";
return;
}
lembretes.Agendar(consulta.Id, "Consulta em 1 hora",
consulta.Profissional + " - " + consulta.Local, quando);
}
public async Task SincronizarLembretesAsync()
{
var consultas = await api.ListarConfirmadasAsync();
foreach (var c in consultas)
{
lembretes.Cancelar(c.Id);
var quando = c.Inicio.AddHours(-1);
if (quando > DateTime.Now)
lembretes.Agendar(c.Id, "Consulta em 1 hora", c.Profissional + " - " + c.Local, quando);
}
}
}
Pedindo a permissão no Android
public async Task<bool> PedirPermissaoAsync()
{
var status = await Permissions.CheckStatusAsync<Permissions.PostNotifications>();
if (status != PermissionStatus.Granted)
status = await Permissions.RequestAsync<Permissions.PostNotifications>();
return status == PermissionStatus.Granted;
}
O pedido acontece depois que a pessoa entendeu o benefício. Se você pedir na primeira tela, antes de qualquer contexto, a chance de recusa é alta, e uma recusa no Android pode impedir que o sistema mostre o pedido de novo; daí em diante, só pelas configurações do aparelho. Note também que o SincronizarLembretesAsync é o que mantém o lembrete honesto: a remarcação da dona Lúcia teria cancelado o lembrete antigo na próxima vez que ela abrisse o app. Mas se ela não abrisse, só um push resolveria.
Quando chega a hora do push
Se a remarcação precisa chegar com o app fechado, o desenho passa a ter: registro do token do aparelho no seu backend, associado ao paciente; envio pelo servidor via FCM e APNs (diretamente ou por um serviço intermediário, como os hubs de notificação dos provedores de nuvem); remoção de tokens inválidos; e a mesma regra de permissão do lado do aparelho. O conteúdo do push deve ser mínimo: "Sua consulta foi alterada. Abra o app para ver." Dado de saúde no texto da notificação aparece na tela bloqueada para quem estiver perto do celular.
Erros comuns
- Vender notificação local como "o app avisa quando algo mudar". A pessoa confia no aviso e perde a informação que nasceu no servidor.
- Pedir permissão na primeira tela. A recusa vem antes do motivo e, no Android, pode ser definitiva até a pessoa mexer nas configurações.
- Agendar e nunca reagendar. Uma reinicialização apaga os alarmes, e remarcações deixam lembretes com horário errado.
- Agendar dezenas de lembretes de uma vez. Você esbarra no limite da plataforma e irrita a pessoa, que desliga tudo.
- App que trava ou fica inútil sem permissão. Notificação é conveniência; a agenda precisa funcionar sem ela.
- Dado sensível no texto do aviso. Nome do exame ou diagnóstico aparece na tela bloqueada.
Checklist
- Cada aviso do app está classificado como local (o aparelho já sabe) ou push (nasce no servidor).
- O manifesto declara
POST_NOTIFICATIONSe o app cria o canal na inicialização. - A permissão é pedida no momento em que o benefício fica claro.
- Com a permissão negada, o app continua funcionando e diz onde a informação está.
- Lembretes usam ids estáveis e são cancelados e reagendados quando o app abre.
- O texto da notificação não expõe dado sensível na tela bloqueada.
- Você testou com o aparelho reiniciado e com a permissão negada.
Pegue a lista de avisos que o seu app promete na loja de aplicativos e marque cada um: esse aviso existiria se o servidor nunca mais falasse com o aparelho depois do agendamento?