Wenn man die Button-Logik in ShieldActionDelegate schreibt, kommt irgendwann der Moment, in dem man von dort die Haupt-App öffnen und einen Unlock-Screen anzeigen möchte. Genau diesen Ablauf kann man aber nicht direkt implementieren. Gerade ohne iOS-Erfahrung ist schwer nachvollziehbar, warum das so ist, deshalb lohnt sich zuerst der Hintergrund.
Warum eine Extension die App nicht direkt öffnen kann
ShieldActionDelegate kann nur zwei Werte zurückgeben: .close und .defer. Auf anderen Plattformen würde man hier vielleicht per URL-Scheme die App starten, aber im Shield-Kontext funktioniert dieser Weg nicht.
Apple blockiert diesen Pfad wahrscheinlich, um die Konsistenz des Shield-Erlebnisses zu schützen. Wenn der Shield selbst zum Schlupfloch wird, verliert das Blockieren seinen Sinn. Würde man der Extension direkten Sprung in die Haupt-App erlauben, könnte man die Einschränkung abhängig von der Implementierung aus der Einschränkung heraus aufheben. Das gilt allgemein für iOS-Extensions: Direkte Aktionen gegen die Haupt-App sind grundsätzlich eingeschränkt.
Das Handoff-Muster über App Group
Die realistische Implementierung ist ein asynchrones Handoff über geteilten Speicher.
App Group ist der Mechanismus, mit dem Haupt-App und Extension Daten teilen können. Normalerweise haben iOS-Prozesse keinen Zugriff auf die Daten anderer Prozesse. Wenn sie aber zur selben App Group gehören, können sie gemeinsame UserDefaults oder einen gemeinsamen Dateicontainer lesen und schreiben.
In der Shield Action Extension schreibt man ein Flag in den gemeinsamen App-Group-Container, das signalisiert, dass eine Unlock-Anfrage aussteht. Wenn der Nutzer die App später manuell öffnet, liest die Haupt-App dieses Flag und startet den Unlock-Flow.
// 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()}Der Shield wird mit .close geschlossen. Der Nutzer muss einmal zurück auf den Home Screen und die App dann manuell öffnen.
Warum zusätzlich ein Zeitstempel gespeichert wird
Wenn gleichzeitig mit der Anfrage auch der Zeitpunkt gespeichert wird, lässt sich alte Anfrage-Logik einfacher schreiben. Eine Regel wie „Anfragen älter als 30 Minuten sind ungültig“ verhindert, dass die App viel später unerwartet einen Unlock-Screen anzeigt.
Als UX-Entscheidung akzeptieren
Wenn man einen Ablauf erwartet wie „ein Tipp vom Shield direkt in den Unlock-Screen“, wirkt dieses Muster vielleicht unbefriedigend. Aber genau das ist der Rahmen, den Apples Interface zulässt.
Man kann es auch anders sehen: Dass der Nutzer den Shield bemerkt und die App bewusst selbst öffnet, ist schon Teil von Selbstkontrolle. Ein zusätzlicher Reibungsmoment kann besser zum Produktziel passen als eine One-Tap-Flucht.
Für die Implementierung ist es am schnellsten, diese Einschränkung zu akzeptieren und darauf aufzubauen.
hsb.horse