Quando você tenta criar um app de autocontrole para bloquear sites sem experiência prévia em desenvolvimento iOS, logo acumula uma série de momentos de “isso não era o que eu imaginava”. Eu comecei com NEDNSProxyProvider porque queria um bloqueio em nível de DNS, depois descobri as extensions, bati nas limitações de assinatura e por fim cheguei à forma correta de usar a Screen Time API.
Este artigo é um índice que conecta cinco posts separados surgidos nesse processo. Espero que ele ajude quem tem pouca experiência com iOS e está esbarrando no mesmo problema.
1. Não entre pela porta errada logo no começo
Quando você procura uma forma de bloquear sites no iOS, NEDNSProxyProvider parece exatamente o que precisa. O nome combina, o caso de uso parece correto, mas ele não foi feito para apps distribuídos na App Store. É uma classe voltada para dispositivos supervisionados gerenciados por MDM.
Não escolha NEDNSProxyProvider ao criar bloqueio de sites no iOS
Vale ler isso antes de decidir abandonar a ideia de bloqueio por DNS e migrar para a Screen Time API.
2. A arquitetura básica da Screen Time API
A combinação certa é FamilyControls + ManagedSettings. Você solicita autorização com AuthorizationCenter, deixa o usuário escolher o que bloquear com FamilyActivityPicker e grava as regras em ManagedSettingsStore.
Projetando bloqueio de autocontrole no iOS com FamilyControls + ManagedSettings
Tentar gerenciar alvos bloqueados como URLs de texto livre leva a um beco sem saída. O artigo também explica por que o desenho baseado em tokens em torno de FamilyActivitySelection é a premissa real.
3. São necessárias duas Shield Extensions
Para personalizar a tela Shield exibida quando ManagedSettings aplica regras, você precisa de duas extensions. Se assumir que basta adicionar um target no Xcode, é aqui que vai travar.
A interface Shield no iOS precisa de duas extensions, não de uma
O artigo organiza os Extension Point Identifier, as principal classes e as configurações de Info.plist da Shield Action Extension (ShieldActionDelegate) e da Shield Configuration Extension (ShieldConfigurationDataSource).
4. Handoff de desbloqueio entre o Shield e o app
A Apple não oferece um caminho para que a tela Shield abra diretamente o app principal e execute um fluxo de desbloqueio. ShieldActionDelegate só pode retornar .close ou .defer.
Implementando o handoff de desbloqueio de uma Shield Extension para o app principal via App Group
Esse artigo explica o padrão em que a extension grava uma “solicitação de desbloqueio” nos UserDefaults compartilhados de um App Group, e o app a lê quando o usuário abre o aplicativo. Também cobre por que essa limitação existe e como ajustar a UX dentro dessa restrição.
5. Testes em dispositivo exigem conta paga de desenvolvedor
O entitlement Family Controls (Development) não está disponível em um Personal Team usando um Apple ID gratuito. Testar em um dispositivo real exige adesão ao Apple Developer Program.
Não é possível testar Family Controls em dispositivo real com Personal Team
O artigo organiza o que é possível e o que não é no simulador, a relação com outros entitlements como In-App Purchase e em que momento faz sentido pagar pelo programa.
Resumo como ordem de implementação
Se você vai construir esse app sem experiência anterior em iOS, a ordem de implementação fica muito mais clara depois de ler esses cinco posts.
Primeiro, abandone a ideia de NEDNSProxyProvider. Depois, feche a arquitetura básica com FamilyControls + ManagedSettings e monte o fluxo de UI usando AuthorizationCenter e FamilyActivityPicker. Em seguida, adicione as duas Shield Extensions e configure corretamente o Info.plist. Depois disso, implemente o handoff de desbloqueio via App Group. Por fim, entre no Apple Developer Program e valide tudo em um dispositivo real.
Seguindo essa ordem, a chance de precisar refazer a arquitetura mais tarde cai bastante. Quando você ainda não está acostumado com iOS, errar na escolha da API no começo costuma contaminar tudo o que vem depois. Por isso, confirmar a direção logo no início é o que mais economiza tempo.
hsb.horse