Ao escrever o tratamento dos botões em ShieldActionDelegate, chega um momento em que você quer abrir o app principal dali mesmo e mostrar uma tela de desbloqueio. Só que esse fluxo não pode ser escrito de forma direta. Quando se está começando em iOS, é uma daquelas partes em que entender por que isso não funciona é difícil, então vale começar pelo contexto.
Por que uma Extension não pode abrir o app diretamente
ShieldActionDelegate só pode retornar dois valores: .close e .defer. Em outras plataformas, este seria o ponto para usar um URL scheme e abrir o app, mas no contexto do shield esse caminho não funciona.
É razoável supor que a Apple feche essa rota para preservar a consistência da experiência do shield. Se o shield virar um atalho de fuga, o bloqueio perde o sentido. Se fosse permitido à extension pular direto para o app principal, dependendo da implementação seria possível remover a restrição a partir de dentro da própria restrição. Isso vale para extensions iOS de forma geral: operações diretas sobre o app principal são limitadas.
O padrão de handoff via App Group
A implementação realista é um handoff assíncrono por meio de armazenamento compartilhado.
App Group é o mecanismo que permite ao app principal e à extension compartilhar dados. Normalmente, processos iOS não acessam os dados uns dos outros, mas, quando pertencem ao mesmo App Group, podem ler e escrever em UserDefaults compartilhados ou em um contêiner de arquivos comum.
Na Shield Action Extension, grava-se no contêiner compartilhado do App Group um sinal de que existe um pedido de desbloqueio pendente. Quando o usuário abre o app manualmente depois, o app principal lê esse sinal e inicia o fluxo de desbloqueio.
// Shield Action Extension 内override func handle( action: ShieldAction, for webDomain: WebDomainToken, completionHandler: @escaping (ShieldActionResponse) -> Void) { let defaults = UserDefaults(suiteName: "group.com.example.stoicdns") defaults?.set(true, forKey: "pendingUnlockRequest") defaults?.set(Date(), forKey: "unlockRequestedAt") completionHandler(.close)}// メインアプリの起動時 / フォアグラウンド復帰時func checkPendingUnlock() { let defaults = UserDefaults(suiteName: "group.com.example.stoicdns") guard defaults?.bool(forKey: "pendingUnlockRequest") == true else { return } defaults?.removeObject(forKey: "pendingUnlockRequest") showUnlockFlow()}O shield se fecha com .close. O usuário precisa voltar para a tela inicial e abrir o app manualmente.
Por que salvar também um timestamp
Se o horário do pedido for salvo junto, fica mais fácil escrever a lógica que ignora solicitações antigas. Uma regra como “pedidos com mais de 30 minutos são inválidos” evita que o app mostre uma tela de desbloqueio inesperada muito tempo depois.
Aceitar isso como decisão de UX
Se a expectativa for um fluxo de “um toque do shield direto para a tela de desbloqueio”, esse padrão pode parecer limitado. Mas esse é o alcance permitido pela interface da Apple.
Também dá para olhar por outro ângulo: perceber o shield e então abrir o app de propósito já faz parte do autocontrole. Ter uma etapa extra de fricção pode combinar melhor com o objetivo do produto do que uma saída em um único toque.
Do ponto de vista de implementação, o mais rápido é aceitar essa restrição e seguir em frente.
hsb.horse