Wenn man mit ManagedSettings Sperrregeln setzt, zeigt iOS beim Zugriff auf eine gesperrte Website einen Shield-Bildschirm an. Beim Anpassen dieses Bildschirms gibt es eine Stelle, an der fast jede Person beim ersten Versuch hängen bleibt: Ein Extension-Target reicht nicht. Man braucht zwei.
Eine iOS-Extension ist ein kleiner Prozess, der getrennt von der Haupt-App läuft. In Xcode erstellt man sie als zusätzliches Target. Eine Shield Extension ist speziell für den Shield-Bildschirm gedacht und läuft unabhängig von der Haupt-App.
Shield Action Extension
Sie verarbeitet, was passiert, wenn die Nutzerin oder der Nutzer einen Button auf dem Shield-Bildschirm antippt. Die Principal Class, also der Einstiegspunkt der Extension, erbt von ShieldActionDelegate.
import ManagedSettings
class ShieldActionExtension: ShieldActionDelegate { override func handle( action: ShieldAction, for application: ApplicationToken, completionHandler: @escaping (ShieldActionResponse) -> Void ) { completionHandler(.close) }}Der Extension Point Identifier ist com.apple.ManagedSettings.shield-action-service.
Hier wird ManagedSettings importiert, nicht ManagedSettingsUI. Diese Verwechslung passiert leicht, deshalb lohnt sich der Hinweis.
Shield Configuration Extension
Sie passt die visuelle Darstellung des Shield-Bildschirms an. Man verwendet sie, wenn Titel, Text oder Button-Beschriftungen zum Kontext der App passen sollen. Die Principal Class erbt von ShieldConfigurationDataSource.
import ManagedSettingsUIimport ManagedSettings
class ShieldConfigurationExtension: ShieldConfigurationDataSource { override func configuration( shielding application: Application ) -> ShieldConfiguration { return ShieldConfiguration( backgroundBlurStyle: .systemUltraThinMaterial, title: ShieldConfiguration.Label(text: "集中モード中です", color: .label) ) }}Der Extension Point Identifier ist com.apple.ManagedSettingsUI.shield-configuration-service. Hier wird ManagedSettingsUI importiert.
Info.plist-Konfiguration
In jeder Target-Info.plist muss der richtige Extension Point Identifier gesetzt werden.
Für die Action Extension:
<key>NSExtensionPointIdentifier</key><string>com.apple.ManagedSettings.shield-action-service</string><key>NSExtensionPrincipalClass</key><string>$(PRODUCT_MODULE_NAME).ShieldActionExtension</string>Für die Configuration Extension:
<key>NSExtensionPointIdentifier</key><string>com.apple.ManagedSettingsUI.shield-configuration-service</string><key>NSExtensionPrincipalClass</key><string>$(PRODUCT_MODULE_NAME).ShieldConfigurationExtension</string>App Group nicht vergessen
Die beiden Extensions und die Haupt-App müssen dieselbe App Group teilen. App Groups sind der Mechanismus, mit dem mehrere Targets Daten gemeinsam nutzen können. Unter iOS können Apps normalerweise nicht direkt Daten austauschen, aber Targets innerhalb derselben App Group können einen gemeinsamen Container lesen und schreiben.
In Xcode fügt man unter Signing & Capabilities für jedes Target App Groups hinzu und trägt dieselbe Gruppen-ID ein. Das ist für alle drei Targets nötig: Haupt-App, Action Extension und Configuration Extension. Wenn man neu in der iOS-Entwicklung ist, passiert leicht der Fehler, dass man denkt, alles sei eingerichtet, obwohl ein Target fehlt. Fehlt auch nur eines, funktioniert das Teilen von Daten auf echten Geräten nicht.
Was man vom Shield-Bildschirm aus tun kann
ShieldActionDelegate kann nur zwei Werte zurückgeben: .close und .defer. .close schließt den Shield-Bildschirm und lässt die Sperre aktiv. .defer wird verwendet, um eine weitere Benutzeraktion auszulösen.
Die Haupt-App direkt vom Shield aus zu öffnen und dort einen Entsperrbildschirm anzuzeigen, lässt sich über diese Schnittstelle nicht direkt umsetzen. Auch das ist ein Punkt, der für iOS-Einsteigerinnen und -Einsteiger überraschend schwer greifbar ist. Das konkrete Muster dafür habe ich in einem eigenen Artikel beschrieben.
hsb.horse