logo hsb.horse
← Zur Blog-Übersicht

Blog

Eine iOS-Shield-Oberfläche braucht zwei Extensions, nicht eine

Der von ManagedSettings angezeigte Shield-Bildschirm besteht aus zwei separaten Targets: einer Action Extension und einer Configuration Extension. Hier sind die richtigen NSExtensionPointIdentifier und Principal Classes.

Veröffentlicht:

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 ManagedSettingsUI
import 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.