canOpenURL ist veraltet: Was Sie stattdessen aufrufen
In drei Sätzen hat Apple eine Methode ausgemustert, die seit iOS 3.0 ausgeliefert wird: „canOpenURL: ist veraltet. Versuchen Sie, die URL zu öffnen, und behandeln Sie einen etwaigen Fehlschlag, statt sie vorab zu validieren. Universal Links statt eigener URL-Schemes machen diese Validierung vollständig überflüssig.”1
Der Eintrag trägt das Radar 179874781 und steht unter UIKit, Deprecations, unmittelbar unter der Vorgabe zum Scene-Lebenszyklus, die Apps am Start hindert.1 Der Nachbareintrag benennt eine Konsequenz. Der canOpenURL-Eintrag benennt keine.
Jeder der drei Sätze ist eine eigenständige Anweisung, und nur der zweite beantwortet die Frage, die Entwickler tatsächlich haben: Was schreibe ich stattdessen? Apples Antwort ändert die Form des Aufrufs, nicht bloß den Namen.
Kurzfassung
- Apple hat
canOpenURL(_:)unter 27.0 auf iOS, iPadOS, Mac Catalyst, tvOS und visionOS als veraltet markiert, mit dem Hinweis „Prefer attempting to open URLs and handling any failures.”2 Keine Entfernungsversion, keine Konsequenz zur Laufzeit. - Die Änderung mit Biss ist eine Zahl, und sie steht in der Beschreibung der veralteten Methode selbst statt in irgendeiner Release Note: „Apps linked on or after iOS 27 are limited to a maximum of 25 entries in the
LSApplicationQueriesSchemeskey” – zuvor 50.2 Ausgelöst wird das durch das SDK, gegen das Sie linken. - Der mechanische Austausch ist
open(_:options:completionHandler:)mit seinem Boolean, der keinen Positivlisteneintrag braucht: „theopen(_:options:completionHandler:)method isn’t constrained by theLSApplicationQueriesSchemesrequirement.”2 - Ein Muster verliert seinen Ersatz, denn
canOpenURLantwortet, bevor Sie irgendetwas zeichnen, während der Öffnungsversuch durch seine Folgen antwortet: Ein Erfolg holt eine andere App in den Vordergrund.2 Was bleibt, istuniversalLinksOnly, eineopen-Option seit iOS 10, die Apple nicht abgekündigt hat: Sie „opens the URL only if the URL is a valid universal link and there is an installed app capable of opening that URL.”3 - SwiftUI hat die Methode nie ausgeliefert, und der Boolean im Completion-Handler bedeutet ohnehin schon „kann öffnen” statt „hat geöffnet”.415 Über sieben meiner ausgelieferten Apps und 463 eigene Swift-Dateien hinweg kommen
canOpenURLundLSApplicationQueriesSchemesjeweils null Mal vor.6
Die Abkündigung ohne Konsequenz – und die Zahl, die eine hat
Apple hat eine Abkündigung geschrieben, keine Entfernung. Die Symbolseite führt deprecatedAt 27.0 auf allen fünf Plattformen, auf denen UIApplication existiert, und Kurzbeschreibung, Diskussion, Rückgabewert-Vertrag sowie Deklaration bleiben sämtlich bestehen.2 Keine Apple-Seite nennt eine Version, in der die Methode ihren Dienst einstellt, und der nächstliegende Präzedenzfall weist in die andere Richtung: openURL(_:), seit iOS 10.0 veraltet, hat weiterhin eine Seite, und der Hinweis dort lautet inzwischen „Calling this method has no effect.”7 Ein Jahrzehnt Abkündigung hat eine Methode hervorgebracht, die wirkungslos ist statt abwesend – ein Präzedenzfall also, kein Zeitplan.
Auch die Ankündigung fällt schmaler aus als die Abkündigung selbst. Die Release Note steht auf einer Seite, die Apple „iOS & iPadOS 27 Beta 4 Release Notes” betitelt, und taucht sonst nirgends auf, während die Symbol-Metadaten die Methode gleichwohl auf tvOS und visionOS abkündigen; weder Apples UIKit-Updates-Seite für Juni 2026 noch die Xcode-27-Release-Notes erwähnen sie überhaupt.1289 Die Symbolseite ist hier die haltbare Hälfte der Aktenlage.
Womit die vergrabene Zahl zur eigentlichen Geschichte wird. In der Beschreibung der veralteten Methode selbst, in derselben Randbemerkung, die die Deklaration überhaupt erst verlangt: „Apps linked on or after iOS 15 are limited to a maximum of 50 entries in the LSApplicationQueriesSchemes key. Apps linked on or after iOS 27 are limited to a maximum of 25 entries in the LSApplicationQueriesSchemes key.”2
Die Positivliste überlebt die Abkündigung der einzigen Methode, der sie dient, und die Obergrenze halbiert sich für Apps, die gegen das neue SDK gelinkt sind. Apple nennt die Obergrenze und belässt es dabei. Nirgends steht, was jenseits von Eintrag 25 geschieht, und wer die beiden Hälften der Randbemerkung zusammenliest, erhält eine wahrscheinliche Antwort statt einer dokumentierten: Nicht deklarierte Schemes liefern stets false, eine App mit 40 deklarierten Schemes behandelt nach dem Neulinken also vermutlich 15 davon als abwesend. Welche 15 das sind – oder ob die Kürzung überhaupt der Reihenfolge im Array folgt – sagt Apple nirgends. Behandeln Sie den Mechanismus als Schlussfolgerung und das Risiko als real, denn ein false sieht identisch aus, ob nun die App fehlt oder die Deklaration.
Der nächste Absatz derselben Beschreibung nennt eine zweite Grenze, und die beiden sind Alternativen, nicht Summanden. Apple knüpft sie an das SDK, gegen das Sie gelinkt haben: „If you link your app against an earlier version of iOS but it is running in iOS 9.0 or later, you can call this method up to 50 times. After reaching that limit, subsequent calls always return false. If the user reinstalls or upgrades the app, iOS resets the limit.”2 Lesen Sie die Bedingung. Dieses Kontingent gehört Apps, die vor iOS 9 gelinkt wurden – nichts, was Sie heute noch ausliefern können. Jede aktuelle App lebt unter dem anderen Zweig, der Deklarationsgrenze, und genau die hat Apple von 50 auf 25 Einträge gekürzt. Beide laufen auf dasselbe stumme false hinaus, und beide sind ausschließlich innerhalb jener Methode dokumentiert, die Apple soeben abgekündigt hat.
Auch die Datenschutzlesart ist Schlussfolgerung. canOpenURL war der gängige Weg, um zu erkennen, welche Apps jemand installiert hatte – ein Gerätesignal also, keine Link-Prüfung –, und Apples eigene Definition von Fingerprinting erfasst APIs, die „misused to access device signals to try to identify the device or user” werden.10 Apple stellt die Verbindung nirgends her: Die Methode erscheint auf keiner Liste der APIs mit Begründungspflicht, und Release Note, Abkündigungshinweis und Symbolseite liefern durchweg eine rein mechanische Begründung.1210 Eine halbierte Abfragegrenze passt zur Datenschutzgeschichte – aufgeschrieben hat Apple sie nicht.
Was canOpenURL tatsächlich zugesichert hat
Ein true war eine Garantie für den nächsten Aufruf, keine Beschreibung der URL: „When this method returns true, iOS guarantees subsequent calls to the open(_:options:completionHandler:) method with the same URL will successfully launch an app that can handle the URL.”2 Ein false war bewusst mehrdeutig, mit zwei Ursachen und ohne Möglichkeit zu erkennen, welche zugetroffen hat: „false if the device doesn’t have an installed app registered to handle the URL’s scheme, or if you haven’t declared the URL’s scheme in your Info.plist file.”2
Drei Dinge hat die Methode nie beantwortet, obwohl man es leicht annimmt: „The return value doesn’t indicate the validity of the URL, whether the specified resource exists, or, in the case of a universal link, whether the device has an installed app registered to respond to the universal link.”2 Der dritte Teilsatz ist für die von Apple empfohlene Migration entscheidend und kommt weiter unten zurück.
Die Eigenschaft, die die Methode strukturell nützlich machte, ist genau jene, die nichts ersetzt. canOpenURL trägt in seiner Deklaration das Schlüsselwort nonisolated, und Apple stellt unmissverständlich fest: „you can call this method safely on a thread that isn’t the main thread.”2 Ein synchroner Boolean, der außerhalb des Main Actors verfügbar ist, kann eine Layout-Entscheidung steuern, bevor irgendetwas gerendert wird.
Versuchen und behandeln: die Form, die sich ändert
Apples Ersatzanweisung ist einen Teilsatz lang, und Vorher/Nachher wirkt trivial.
// Before: validate, then open. Requires an Info.plist declaration.
let url = URL(string: "someapp://profile/42")!
if UIApplication.shared.canOpenURL(url) {
UIApplication.shared.open(url)
} else {
presentWebFallback()
}
<key>LSApplicationQueriesSchemes</key>
<array>
<string>someapp</string>
</array>
// After: attempt, then handle. No declaration needed.
let url = URL(string: "someapp://profile/42")!
let opened = await UIApplication.shared.open(url)
if !opened {
presentWebFallback()
}
Der Info.plist-Eintrag verschwindet, und Apple sagt das direkt: „Unlike this method, the open(_:options:completionHandler:) method isn’t constrained by the LSApplicationQueriesSchemes requirement. If an app is available to handle the URL, the system will launch it, even if you haven’t declared the scheme.”2 Eine Codebasis, die vollständig migriert, löscht den Key – und mit ihm das 25-Einträge-Problem.
Zwei Unterschiede überleben die Umschreibung, und beide sind struktureller Natur.
Der erste betrifft Isolation und Zeitpunkt. Die Deklaration von UIApplication lautet @MainActor class UIApplication, open läuft also auf dem Main Actor, und die Kurzbeschreibung benennt genau das: „Attempts to asynchronously open the resource at the specified URL.”1112 Der synchrone Boolean abseits des Main Threads ist weg; Validieren-dann-Öffnen-Logik, die in einer Model-Schicht, einer Hintergrund-Queue oder einem nicht isolierten Helfer sitzt, muss also umziehen oder async werden.
Der zweite: Sie können nicht mehr im Verborgenen fragen. Gelingt der Versuch, steht eine andere App im Vordergrund: „iOS launches that app and passes the URL to it. (Launching the app brings the other app to the foreground.)”12 Die Antwort kommt als Nebenwirkung des Handelns. Für den Fehlschlag dokumentiert Apple nichts Sichtbares, nur dass „the completion handler is called with the success parameter set to false” – doch jedes Muster, das die Antwort vor der Handlung brauchte, verliert sie: eine „In anderer App öffnen”-Zeile nur dann anzeigen, wenn die App da ist; ein Share Sheet danach sortieren, was installiert ist; unter konkurrierenden Zielen einen Standard auswählen.12
Auch Apples eigene Dokumentation hat noch nicht nachgezogen. Die Seite zu open(_:options:completionHandler:) weist weiterhin an: „To determine whether an app is installed that is capable of handling the URL, call the canOpenURL(_:) method before calling this one.”12 Die Seite des Ersatzes empfiehlt die veraltete Methode.
Die Anwesenheitsprüfung, die bleibt
Ein dokumentierter Weg beantwortet die Frage von canOpenURL durch einen Versuch, ohne dass für den Benutzer etwas sichtbar wird, wenn die Antwort Nein lautet. UIApplication.OpenExternalURLOptionsKey.universalLinksOnly existiert seit iOS 10, Apple hat es nicht abgekündigt, und das Verhalten ist exakt eine Anwesenheitsprüfung: „the method opens the URL only if the URL is a valid universal link and there is an installed app capable of opening that URL.”3
// Presence check with no side effect when the app is absent.
let url = URL(string: "https://myphotoapp.example.com/albums?albumname=vacation")!
let installed = await UIApplication.shared.open(
url,
options: [.universalLinksOnly: true]
)
if !installed {
presentWebFallback() // nothing opened, nothing switched
}
Der wertvolle Teil ist der false-Zweig. Kein Browser startete, keine App trat hervor, und der Aufrufer erfuhr, was canOpenURL ihm früher sagte. Der Haken steckt im Namen der Option: Ohne sie gelingt ein https-Versuch immer dann, wenn irgendein Browser ihn annehmen kann, denn „if no app is available to handle a universal link, iOS routes it to the person’s default browser, allowing the associated website to respond.”2 Die Option erkauft einen aussagekräftigen Boolean, indem sie genau den Rückfallweg unterdrückt, der Universal Links angenehm macht. Apple typisiert den Wert als „an NSNumber object containing a Boolean value”, was ein Swift-true über die Objective-C-Brücke erfüllt.3
Der Preis ist architektonisch, und er steht in Apples drittem Satz. Universal Links brauchen eine beidseitige Zuordnung: „When someone installs your app, the system checks a file stored on your web server to verify that your website allows your app to open URLs on its behalf. Only you can store this file on your server, securing the association of your website and your app.”13 Eine Datei auf einem Server, den Sie kontrollieren, ist genau das, was ein eigenes Scheme nie verlangte – weshalb die Migration für die eigene App-Familie funktioniert und bei einem Dritten, der ausschließlich theirapp:// veröffentlicht, nichts ausrichtet. Zwei dokumentierte Überraschungen kommen obendrein hinzu: Öffnet Ihre App einen eigenen Universal Link, landet der nicht in Ihrer App, und ein Tipp auf dieselbe Domain, während der Nutzer Ihre Website in Safari besucht, bleibt in Safari.13
Und da landet der dritte Teilsatz von vorhin: canOpenURL hat die Anwesenheitsfrage für einen Universal Link ebenfalls nie beantwortet.2 Die Migration entfernt die Anwesenheitserkennung also, statt sie zu portieren, denn ein schlichter https-Versuch gelingt bereits, ob nun die App geantwortet hat oder nur die Website. Ein Muster, das nur funktionierte, weil eigene Schemes den Installationsstatus preisgaben, verschwindet mit den Schemes – und Apples Release Note rahmt genau diesen Verlust als Grund zur Migration.
SwiftUI hatte die Methode nie
Die SwiftUI-Seite ist kurz, und die Nachricht ist gut. EnvironmentValues.openURL, OpenURLAction und Link sind sämtlich ab iOS 14.0 verfügbar und nicht abgekündigt, und keines der drei bietet eine Gültigkeitsprüfung.4514
Was SwiftUI stattdessen ausliefert, ist Versuchen-und-behandeln mit genau der Semantik, die Apple nun überall haben will, und die Dokumentation des Completion-Parameters sagt, dass der Boolean die alte Frage beantwortet: „A closure the method calls after determining if it can open the URL, but possibly before fully opening the URL. The closure takes a Boolean value that indicates whether the method can open the URL.”15 Kann öffnen, nicht hat geöffnet. Apples eigenes Beispiel gibt es aus:
openURL(url) { accepted in
print(accepted ? "Success" : "Failure")
}
Link gibt überhaupt keinen Boolean preis und überlässt die Sache der Umgebung, wo der Standard die Universal-Link-Geschichte bereits umsetzt: „the default action opens a Universal Link in the associated app if possible, or in the user’s default web browser if not.”5 Eine eigene OpenURLAction, die .handled, .discarded oder .systemAction zurückgibt, fängt jedes Link ab und jeden Markdown-Link in einem Text, der die Aktion aus dieser Umgebung liest.5
Eine Lücke sollten Sie kennen, bevor Sie eine reine SwiftUI-Migration planen. OpenURLAction hat kein Options-Dictionary. Seine Aufrufsignaturen sind callAsFunction(_:), callAsFunction(_:completion:) und die mit iOS 26 hinzugekommene callAsFunction(_:prefersInApp:), und keine der drei nimmt universalLinksOnly entgegen.1518 Eine nebenwirkungsfreie Anwesenheitsprüfung heißt also weiterhin: UIApplication.shared.open aufrufen.
Sieben Apps, 463 Dateien, null Aufrufe
Ich habe mein eigenes Portfolio geprüft, bevor ich über fremdes schreibe – in Erwartung einer Migrationsliste. Es gibt nichts zu migrieren.6
| App | Swift-Dateien | canOpenURL |
LSApplicationQueriesSchemes |
Aufrufstellen zum URL-Öffnen |
|---|---|---|---|---|
| Reps | 77 | 0 | 0 | 5 |
| Return | 57 | 0 | 0 | 2 |
| Banana List | 55 | 0 | 0 | 2 |
| Ace Citizenship | 26 | 0 | 0 | 2 |
| Water | 34 | 0 | 0 | 0 |
| ResumeGeni | 71 | 0 | 0 | 12 |
| Yawara | 143 | 0 | 0 | 0 |
| Gesamt | 463 | 0 | 0 | 23 |
Die Null hielt drei Durchgängen mit wachsendem Suchraum stand, bis hinaus zu jedem mitgelieferten Swift-Package und jedem Dateityp in jedem Repository.6 Auch in 192 .plist-, .pbxproj-, .entitlements- und .xcconfig-Dateien deklariert nichts ein abgefragtes Scheme, was folgerichtig ist: Eine App ohne canOpenURL-Aufruf hat keinen Anlass, eines zu deklarieren.
Der Grund ist banal und vermutlich verbreitet. Von den 23 Aufrufstellen öffnen neun ein Rechtsdokument, vier übergeben an das eigene Webprodukt der App, zwei öffnen census.gov aus einem Hinweisdialog, damit ein Nutzer seinen Abgeordneten findet, zwei öffnen die URL einer Stellenanzeige, die von einer API kommt, zwei sind reine macOS-file:-Exporte und einer ist UIApplication.openSettingsURLString hinter einem Hinweis „Health Access Required”. Keine dieser 20 fragt eine andere App ab, denn jedes Ziel ist entweder https, was Safari stets beantwortet, oder eine System-URL. Die verbleibenden drei tragen das gesamte interessante Verhalten.
Die eine Stelle, die vor dem Öffnen validiert, tut nicht das, worum es bei der Abkündigung geht: Der Abrechnungsablauf von ResumeGeni schickt ein POST an /api/me/portal und prüft dann url.scheme == "https" an der vom Server zurückgegebenen URL – für den Fall, dass ein kompromittierter oder fehlerhafter Server der App eine file:- oder Custom-Scheme-URL unterschiebt.6 Apples Hinweis zielt auf die Prüfung, ob eine Ziel-App existiert, und sagt nichts über das Vertrauen in entfernte Eingaben; diese Absicherung zu löschen wäre also eine Sicherheitsregression, keine Migration.
Die anderen beiden sind die macOS-Übergaben von Banana List, und eine davon enthält die einzige echte Anwesenheitsprüfung des Portfolios. Die App fragt NSWorkspace.shared.urlForApplication(withBundleIdentifier: "com.anthropic.claudefordesktop") != nil, bevor sie eine mitgelieferte .mcpb-Erweiterung an Launch Services übergibt; ein Button daneben öffnet claude.com/download für alle, die die App zuerst brauchen. Der Kommentar im Code benennt das Motiv: Ohne die Prüfung zeigt macOS seinen eigenen Dialog „no application set to open the document”.6 Andere Plattform – und der nützlichste Datenpunkt der ganzen Prüfung, denn er fängt den Fehlermodus von Versuchen-und-behandeln im Feld ein. Ein fehlgeschlagener Versuch ist nicht immer stumm, und wenn das System für Sie spricht, liest der Nutzer eine Systemfehlermeldung statt Ihres Rückfallwegs.
Kein Repository deklariert applinks:, keine App hier unterstützt also Universal Links, und den Preis für Apples architektonische Lösung habe auch ich nicht bezahlt.6 Ein eigenes Scheme kostet einen Info.plist-Eintrag; ein Universal Link kostet eine Datei auf einem Webserver, ein Entitlement und eine Domain, die Ihnen gehört.
Womit klar wird, wo die eigentliche Arbeit liegt: nicht im eigenen App-Code, sondern in Share Sheets, die nach installierten Apps umsortieren, in „Öffnen in”-Auswahllisten und in Attributions-SDKs – nichts davon schließt ein sauberes Repository aus.
Die Prüfung selbst fällt hier leichter als anderswo im 27er-Zyklus. Anders als die Launch-Screen-Keys, die aus Build Settings stammen und eine Textsuche vollständig ins Leere laufen lassen, hat LSApplicationQueriesSchemes in Apples Build-Settings-Referenz kein INFOPLIST_KEY_-Gegenstück; ein grep ist also der richtige erste Zug, und wessen Schemes in diesem Array auftauchen, verrät Ihnen, welche Abhängigkeit die Antwort haben will.16
FAQ
Hört canOpenURL unter iOS 27 auf zu funktionieren?
Nein, und Apple hat nicht gesagt, wann es so weit ist. Das Symbol trägt deprecatedAt 27.0, und jeder andere Teil der Seite bleibt dokumentiert – der Rückgabewert-Vertrag, die Garantie für den folgenden open-Aufruf, die Deklarationsgrenze und das Aufrufkontingent für Altfälle.2 Weder in der Release Note noch auf der Symbolseite noch in den Xcode-27-Release-Notes taucht eine Entfernungsversion auf.129 Rechnen Sie mit einer Warnung und langsamem Verfall, nicht mit einem Bruch.
Was schreibe ich stattdessen, wenn ich wissen muss, ob die App installiert ist?
Das hängt davon ab, ob Ihnen das Ziel gehört. Wenn ja, veröffentlichen Sie einen Universal Link und übergeben Sie universalLinksOnly an open; Apple dokumentiert das so, dass die URL nur geöffnet wird, wenn sie ein gültiger Universal Link ist und eine installierte App sie annehmen kann – ein false bedeutet also: Nichts wurde geöffnet, nichts gewechselt.3 Der Preis ist eine Datei zur beidseitigen Zuordnung auf Ihrem Webserver.13 Veröffentlicht ein Dritter nur ein eigenes Scheme, existiert kein Ersatz: canOpenURL antwortet weiterhin, braucht weiterhin seine Info.plist-Deklaration, und die Obergrenze dieser Deklaration halbiert sich für Apps, die ab iOS 27 gelinkt werden, auf 25 Einträge.2 SwiftUI-Code braucht an dieser Front keine Änderung, denn openURL und Link haben die Prüfung nie angeboten.414
Brauche ich LSApplicationQueriesSchemes weiterhin?
Nur für canOpenURL. Apples Launch-Services-Dokumentation definiert den Key vollständig über die veraltete Methode: Er „specifies the URL schemes you want the app to be able to use with the canOpenURL: method of the UIApplication class.”17 In Apples moderner Information-Property-List-Referenz hat der Key überhaupt keine Seite, und die Beschreibung der veralteten Methode verlinkt dafür ins Archiv.217 Der Ersatz braucht nichts, weil Apple open von der Deklarationspflicht rundheraus ausnimmt.2 Migrieren Sie vollständig, und das Array verschwindet; behalten Sie einen Aufruf, behalten Sie das Array, die Deklarationspflicht und die kleinere Obergrenze.
Lehnt der App Store einen Build mit mehr als 25 Einträgen ab?
Keine Apple-Seite sagt das. Die Obergrenze erscheint an genau einer Stelle, in der Beschreibung von canOpenURL(_:), und Apple formuliert sie als Grenze dessen, was der Key aufnimmt, nicht als Einreichungsregel.2 Weder die iOS-27-Release-Notes noch die UIKit-Updates-Seite noch die Xcode-27-Release-Notes knüpfen daran eine Prüfkonsequenz, und das dokumentierte Symptom für ein Scheme, das das System als nicht deklariert behandelt, ist ein schlichtes false zur Laufzeit.1289 In den App Store Review Guidelines kommen weder LSApplicationQueriesSchemes noch canOpenURL noch die Zahl 25 vor – und dort stünde eine Einreichungsregel, wenn es sie gäbe.19 Vorsorgen sollten Sie also gegen eine falsche Antwort im eigenen Code, nicht gegen einen abgelehnten Build.
Das Wichtigste in Kürze
Für iOS-Entwickler:
- Ersetzen Sie if canOpenURL(url) { open(url) } durch let opened = await open(url) mit einem Rückfallweg auf !opened, und löschen Sie den zugehörigen LSApplicationQueriesSchemes-Eintrag, sobald kein Aufruf mehr übrig ist.2
- Behalten Sie jede Scheme-Prüfung, die Sie auf eine vom Server kommende URL anwenden. Apples Hinweis zielt auf die Prüfung der App-Anwesenheit, nicht auf entfernte Eingaben – und im grep sehen beide gleich aus.
Für Teams, die Deep Links innerhalb einer App-Familie oder SDKs ausliefern:
- Greifen Sie zu universalLinksOnly statt zu canOpenURL, wenn Sie eine Anwesenheitsantwort brauchen, und kalkulieren Sie die dafür nötige Associated-Domains-Datei ein.313 Es ist die einzige dokumentierte Prüfung, die nichts für den Benutzer Sichtbares hinterlässt, wenn die App fehlt.
- Zählen Sie Ihr LSApplicationQueriesSchemes-Array, bevor Sie gegen das iOS-27-SDK linken. Alles jenseits von 25 Einträgen liegt außerhalb der dokumentierten Obergrenze, und Apples Symptom für ein nicht deklariertes Scheme ist ein schlichtes false – exakt so, wie sich eine nicht installierte App liest.2
Für Release-Verantwortliche:
- Planen Sie die Abkündigung nicht als Release-Blocker ein. Keine Entfernungsfrist und keine Konsequenz zur Laufzeit setzen sie hinter den Launch-Screen-Key, der eine Ablehnung kostet, hinter die Scene-Vorgabe, die Starts verhindert, und hinter das @State-Makro, das einen Build stoppt.
- Behandeln Sie die 25-Einträge-Grenze als den einen Punkt mit einem echten Auslöser, denn sie hängt am SDK, gegen das Sie linken, nicht am Betriebssystem, das Ihre Nutzer verwenden.2
Der 27er-Zyklus kommt in unterschiedlichen Gewichtsklassen daher, und dieses Gewicht zu lesen ist die Art, den Zyklus gut zu nutzen: Der Launch-Screen-Key blockiert eine Einreichung, die Scene-Vorgabe verhindert den App-Start, das @State-Makro stoppt einen Build, On Demand Resources startet eine Migrationsuhr, und canOpenURL warnt bloß. Um die Warnung herum Dringlichkeit zu fabrizieren, verschwendet einen Zyklus. Die Zeile, die Beachtung verdient, steht in einem Beschreibungsabsatz statt in einer Release Note – und sie ist eine Zahl. Der vollständige Serien-Hub ist die Apple-Ökosystem-Serie.
Quellen
-
Apple, iOS & iPadOS 27 Release Notes, Abschnitt UIKit, Deprecations (Radar 179874781). Die Seite betitelte sich beim Abruf selbst als „iOS & iPadOS 27 Beta 4 Release Notes”, ebenso wie jede andere in diesem Artikel zitierte Release-Note-Seite; behandeln Sie sämtliche Formulierungen aus Release Notes hier daher als vorläufig – die Verfügbarkeits-Metadaten der Symbolseiten sind die haltbarere Aktenlage. Quelle des hier vollständig zitierten Eintrags: „
canOpenURL:is deprecated. Attempt to open the URL and handle any failure instead of validating it first. Using universal links instead of custom URL schemes removes the need for this validation entirely.” Der Eintrag folgt unmittelbar auf den Eintrag zum Scene-Lebenszyklus (Radar 141837548), „Apps built with the latest SDK must adopt the scene-based life cycle or they fail to launch.” Am 26. Juli 2026 gegen Apples Dokumentations-JSON verifiziert, weil die HTML-Seite über JavaScript gerendert wird. Dasselbe JSON enthält genau ein Vorkommen voncanOpenURLund eines von Radar 179874781. Die Release Notes zu tvOS 27, visionOS 27, watchOS 27 und macOS 27 wurden am selben Tag abgerufen, betitelt als „tvOS 27 Beta 4”, „visionOS 27 Beta 4”, „watchOS 27 Beta 4” und „macOS 27 Golden Gate Beta 4”, und enthalten null Vorkommen beider Zeichenfolgen. ↩↩↩↩↩↩ -
Apple, canOpenURL(_:), Referenz der UIKit-Instanzmethode. Deklariert als
nonisolated func canOpenURL(_ url: URL) -> Bool, eingeführt mit iOS 3.0 (Mac Catalyst 13.1, tvOS 9.0, visionOS 1.0) und mitdeprecatedAt27.0 auf iOS, iPadOS, Mac Catalyst, tvOS und visionOS markiert, jeweils mit dem Verfügbarkeitshinweis „Prefer attempting to open URLs and handling any failures.” Die Abkündigungszusammenfassung der Seite wiederholt zwei der drei Sätze der Release Note wörtlich: „Attempt to open the URL and handle any failure instead of validating it first. Using universal links instead of custom URL schemes removes the need for this validation entirely.” Quelle der Dokumentation zum Rückgabewert („falseif the device doesn’t have an installed app registered to handle the URL’s scheme, or if you haven’t declared the URL’s scheme in yourInfo.plistfile; otherwise,true”), der Garantie („When this method returnstrue, iOS guarantees subsequent calls to theopen(_:options:completionHandler:)method with the same URL will successfully launch an app that can handle the URL. The return value doesn’t indicate the validity of the URL, whether the specified resource exists, or, in the case of a universal link, whether the device has an installed app registered to respond to the universal link”), des Threading-Hinweises („You can call this method safely on a thread that isn’t the main thread”), der hier zitierten Randbemerkung zur Positivliste samt beider Obergrenzen („Apps linked on or after iOS 15 are limited to a maximum of 50 entries in theLSApplicationQueriesSchemeskey. Apps linked on or after iOS 27 are limited to a maximum of 25 entries in theLSApplicationQueriesSchemeskey”), des hier zitierten Laufzeit-Aufrufkontingents („If you link your app against an earlier version of iOS but it is running in iOS 9.0 or later, you can call this method up to 50 times. After reaching that limit, subsequent calls always returnfalse. If the user reinstalls or upgrades the app, iOS resets the limit”), der Ausnahme („Unlike this method, theopen(_:options:completionHandler:)method isn’t constrained by theLSApplicationQueriesSchemesrequirement. If an app is available to handle the URL, the system will launch it, even if you haven’t declared the scheme”) sowie des Universal-Link-Rückfallwegs („if no app is available to handle a universal link, iOS routes it to the person’s default browser, allowing the associated website to respond”). Ein Satz der Randbemerkung liest sich in der veröffentlichten Fassung schief: „This method always returnsfalsefor undeclared schemes, even if the device doesn’t have a registered app installed.” Die Aussage dieses Artikels über mehrdeutigefalse-Werte stützt sich auf den Abschnitt zum Rückgabewert, nicht auf jenen Satz. Am 26. Juli 2026 gegen Apples Dokumentations-JSON verifiziert. ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩ -
Apple, UIApplication.OpenExternalURLOptionsKey.universalLinksOnly, Referenz der UIKit-Typeigenschaft. Verfügbar seit iOS 10.0 (Mac Catalyst 13.1, tvOS 10.0, visionOS 1.0), ohne Abkündigungs-Metadaten mit Stand 26. Juli 2026. Quelle der Kurzbeschreibung („URLs must be universal links and have an app configured to open them”) und der hier zitierten Beschreibung: „When you include this key in the options dictionary of the
open(_:options:completionHandler:)method, the method opens the URL only if the URL is a valid universal link and there is an installed app capable of opening that URL. The value of this key is anNSNumberobject containing a Boolean value.” ↩↩↩↩↩ -
Apple, EnvironmentValues.openURL, Referenz der SwiftUI-Instanzeigenschaft. Deklariert als
@MainActor @preconcurrency var openURL: OpenURLAction, verfügbar ab iOS 14.0, iPadOS 14.0, Mac Catalyst 14.0, macOS 11.0, tvOS 14.0, visionOS 1.0 und watchOS 7.0, ohne Abkündigungs-Metadaten mit Stand 26. Juli 2026. Quelle des hier wiedergegebenen BeispielsopenURL(url) { accepted in ... }und der in diesem Artikel zitierten Beschreibung der Standardaktion. ↩↩↩ -
Apple, OpenURLAction, Referenz der SwiftUI-Struktur. Deklariert als
@MainActor @preconcurrency struct OpenURLAction, verfügbar ab iOS 14.0, ohne Abkündigungs-Metadaten. Quelle von „The system provides a default open URL action with behavior that depends on the contents of the URL. For example, the default action opens a Universal Link in the associated app if possible, or in the user’s default web browser if not” sowie der Aussage, dass eine eigene Aktion für „the built-inLinkview andTextviews with markdown links, or links in attributed strings” gilt. Die in diesem Artikel genanntenResult-Mitglieder stammen von der Unterseite Apple, OpenURLAction.Result, diehandled,discarded,systemAction,systemAction(_:)und die mit iOS 26 hinzugekommene TypmethodesystemAction(_:prefersInApp:)aufführt. ↩↩↩ -
Erhebung des Autors über sieben ausgelieferte Apple-Plattform-Projekte (Reps, Return, Banana List, Ace Citizenship, Water, ResumeGeni und Yawara) unter macOS 26.5.2 am 26. Juli 2026, mit ripgrep über eigenen Swift-Code, unter Ausschluss von
build/,DerivedData/,.build/,Pods/,Carthage/,.swiftpm/,SourcePackages/undcheckouts/der Packages. Die Dateiabdeckung wurde je Repository perfindgegenrgabgeglichen (77, 57, 55, 26, 34, 71 und 143 Dateien), um sicherzustellen, dass kein per gitignore ausgeblendeter eigener Swift-Code übersprungen wurde. Die Null beicanOpenURLwurde auf drei Wegen verifiziert: eigener Swift-Code; Swift mit--no-ignore --hidden, was Build-Artefakte und jedes mitgelieferte Package-Checkout einschließt (3.946 Swift-Dateien im ResumeGeni-Baum, 15.760 im gemeinsamen 941Kit-Baum); und alle Dateitypen mit--no-ignore. In jedem Durchgang null, einschließlich Fremd- und mitgeliefertem Code.LSApplicationQueriesSchemesundINFOPLIST_KEY_LSApplicationQueriesSchemeslieferten null über 192.plist-,.pbxproj-,.entitlements- und.xcconfig-Dateien. Die 23 Aufrufstellen setzen sich zusammen aus sechs SwiftUI-Link-Views, dreiUIApplication.shared.open-Aufrufen, 12openURL(...)-Aufrufen (alle in ResumeGeni, aus sechs@Environment(\.openURL)-Deklarationen) und zweiNSWorkspace.shared.open-Aufrufen im macOS-Code von Banana List; die Zählung vonLink(erfordert eine Wortgrenze, da ein bloßes Muster auchNavigationLink(und mehrere projektspezifische...Link(-Typen trifft. In keinem Projekt existierenSFSafariViewController- oderWKWebView-Verwendungen, und kein Repository deklariertapplinks:. Die Abrechnungsabsicherung von ResumeGeni steht inProfile/ProfileView.swift:1746; die Anwesenheitsprüfung von Banana List und der erläuternde Kommentar stehen inBanana List/SettingsView.swift:321und:329, und die in diesem Artikel zitierte Formulierung „no application set to open the document” ist der Wortlaut jenes Quellcode-Kommentars und keine Abschrift des macOS-Dialogs; der Settings-Deep-Link von Return steht inReturn/ContentView.swift:222. Das Haupt-App-Target von Reps deklariertSUPPORTED_PLATFORMS = "appletvos appletvsimulator iphoneos iphonesimulator macosx"; keine Plattformaussage in diesem Artikel leitet sich aus einem*_DEPLOYMENT_TARGET-Key ab, und die vollständige Plattformreichweite keiner App wird ausSUPPORTED_PLATFORMSerschlossen, das ohnehin nur 40 von 80 Build-Konfigurationen in diesen Projekten überhaupt setzen. ↩↩↩↩↩↩ -
Apple, openURL(_:), Referenz der UIKit-Instanzmethode. Deklariert als
func openURL(_ url: URL) -> Bool, eingeführt mit iOS 2.0 und abgekündigt mit iOS 10.0 (Mac Catalyst 13.1). Quelle des aktuellen Abkündigungshinweises: „Calling this method has no effect. Use theopen(_:options:completionHandler:)method instead.” Geprüft am 26. Juli 2026. ↩ -
Apple, UIKit updates, Apple Developer Documentation. Der Abschnitt Juni 2026 umfasst vier Unterabschnitte (General, App life cycle, Drag and drop und Text views) und enthält unter App life cycle die Vorgabe zum Scene-Lebenszyklus: „Starting in iOS 27, apps built with the latest SDK must use the scene-based life cycle or they fail to launch.” Am 26. Juli 2026 nach
canOpenURLundLSApplicationQueriesSchemesdurchsucht; keines von beiden erscheint irgendwo auf der Seite. ↩↩ -
Apple, Xcode 27 Release Notes. Am 26. Juli 2026 nach
canOpenURL,LSApplicationQueriesSchemesund Radar 179874781 durchsucht; nichts davon erscheint. ↩↩↩ -
Apple, Describing use of required reason API, Bundle-Resources-Dokumentation. Quelle der hier zitierten Fingerprinting-Definition Apples: „Some APIs that your app uses to deliver its core functionality… have the potential of being misused to access device signals to try to identify the device or user, also known as fingerprinting. Regardless of whether a user gives your app permission to track, fingerprinting is not allowed.” Durchsucht am 26. Juli 2026:
canOpenURLundLSApplicationQueriesSchemeserscheinen nicht auf der Seite, worauf sich die hiesige Aussage stützt, dass Apple die Methode nirgends mit Fingerprinting in Verbindung bringt. Die Seite beschreibt die Meldepflicht und verweist für die Kategorienliste auf die Dokumentation zuNSPrivacyAccessedAPIType. Die Datenschutzlesart der Abkündigung in diesem Artikel ist die Schlussfolgerung des Autors, nicht Apples erklärte Begründung. ↩↩ -
Apple, UIApplication, Referenz der UIKit-Klasse. Deklariert als
@MainActor class UIApplication, verfügbar ab iOS 2.0, ohne Abkündigungs-Metadaten. Quelle der Main-Actor-Isolation, dieopen(_:options:completionHandler:)erbt und von der sichcanOpenURL(_:)mitnonisolatedausnimmt. ↩ -
Apple, open(_:options:completionHandler:), Referenz der UIKit-Instanzmethode. Verfügbar ab iOS 10.0, ohne Abkündigungs-Metadaten, deklariert sowohl in der Completion-Handler- als auch in der
async-Form:func open(_ url: URL, options: [UIApplication.OpenExternalURLOptionsKey : Any] = [:], completionHandler completion: (@MainActor @Sendable (Bool) -> Void)? = nil)undfunc open(_ url: URL, options: [UIApplication.OpenExternalURLOptionsKey : Any] = [:]) async -> Bool. Quelle der Kurzbeschreibung („Attempts to asynchronously open the resource at the specified URL”), des hier zitierten Startverhaltens („If the specified URL scheme is handled by another app, iOS launches that app and passes the URL to it. (Launching the app brings the other app to the foreground.) If no app is capable of handling the specified scheme, the completion handler is called with the success parameter set tofalse”) sowie der Anweisung, die weiterhin die veraltete Methode empfiehlt: „To determine whether an app is installed that is capable of handling the URL, call thecanOpenURL(_:)method before calling this one. Be sure to read the description of that method for an important note about registering the schemes you want to employ.” Geprüft am 26. Juli 2026. ↩↩↩↩ -
Apple, Allowing apps and websites to link to your content, Xcode-Dokumentation. Quelle der serverseitigen Zuordnungspflicht („When someone installs your app, the system checks a file stored on your web server to verify that your website allows your app to open URLs on its behalf. Only you can store this file on your server, securing the association of your website and your app”), des Browser-Rückfallwegs („If the person hasn’t installed your app, the system opens the URL in their default web browser, allowing your website to handle it”), des Hinweises, dass eine App beim Öffnen eines eigenen Universal Links nicht zu sich selbst geleitet wird („If your app uses one of the above methods to open a universal link to your website, the link won’t open in your app”), sowie des hier beschriebenen Safari-Verhaltens bei identischer Domain. Die Seite führt SwiftUIs
EnvironmentValues.openURLund UIKitsopen(_:options:completionHandler:)unter den Aufrufen auf, die Universal Links weiterleiten. ↩↩↩↩ -
Apple, Link, Referenz der SwiftUI-Struktur. Deklariert als
@MainActor @preconcurrency struct Link<Label> where Label : View, verfügbar ab iOS 14.0, macOS 11.0 und watchOS 7.0, ohne Abkündigungs-Metadaten. Quelle des hier zitierten Standardverhaltens: „When a user taps or clicks aLink, the default behavior depends on the contents of the URL. For example, SwiftUI opens a Universal Link in the associated app if possible, or in the user’s default web browser if not.” ↩↩ -
Apple, OpenURLAction.callAsFunction(_:completion:), Referenz der SwiftUI-Instanzmethode. Deklariert als
@MainActor @preconcurrency func callAsFunction(_ url: URL, completion: @escaping (Bool) -> Void). Quelle der hier zitierten Completion-Semantik: „A closure the method calls after determining if it can open the URL, but possibly before fully opening the URL. The closure takes a Boolean value that indicates whether the method can open the URL.” Die verwandte SignaturcallAsFunction(_:)nimmt allein eine URL entgegen. Geprüft am 26. Juli 2026. ↩↩↩ -
Apple, Build settings reference, Xcode-Dokumentation. Am 26. Juli 2026 nach
INFOPLIST_KEY_LSApplicationQueriesSchemesdurchsucht: Die Einstellung erscheint nicht, währendINFOPLIST_KEY_LSApplicationCategoryType,INFOPLIST_KEY_LSBackgroundOnly,INFOPLIST_KEY_LSSupportsOpeningDocumentsInPlaceundINFOPLIST_KEY_LSUIElementvorhanden sind. Ein Build-Schritt, der eine eigene Property List einmischt, kann den Key dennoch einschleusen; die Abwesenheit macht eine Repository-Suche daher zum richtigen ersten Zug, nicht zu einer vollständigen Prüfung. ↩ -
Apple, Launch Services Keys, Information Property List Key Reference (Apple-Archiv). Quelle der Definition des Keys: „
LSApplicationQueriesSchemes(Array - iOS) Specifies the URL schemes you want the app to be able to use with thecanOpenURL:method of theUIApplicationclass. For each URL scheme you want your app to use with thecanOpenURL:method, add it as a string in this array.” Die Seite hält fest, der Key werde „in iOS 9.0 and later” unterstützt, und nennt keine Obergrenze für Einträge. Das Archiv ist das Ziel des Links innerhalb der Beschreibung voncanOpenURL(_:)selbst. In Apples aktueller Information Property List Reference hat der Key keine Seite, verifiziert am 26. Juli 2026:documentation/bundleresources/information-property-list/lsapplicationqueriesschemes.jsonliefert HTTP 404, während benachbarteLS*-Key-Seiten wielsapplicationcategorytypeundlsbackgroundonly200 liefern. Das eigene Index-JSON der Referenz taugt ebenfalls in keine Richtung als Test, da es nur sieben Schlüsselgruppen der obersten Ebene aufzählt und keinen einzelnenLS*-Key nennt;lsapplicationcategorytype, das eine aktive Seite hat, fehlt dort gleichermaßen. ↩↩ -
Apple, OpenURLAction.callAsFunction(_:prefersInApp:), Referenz der SwiftUI-Instanzmethode. Deklariert als
@MainActor @preconcurrency func callAsFunction(_ url: URL, prefersInApp: Bool), verfügbar ab iOS 26.0, iPadOS 26.0, Mac Catalyst 26.0, macOS 26.0, tvOS 26.0, visionOS 26.0 und watchOS 26.0. Auf derOpenURLAction-Seite unter Instance Methods gelistet statt unter Calling the action. Sie nimmt einen einzelnen Boolean entgegen statt eines Options-Dictionary, ist damit die dritte und letzte Aufrufsignatur, und keine der drei nimmtuniversalLinksOnlyentgegen. Geprüft am 26. Juli 2026. ↩ -
Apple, App Store Review Guidelines. Am 26. Juli 2026 nach
LSApplicationQueriesSchemes,canOpenURLund „25 entries” durchsucht: jeweils null Vorkommen. Zitiert zur Stützung der Abwesenheit einer Einreichungsregel, nicht für eine positive Behauptung. ↩