PDM · DAW 2

Aula 19 · Semana 9 · Segunda, 2 de novembro de 2026 · 16:00 às 18:00

Push notifications, review da sprint 1 e revisão para o teste 1

Teoria (30 minutos): percurso de uma notificação push do servidor ao ecrã bloqueado. Review da sprint 1, retrospetiva e planeamento da sprint 2. Revisão para o teste 1: mapa da matéria e perguntas-tipo.

Review da sprint 1Teste 1 na quarta, 4/11

No fim desta aula consegues

Como uma push chega ao ecrã

1 · a app envia o token de dispositivo ao servidor Servidor da app token por utilizador 2 · payload FCM (Android) · APNs (iOS) escolhe o dispositivo pelo token 3 · entrega Sistema operativo mostra, acorda a app ou descarta Em primeiro plano a app recebe a mensagem (onMessage) e decide o que mostrar: snackbar, badge ou nada Em segundo plano o SO mostra a notificação no tray sem acordar a interface toque → onMessageOpenedApp Fechada o SO mostra a notificação o toque abre a app com o payload getInitialMessage() decide a rota
O servidor nunca fala com o telemóvel: entrega ao FCM ou APNs, e o sistema operativo decide o que fazer conforme o estado da app.
  1. A app regista-se no serviço da plataforma: APNs (Apple Push Notification service) no iOS, FCM (Firebase Cloud Messaging) no Android. Recebe um token de dispositivo: uma string longa que identifica esta instalação neste telemóvel.
  2. A app envia o token ao teu servidor, associado ao utilizador. Sem isto, o servidor não sabe a quem enviar.
  3. O servidor envia o payload ao FCM/APNs (nunca diretamente ao telemóvel), autenticado com uma chave de servidor.
  4. O FCM/APNs entrega ao sistema operativo, que decide: mostrar, acordar a app, ou descartar.

Para os testes: o teu servidor nunca fala com o telemóvel; fala com o FCM ou o APNs, que falam com o sistema operativo.

Analogia Os correios. A app não fica à porta à espera do carteiro: regista a sua morada, o token de dispositivo, nos correios da plataforma, o FCM ou o APNs. O servidor entrega a carta aos correios com essa morada, e os correios entregam-na quando o telemóvel estiver contactável. Uma única ligação do telemóvel aos correios serve todas as apps instaladas, e é por isso que a bateria aguenta.

Permissões: pedir no momento certo

Para os testes: um pedido de permissão explica-se antes de aparecer, e faz-se quando o utilizador já vê o benefício.

Payload: notificação vs dados

Estado da appMensagem de notificação (notification)Mensagem de dados (data)
ForegroundEntregue ao teu código; por defeito não aparece nada. A app decide mostrar.Entregue ao teu código.
BackgroundO sistema mostra-a na bandeja sem correr a app. Ao tocar, a app abre com os dados.Acorda a app por instantes para processar (com limites).
MortaIgual ao background: o sistema trata.Android: pode acordar a app. iOS: só se for silenciosa e o sistema deixar.

Para os testes: com a app em background, uma mensagem só de notificação é mostrada pelo sistema sem executar código da app.

Canais, categorias, som, badge e silêncio

Para os testes: canais são do Android e servem para o utilizador escolher que tipos de notificação quer.

Locais vs remotas

LocalRemota (push)
Quem a criaA própria app, no telemóvelUm servidor, via FCM/APNs
Precisa de redeNãoSim, pelo menos no momento da entrega
Quando serveLembretes, agendadas ("previsão de amanhã às 20:00"), eventos que a app já conheceNovidades que só o servidor sabe: aviso novo do IPMA, mensagem de outra pessoa
Aspeto para o utilizadorIdêntico. O utilizador não distingue.
Package Flutterflutter_local_notificationsfirebase_messaging

Na aula 22 fazemos notificações locais: a app deteta um aviso novo para um favorito quando atualiza, e agenda a previsão do dia seguinte. Push remoto exige um projeto Firebase por grupo; fica como extra do projeto.

Analogia Uma notificação local é um lembrete que a própria app deixa no frigorífico: escreve-o e agenda-o no telemóvel, sem passar pelos correios. Uma push remota é uma carta que vem de fora, e só os correios (FCM ou APNs) a sabem entregar. Para quem lê, o papel no frigorífico e a carta têm o mesmo aspeto.

Boas práticas

Para os testes: uma notificação sem deep link para o conteúdo é uma notificação mal feita.

Review da sprint 1: 5 minutos por grupo

O que cada grupo mostra

  1. 1 min: objetivo da sprint e o que entrou.
  2. 3 min: demo no telemóvel, projetada, a partir de main. Percurso: abrir a app, lista, detalhe, um estado de erro (modo avião).
  3. 1 min: o que ficou por fazer e porquê; o que muda na sprint 2.

O que o docente observa

  • A app corre a partir de main, sem cabo do docente.
  • Cada membro tem commits e PRs revistos por outro.
  • Estados de loading, erro e vazio existem.
  • Token e segredos fora do repositório.
  • Cada membro consegue explicar a sua parte.

Retrospetiva: 15 minutos

Cada grupo, em conjunto, escreve três colunas num documento partilhado ou em post-its:

ComeçarPararContinuar
O que não fizemos e devíamos ter feito. Ex.: rever PRs no próprio dia.O que nos atrasou. Ex.: PRs de 800 linhas; trabalhar todos no mesmo ficheiro.O que funcionou. Ex.: reunião de 10 min ao início de cada aula.

Planear a sprint 2 (3/11 a 18/11)

Até sexta, 6/11 Backlog da sprint 2 fechado no board do repositório, com issues atribuídas. O docente comenta as issues no fim de semana.

Mapa da matéria (1 de 3): fundações

Mapa da matéria (2 de 3): construir

Mapa da matéria (3 de 3): pôr em produção

Perguntas-tipo (1 de 3)

Método Lê a pergunta até ao fim. Risca as duas opções claramente erradas. Entre as duas que sobram, escolhe a que usa o vocabulário exato das aulas; a outra costuma ser "quase verdade".

1. Alteraste o corpo de main() e carregaste em r. A app não reflete a alteração. Porquê?

  1. O hot reload só funciona em modo release.
  2. O hot reload não volta a executar main(); é preciso hot restart.
  3. Faltou correr flutter pub get.
  4. O telemóvel está em modo avião.

2. Um cálculo de 2 segundos dentro de build faz a app…

  1. continuar fluida, porque o Dart é multithread por defeito.
  2. congelar, porque a interface corre numa única thread.
  3. ser terminada de imediato pelo sistema operativo.
  4. falhar a compilação.

3. Onde vive o estado de um StatefulWidget?

  1. No próprio widget, que por isso é mutável.
  2. No objeto State, que sobrevive aos rebuilds do widget.
  3. No BuildContext.
  4. No MaterialApp.

Perguntas-tipo (2 de 3)

4. Com go_router, qual é a diferença entre context.go('/x') e context.push('/x')?

  1. go substitui a pilha pela rota; push empilha por cima da atual.
  2. São equivalentes; push é o nome antigo.
  3. push só funciona na web.
  4. go só funciona com Navigator.push.

5. A API do curso devolve 429. O que deve a app fazer?

  1. Repetir imediatamente até obter 200.
  2. Esperar o tempo indicado em Retry-After e repetir com backoff.
  3. Mostrar um erro fatal e fechar a app.
  4. Trocar o método POST por GET.

6. Qual destes pedidos não deves repetir automaticamente depois de um timeout?

  1. GET /v1/locations
  2. GET /v1/forecast/3
  3. POST /v1/me/favorites
  4. GET /v1/warnings

7. Onde se guarda o token de acesso da API?

  1. Em shared_preferences, porque é rápido.
  2. Num ficheiro em getApplicationDocumentsDirectory().
  3. Em flutter_secure_storage, que usa o Keychain e o Keystore.
  4. Numa constante no código, para não se perder.

Perguntas-tipo (3 de 3)

8. Um JWT…

  1. é cifrado; ninguém consegue ler o conteúdo.
  2. é assinado; qualquer pessoa lê o conteúdo, mas não o altera sem invalidar a assinatura.
  3. nunca expira.
  4. deve conter a password do utilizador para renovar a sessão.

9. Para fazer o parse de uma resposta JSON de 5 MB sem jank, usas…

  1. setState depois do parse.
  2. Future.delayed para dar tempo à interface.
  3. compute() ou Isolate.run.
  4. async/await, que liberta a thread durante o parse.

10. Uma push só com campo notification, sem data, chega com a app em background. O que acontece?

  1. A app é acordada e decide o que mostrar.
  2. O sistema operativo mostra-a na bandeja sem executar código da app.
  3. É descartada.
  4. Fica guardada até a app ser aberta manualmente.

Respostas e porquê

  1. b. O hot reload injeta código e volta a chamar build; main e variáveis globais só com R.
  2. b. Uma thread de UI, um event loop. Cálculo pesado bloqueia até acabar.
  3. b. O widget é imutável; o State é o objeto que persiste.
  4. a. go é navegação declarativa para uma localização; push empilha um ecrã que se pode fechar com voltar.
  5. b. 429 é "abranda"; repetir de imediato piora e pode levar a bloqueio.
  1. c. POST não é idempotente: repetir pode criar o favorito duas vezes. GETs repetem-se sem risco.
  2. c. shared_preferences é um ficheiro legível num telemóvel com root; segredos vão para o armazenamento seguro do sistema.
  3. b. Base64 não é cifra. A assinatura garante integridade, não confidencialidade. Expira via exp.
  4. c. await só cede a thread em operações de espera; jsonDecode é cálculo puro.
  5. b. Mensagens de notificação em background são tratadas pelo sistema; só ao tocar é que a app recebe os dados.

Erros frequentes no teste

ErroPorque está errado
Confundir hot reload com hot restartReload mantém estado e não re-executa main; restart recomeça a app e perde o estado. Rebuild completo é outra coisa: flutter run de novo.
Widget "mutável" com campos que mudamWidgets são imutáveis e recriados a cada build; o que muda é o State ou o estado de aplicação num notifier.
! como solução para o null safetyForça um valor que pode ser null e transfere o erro do compilador para um crash em produção. Usa ?., ??, if ou padrões.
Token em shared_preferencesTexto legível no disco; num telemóvel com root ou numa cópia de segurança fica exposto. Keychain e Keystore existem para isto.
Retry automático em POSTUm POST não idempotente repetido cria duplicados. Retry só em operações seguras de repetir, com backoff e limite.

Para os testes: quando duas opções parecem certas, a certa é a que não tem uma palavra a mais ("sempre", "nunca", "só em iOS").

Até quarta, dia do teste

Para fazer

  • Estudar a componente teórica das aulas 1 a 19: os slides de teoria de cada aula e as frases "Para os testes".
  • Refazer as dez perguntas desta aula sem ver as respostas, e escrever uma pergunta nova por aula.
  • Backlog da sprint 2 fechado até sexta: issues com critérios de aceitação, estimativa e dono, organizadas no board.
  • Sprint 2: a branch de cada membro com o primeiro commit até sexta.

Para ler