Quando você define regras de bloqueio com ManagedSettings, o iOS mostra uma tela Shield ao acessar um site bloqueado. Existe um ponto em que quase todo mundo trava na primeira tentativa de personalizar essa tela: adicionar só uma extension não basta. São necessários dois targets.
Uma extension no iOS é um pequeno processo que roda separado do app principal. No Xcode, ela é criada adicionando um novo target. A Shield Extension é uma extension dedicada à tela Shield e roda de forma independente do app principal.
Shield Action Extension
Ela cuida do que acontece quando o usuário toca em um botão na tela Shield. A principal class, ou seja, a classe que funciona como ponto de entrada da extension, herda de ShieldActionDelegate.
import ManagedSettings
class ShieldActionExtension: ShieldActionDelegate { override func handle( action: ShieldAction, for application: ApplicationToken, completionHandler: @escaping (ShieldActionResponse) -> Void ) { completionHandler(.close) }}O Extension Point Identifier é com.apple.ManagedSettings.shield-action-service.
Aqui você importa ManagedSettings, não ManagedSettingsUI. Essa confusão acontece com facilidade, então vale registrar explicitamente.
Shield Configuration Extension
Ela personaliza o visual da tela Shield. Use quando quiser ajustar título, texto e rótulos dos botões ao contexto do app. A principal class herda de ShieldConfigurationDataSource.
import ManagedSettingsUIimport ManagedSettings
class ShieldConfigurationExtension: ShieldConfigurationDataSource { override func configuration( shielding application: Application ) -> ShieldConfiguration { return ShieldConfiguration( backgroundBlurStyle: .systemUltraThinMaterial, title: ShieldConfiguration.Label(text: "集中モード中です", color: .label) ) }}O Extension Point Identifier é com.apple.ManagedSettingsUI.shield-configuration-service. Esta extension importa ManagedSettingsUI.
Configuração do Info.plist
Defina o Extension Point Identifier correto no Info.plist de cada target.
No caso da Action Extension:
<key>NSExtensionPointIdentifier</key><string>com.apple.ManagedSettings.shield-action-service</string><key>NSExtensionPrincipalClass</key><string>$(PRODUCT_MODULE_NAME).ShieldActionExtension</string>No caso da Configuration Extension:
<key>NSExtensionPointIdentifier</key><string>com.apple.ManagedSettingsUI.shield-configuration-service</string><key>NSExtensionPrincipalClass</key><string>$(PRODUCT_MODULE_NAME).ShieldConfigurationExtension</string>Não esqueça da configuração de App Group
As duas extensions e o app principal precisam compartilhar o mesmo App Group. App Group é o mecanismo usado para compartilhar dados entre vários targets. No iOS, apps normalmente não conseguem trocar dados diretamente, mas targets no mesmo App Group conseguem ler e gravar no contêiner compartilhado.
No Xcode, adicione App Groups em Signing & Capabilities para cada target e configure o mesmo group ID. Isso precisa existir nos três targets: app principal, Action Extension e Configuration Extension. Para quem está começando no desenvolvimento iOS, é fácil achar que configurou tudo e ainda deixar um target de fora. Se faltar um único target, os dados não serão compartilhados no dispositivo real.
O que dá para fazer a partir da tela Shield
ShieldActionDelegate só pode retornar dois valores: .close e .defer. .close fecha a tela Shield e mantém o bloqueio. .defer é usado para disparar uma interação adicional do usuário.
Abrir o app principal diretamente a partir da tela Shield e mostrar um fluxo de desbloqueio não é algo que essa interface permita fazer de forma direta. Esse também é um ponto que costuma ser pouco intuitivo para quem está começando no desenvolvimento iOS. Separei esse padrão de implementação em outro artigo.
hsb.horse