Quand on commence à creuser le sujet des Associated Domains sur iOS, on se rend vite compte que le terme recouvre en réalité plusieurs mécanismes très différents. Sous un même entitlement et un même fichier de configuration se cachent cinq services distincts, qui répondent à cinq problèmes distincts. Les confondre est une source classique de bugs, et c'est aussi la raison pour laquelle beaucoup de développeurs iOS n'implémentent qu'une petite partie de ce qu'ils pourraient faire.
Cet article vise à clarifier tout ça. On va commencer par comprendre le mécanisme commun qui relie ton app à un domaine web, puis on détaillera chacun des cinq services, avec pour chacun un exemple concret d'implémentation. On finira par une checklist de debug qui te fera gagner plusieurs heures la prochaine fois qu'un Universal Link refusera obstinément de s'ouvrir dans ton app.
Tout l'article utilise un exemple fictif : une application MonApp dont le domaine web est monapp.fr, le bundle identifier com.monentreprise.monapp, et le Team ID ABCDE12345. Remplace ces valeurs par les tiennes quand tu passeras à la pratique.
1. Le mécanisme sous-jacent
Avant de parler des services eux-mêmes, il faut comprendre comment iOS établit le lien entre ton application et un domaine web. Ce lien repose sur un fichier statique appelé apple-app-site-association, qu'on abrégera souvent AASA dans la suite de l'article.
Quand tu installes ton app sur un appareil, iOS regarde ses entitlements et y trouve une liste de domaines associés. Pour chaque domaine, le système va télécharger le fichier AASA et vérifier qu'il contient bien une déclaration autorisant ton app. Sans cette vérification croisée, n'importe quelle application pourrait prétendre gérer les URLs de n'importe quel site, ce qui serait catastrophique en termes de sécurité. Le mécanisme garantit donc qu'une app ne peut intercepter les liens d'un domaine que si le propriétaire de ce domaine l'a explicitement autorisé.
Le fichier AASA doit être servi à l'URL https://tondomaine.fr/.well-known/apple-app-site-association, sans extension .json, en HTTPS uniquement, sans redirection, avec le Content-Type application/json. Ces contraintes peuvent sembler arbitraires mais chacune a sa raison d'être, et on verra plus loin les pièges concrets qu'elles cachent.
Point important à connaître dès maintenant : iOS ne télécharge pas le fichier AASA directement depuis ton serveur. Le système passe par un CDN (Un CDN (Content Delivery Network) est un réseau de serveurs répartis géographiquement qui mettent en cache des fichiers pour les servir plus rapidement aux utilisateurs finaux.) intermédiaire géré par Apple, accessible à l'URL https://app-site-association.cdn-apple.com/a/v1/tondomaine.fr. Ce CDN interroge ton serveur, met le fichier en cache, et sert ensuite cette version cachée à tous les appareils iOS de la planète. La conséquence pratique est qu'une modification de ton AASA peut mettre jusqu'à 24 heures à se propager. Ce point à lui seul explique une bonne partie des galères de debug que rencontrent les développeurs iOS quand ils mettent en place leurs Universal Links pour la première fois.
À retenir : ton AASA est lue une seule fois par Apple, pas par chaque appareil. Si tu modifies le fichier et que ça ne marche pas immédiatement, ce n'est pas forcément toi qui as fait une erreur, c'est peut-être juste le CDN qui n'a pas encore rafraîchi son cache. On verra comment contourner ça avec le mode développeur.
Passons maintenant aux cinq services qui s'appuient sur ce mécanisme.
2. applinks: les Universal Links
Les Universal Links sont de loin le service le plus connu et le plus utilisé. Ils permettent qu'un lien HTTPS classique, par exemple https://monapp.fr/produit/42, ouvre directement ton application si elle est installée sur l'appareil, au lieu d'ouvrir Safari. Si l'app n'est pas installée, le lien s'ouvre normalement dans le navigateur, qui peut alors afficher une page invitant à télécharger l'app.
Cette bascule se fait sans que l'utilisateur s'en rende compte. Le lien fonctionne partout : dans Messages, dans Mail, dans Slack, dans n'importe quelle notification push, ou même quand il est tapé à la main dans la barre d'adresse. C'est ce qui le distingue d'un scheme custom comme monapp://produit/42, qui ne fonctionne que si l'émetteur du lien connaît à l'avance le scheme de ton app, ce qui est rarement le cas en dehors de tes propres notifications.
Mise en place
L'implémentation se fait en trois étapes : déclarer le domaine dans les entitlements de ton app, déposer le fichier AASA sur le serveur web, et intercepter les URLs dans le code Swift.
Côté app, tu ajoutes l'entitlement com.apple.developer.associated-domains avec l'entrée applinks:monapp.fr. La configuration se fait en quatre étapes dans Xcode :

Sélectionne ton projet dans le navigateur de fichiers, puis ton target applicatif dans le panneau central.
Va dans l'onglet Signing & Capabilities.
Clique sur le bouton + Capability en haut à gauche, puis double-clique sur Associated Domains dans la liste qui s'affiche.
Une section Associated Domains apparaît avec un champ Domains. Clique sur le + pour ajouter une ligne, et saisis
applinks:monapp.fr(attention, bien inclure le préfixeapplinks:et pas seulement le nom de domaine).
Xcode génère automatiquement un fichier MonApp.entitlements dans ton projet et l'associe à la build config via la clé CODE_SIGN_ENTITLEMENTS. Son contenu ressemble à ceci :
<key>com.apple.developer.associated-domains</key>
<array>
<string>applinks:monapp.fr</string>
</array>Une fois la capability ajoutée, vérifie que ton App ID sur le portail développeur Apple a bien activé Associated Domains dans la liste des services. En mode Automatic signing, Xcode s'en occupe seul, mais en signing manuel il faut régénérer le provisioning profile après cet ajout, sinon l'entitlement ne sera pas signé correctement et iOS ignorera silencieusement ta configuration.
Côté serveur, tu déposes un fichier nommé apple-app-site-association (sans extension) à l'emplacement /.well-known/ de ton site. Son contenu JSON déclare quelles apps sont autorisées à intercepter quels chemins :
{
"applinks": {
"details": [
{
"appID": "ABCDE12345.com.monentreprise.monapp",
"paths": ["/produit/*", "/article/*", "NOT /admin/*"]
}
]
}
}Le champ appID combine ton Team ID et ton bundle identifier, séparés par un point. Le champ paths liste les chemins que ton app va intercepter, avec trois syntaxes utiles. Un chemin littéral comme /about matche exactement cette URL. Le wildcard * matche n'importe quelle suite de caractères, donc /produit/* matche /produit/42 aussi bien que /produit/chaussures/rouge. Le préfixe NOT exclut un chemin, ce qui te permet de dire "toutes les URLs sauf l'interface d'administration".
Apple recommande aujourd'hui d'utiliser une syntaxe plus expressive basée sur le champ components, qui permet de filtrer non seulement sur le path mais aussi sur la query string et sur le fragment. Cette syntaxe est plus verbeuse mais plus précise :
{
"applinks": {
"details": [
{
"appIDs": ["ABCDE12345.com.monentreprise.monapp"],
"components": [
{ "/": "/produit/*" },
{ "/": "/article/*", "?": { "source": "email" }, "comment": "Seuls les liens envoyés par email" },
{ "/": "/admin/*", "exclude": true }
]
}
]
}
}Les deux syntaxes sont supportées depuis iOS 13, et components est celle à privilégier pour tout nouveau projet.
Interception dans le code Swift
Une fois l'app installée avec le bon entitlement et le fichier AASA correctement servi, iOS va router automatiquement les URLs matchant tes chemins vers ton application. Il reste à gérer cette URL dans le code. En SwiftUI, ça se fait avec le modifier onOpenURL appliqué au niveau de ta scène principale :
@main
struct MonApp: App {
var body: some Scene {
WindowGroup {
ContentView()
.onOpenURL { url in
handleDeepLink(url)
}
}
}
private func handleDeepLink(_ url: URL) {
guard url.scheme == "https", url.host == "monapp.fr" else { return }
switch url.pathComponents {
case [_, "produit", let productID]:
// Naviguer vers la fiche produit
navigate(to: .product(id: productID))
case [_, "article", let articleID]:
navigate(to: .article(id: articleID))
default:
break
}
}
}En UIKit, le même travail se fait dans application(_:continue:restorationHandler:) de ton AppDelegate ou SceneDelegate, via un NSUserActivity de type NSUserActivityTypeBrowsingWeb. Le mécanisme est identique sur le fond, seule l'API diffère.
Les quatre pièges qui font perdre des heures
Une fois cette mise en place faite, tu vas probablement tester, et il y a de fortes chances que ça ne fonctionne pas du premier coup. Voici les quatre causes qui couvrent 90 % des cas.
Premier piège : la redirection HTTP. Beaucoup de serveurs sont configurés pour rediriger /apple-app-site-association (à la racine, sans .well-known/) vers /.well-known/apple-app-site-association, dans un souci de rétro-compatibilité. Or iOS refuse catégoriquement de suivre une redirection sur ce fichier. Si ton serveur renvoie un code 301 ou 302, le fichier est considéré comme invalide, point. Assure-toi que l'URL /.well-known/apple-app-site-association répond directement avec un code 200 et le contenu JSON, sans intermédiaire.
Deuxième piège : le cache du CDN Apple. Comme mentionné plus haut, iOS passe par un CDN intermédiaire pour récupérer ton AASA. Si tu as publié une première version incorrecte de ton fichier, puis que tu l'as corrigée, le CDN peut continuer à servir l'ancienne version pendant plusieurs heures. Tu peux vérifier ce que le CDN a en cache en ouvrant directement https://app-site-association.cdn-apple.com/a/v1/monapp.fr dans ton navigateur. Si le contenu ne correspond pas à ton AASA actuel, le problème vient du cache. Il n'existe pas de bouton "purger le cache" accessible aux développeurs, il faut attendre, ou utiliser le mode développeur décrit plus loin.
Troisième piège : le Content-Type. Le fichier doit être servi avec le Content-Type application/json. Certains serveurs web, ne reconnaissant pas le nom de fichier sans extension, envoient par défaut text/plain ou application/octet-stream. iOS rejette alors le fichier silencieusement. Sur Nginx, la configuration ressemble à ceci :
location = /.well-known/apple-app-site-association {
default_type application/json;
}Si tu utilises un framework moderne comme Next.js ou SvelteKit, le fichier déposé dans le dossier public/ est généralement servi correctement, mais il est prudent de vérifier avec un curl -I ce que renvoie réellement ton serveur.
Quatrième piège : l'entitlement mal signé. Si ton entitlement com.apple.developer.associated-domains n'est pas présent dans le provisioning profile avec lequel ton app est signée, iOS ignore complètement les Associated Domains. Xcode gère ça automatiquement en mode Automatic signing, mais si tu es en signing manuel, il faut que le provisioning profile ait été régénéré après l'ajout de la capability dans l'App ID sur le portail développeur.
Cohabitation avec un scheme custom
Beaucoup d'apps, en plus des Universal Links, utilisent un scheme custom de type monapp:// pour leurs liens internes. Par exemple pour des widgets, des notifications locales, ou des actions rapides depuis un shortcut. Les deux mécanismes peuvent parfaitement coexister, et c'est même souvent la meilleure architecture.
La règle pratique est la suivante : les Universal Links sont pour les liens publics, partageables, qui peuvent arriver de n'importe où et qui doivent fallback sur le web si l'app n'est pas installée. Les schemes custom sont pour les liens internes à ton écosystème, qui n'ont de sens que si ton app est installée, et qui ne sont jamais exposés à des utilisateurs qui ne l'ont pas.
Côté implémentation, le même modifier onOpenURL reçoit les deux types d'URL. Tu différencies en inspectant le scheme :
private func handleDeepLink(_ url: URL) {
if url.scheme == "https" {
handleUniversalLink(url)
} else if url.scheme == "monapp" {
handleCustomScheme(url)
}
}Le scheme custom se déclare dans le Info.plist de l'app, via la clé CFBundleURLTypes, et ne nécessite aucune configuration côté serveur puisqu'il ne passe par aucun mécanisme web.
💡 Sur ce genre de chantier (générer le bon AASA, débugger un Universal Link silencieux, brancher le routing dans une app SwiftUI existante), Claude Code me fait gagner pas mal de temps au quotidien. Je détaille tout le workflow dans mon guide Claude Code × iOS.
3. webcredentials: Password AutoFill
Le deuxième service est nettement moins connu que les Universal Links, mais beaucoup plus simple à mettre en place et beaucoup plus utile qu'il n'y paraît. Il s'agit de permettre au trousseau iCloud de l'utilisateur de partager ses identifiants et mots de passe entre ton site web et ton application mobile.
Imagine qu'un utilisateur se soit créé un compte sur monapp.fr depuis son navigateur, en laissant iCloud générer et mémoriser un mot de passe. Quelques jours plus tard, il installe ton application. Sans webcredentials, il devrait soit se souvenir de son mot de passe, soit aller le chercher manuellement dans Réglages. Avec webcredentials, iOS reconnaît que l'app et le site sont liés, et propose directement le mot de passe stocké pour monapp.fr quand il tape sur le champ Mot de passe dans l'app. L'inverse fonctionne aussi : un mot de passe créé depuis l'app est proposé automatiquement quand l'utilisateur revient sur le site.
Mise en place
La configuration se fait des deux côtés. Dans les entitlements de ton app, tu ajoutes webcredentials:monapp.fr à la liste des associated domains. Dans ton AASA, tu ajoutes une clé webcredentials à côté de la clé applinks :
{
"applinks": {
"details": [{
"appID": "ABCDE12345.com.monentreprise.monapp",
"paths": ["/produit/*"]
}]
},
"webcredentials": {
"apps": ["ABCDE12345.com.monentreprise.monapp"]
}
}
Côté code Swift, il n'y a presque rien à faire. La seule chose à retenir est de bien typer tes TextField SwiftUI avec les bons textContentType :
TextField("Email", text: $email)
.textContentType(.username)
SecureField("Mot de passe", text: $password)
.textContentType(.password)
C'est ce qui permet à iOS d'identifier qu'il s'agit d'un champ où proposer des credentials. Pour un écran de création de compte, tu utilises .newPassword au lieu de .password, ce qui indique à iOS de générer un mot de passe fort plutôt que de proposer les existants.
Un piège conceptuel classique
webcredentials est souvent confondu avec Sign in with Apple. Ce sont pourtant deux systèmes complètement indépendants. webcredentials partage les mots de passe stockés dans le trousseau iCloud de l'utilisateur, pour un compte classique identifiant + mot de passe. Sign in with Apple est un système d'authentification fédérée, où l'utilisateur se connecte avec son Apple ID sans jamais créer de mot de passe.
Si ton app propose les deux, webcredentials et Sign in with Apple, tu as deux flux d'authentification différents qui coexistent. webcredentials ne fera rien pour les utilisateurs qui se sont inscrits via Apple, puisqu'ils n'ont pas de mot de passe à stocker. Inversement, Sign in with Apple est disponible que tu aies webcredentials ou non. Les deux ne s'influencent pas.
4. appclips: les App Clips
Un App Clip est une version légère et instantanée d'une application, limitée à 15 Mo décompressée, qui peut s'exécuter sans installation préalable. Quand l'utilisateur scanne un code QR associé à un App Clip, tape un tag NFC, ou clique sur un lien particulier, iOS télécharge et lance cette mini-version de l'app en quelques secondes, sans passer par l'App Store.
Le cas d'usage typique est un parking où l'utilisateur scanne un QR code pour payer sa place. Il n'a pas envie d'installer une app complète pour une transaction unique de trois euros. L'App Clip lui permet de payer immédiatement, et propose ensuite éventuellement d'installer l'app complète. Autre cas fréquent : un restaurant où le menu est accessible via un QR code sur la table, avec une commande directement dans l'App Clip.
Mise en place
Côté Xcode, un App Clip est un target séparé de ton app principale, mais qui partage le code et les ressources. Tu crées ce target via File > New > Target > App Clip, et il reçoit automatiquement son propre bundle identifier, généralement com.monentreprise.monapp.Clip.
L'entitlement associé-domain de l'App Clip liste les domaines avec le préfixe appclips: :
<key>com.apple.developer.associated-domains</key>
<array>
<string>appclips:monapp.fr</string>
</array>Côté AASA, tu ajoutes une section appclips avec le bundle identifier de l'App Clip :
{
"appclips": {
"apps": ["ABCDE12345.com.monentreprise.monapp.Clip"]
}
}Une URL App Clip a une structure particulière qui permet à iOS de différencier un App Clip d'un Universal Link classique. En pratique, tu associes une Advanced App Clip Experience dans App Store Connect, qui déclare que les URLs matchant un certain pattern déclenchent l'App Clip plutôt que le Universal Link. Par exemple, tu peux dire que https://monapp.fr/clip/table/12 déclenche l'App Clip du restaurant, tandis que https://monapp.fr/menu reste un Universal Link classique.
Quand ça vaut le coup
Les App Clips ont un coût de développement non négligeable. Il faut maintenir deux targets, gérer la contrainte des 15 Mo, tester les flux sans l'app complète installée. Ça ne vaut le coup que si ton produit a un moment de friction où l'installation est un frein majeur. Si ton app est principalement utilisée par des utilisateurs qui l'installent une fois pour toutes, un App Clip n'apporte rien. En revanche, pour les apps où la découverte se fait dans le monde physique, par un code QR ou un tag NFC, l'App Clip peut multiplier ton taux de conversion de manière significative.
5. activitycontinuation: Handoff (legacy)
Le service activitycontinuation existe pour des raisons historiques. Avant iOS 13, le mécanisme de Handoff, qui permet par exemple de commencer à lire une page web sur Mac et de la reprendre dans une app sur iPhone, nécessitait une déclaration explicite activitycontinuation:tondomaine.fr dans les entitlements.
Depuis iOS 13, ce cas d'usage est couvert par applinks: de manière transparente. Tu n'as donc plus besoin d'ajouter activitycontinuation si ton app cible iOS 13 ou plus, ce qui est le cas de toutes les apps maintenues aujourd'hui. Le service est gardé par Apple uniquement pour la rétro-compatibilité avec les apps anciennes.
La seule situation où tu pourrais avoir besoin de le déclarer est si tu maintiens une app qui cible encore iOS 12 ou antérieur. Étant donné qu'iOS 12 représente une fraction infinitésimale du parc installé en 2026, tu peux considérer ce service comme obsolète pour toute nouvelle implémentation.
6. Le mode développeur 👀
On a vu plus haut que le cache du CDN Apple pouvait faire perdre plusieurs heures en debug, puisqu'une modification de l'AASA peut mettre jusqu'à 24 heures à se propager. Il existe une solution peu documentée à ce problème : le mode développeur des Associated Domains.
Activation
Ce mode s'active en deux étapes. La première est dans ton entitlement, où tu ajoutes le paramètre ?mode=developer après le nom du domaine :
<key>com.apple.developer.associated-domains</key>
<array>
<string>applinks:monapp.fr?mode=developer</string>
</array>La seconde étape est sur le device lui-même. Tu dois aller dans Réglages > Développeur > Associated Domains Development et activer cette option. Attention, cette section n'apparaît que sur les appareils où le Developer Mode est actif, ce qui se fait depuis Réglages > Confidentialité et sécurité > Mode développeur.
Une fois ce mode actif, iOS ne passe plus par le CDN Apple pour récupérer le fichier AASA. Il interroge directement ton serveur à chaque installation ou mise à jour de l'app. Résultat : tu peux modifier ton AASA, réinstaller l'app, et tester immédiatement sans attendre le cache.
Limites et bonnes pratiques
Ce mode est uniquement prévu pour le développement. Il ne faut surtout pas laisser ?mode=developer dans les entitlements d'une build distribuée sur l'App Store. En production, tu veux absolument passer par le CDN Apple, pour des raisons de performance (le CDN est beaucoup plus rapide que ton serveur web) et de résilience (si ton serveur tombe, le CDN continue à servir la version cachée).
Le bon pattern consiste à avoir deux fichiers d'entitlements dans ton projet Xcode : un pour les builds Debug avec le mode développeur actif, un pour les builds Release sans ce paramètre. La sélection se fait dans les build settings de ton target, via la clé CODE_SIGN_ENTITLEMENTS qui peut prendre une valeur différente selon la configuration.
7. Architecture d'un handler de deep link robuste
Maintenant que les cinq services sont clairs, parlons architecture. Dans une app qui mélange Universal Links, scheme custom, et potentiellement App Clips, le code qui reçoit les URLs peut vite devenir un monstre de conditions imbriquées. Voici un pattern qui se maintient bien sur la durée.
L'idée est de séparer trois responsabilités : la réception de l'URL, le parsing qui la transforme en intention métier, et le routage qui effectue la navigation.
// 1. Réception : unique point d'entrée
@main
struct MonApp: App {
@State private var router = Router()
var body: some Scene {
WindowGroup {
ContentView()
.environment(router)
.onOpenURL { url in
if let intent = DeepLinkParser.parse(url) {
router.handle(intent)
}
}
}
}
}
// 2. Parsing : transforme une URL en intention
enum DeepLinkIntent {
case showProduct(id: String)
case showArticle(id: String)
case openPaywall
}
enum DeepLinkParser {
static func parse(_ url: URL) -> DeepLinkIntent? {
if url.scheme == "https", url.host == "monapp.fr" {
return parseUniversalLink(url)
}
if url.scheme == "monapp" {
return parseCustomScheme(url)
}
return nil
}
private static func parseUniversalLink(_ url: URL) -> DeepLinkIntent? {
let components = url.pathComponents
switch components {
case [_, "produit", let id]: return .showProduct(id: id)
case [_, "article", let id]: return .showArticle(id: id)
default: return nil
}
}
private static func parseCustomScheme(_ url: URL) -> DeepLinkIntent? {
switch url.host {
case "paywall": return .openPaywall
default: return nil
}
}
}
// 3. Routage : effectue la navigation
@Observable
final class Router {
var path: [Destination] = []
var presentedSheet: Sheet?
func handle(_ intent: DeepLinkIntent) {
switch intent {
case .showProduct(let id):
path.append(.product(id: id))
case .showArticle(let id):
path.append(.article(id: id))
case .openPaywall:
presentedSheet = .paywall
}
}
}Ce découpage a plusieurs avantages concrets. Le parser est testable unitairement, sans avoir besoin de monter une app complète. Les intentions métier sont un type énuméré fermé, donc le compilateur te force à traiter tous les cas quand tu ajoutes un nouvel écran. Et le router reste agnostique de la source de l'intention, ce qui te permet d'injecter les mêmes intentions depuis un widget, depuis une notification push, ou depuis un shortcut iOS, sans dupliquer la logique de navigation.
8. Checklist de debug
Quand un Associated Domain ne fonctionne pas, voici l'ordre des vérifications à faire, du plus rapide au plus profond.
Vérifier que le fichier est bien servi. Depuis ton terminal :
curl -I https://monapp.fr/.well-known/apple-app-site-associationTu dois voir un code 200, un Content-Type: application/json, et aucun Location (qui indiquerait une redirection). Si l'un de ces trois points est faux, iOS ne chargera jamais ton fichier.
Vérifier le contenu du fichier. Toujours depuis ton terminal :
curl https://monapp.fr/.well-known/apple-app-site-association | jqLe JSON doit être valide, les appID doivent inclure le Team ID et le bundle identifier séparés par un point. Une typo sur le Team ID est un grand classique qui fait perdre des heures.
Vérifier ce que le CDN Apple a en cache. Tu peux voir exactement ce qu'iOS reçoit réellement en interrogeant directement le CDN :
curl https://app-site-association.cdn-apple.com/a/v1/monapp.frSi le contenu ne correspond pas à ton AASA local, tu sais que le problème est le cache. Soit tu attends, soit tu bascules en mode développeur.
Lire les logs système sur le device. Branche ton iPhone à ton Mac, ouvre Console.app, filtre sur le process swcd qui est le daemon iOS responsable des Associated Domains. Réinstalle ton app, et tu verras passer les logs détaillés : téléchargement de l'AASA, parsing, validation, association à l'app. Les erreurs y sont généralement explicites.
Tester avec la commande swcutil. Sur macOS, la commande swcutil permet d'inspecter l'état des Associated Domains d'une app installée sur le Mac :
swcutil dl bundle com.monentreprise.monappCette commande affiche le résultat du dernier téléchargement d'AASA, avec les erreurs éventuelles. Pour un test iOS, tu peux faire le même diagnostic en connectant ton iPhone et en lisant les logs via Console.app filtrés sur swcd.
Vérifier l'entitlement signé. Depuis le dossier de ton app installée sur le simulateur :
codesign -d entitlements - /chemin/vers/MonApp.appTu dois voir com.apple.developer.associated-domains dans la sortie. Si cette entitlement n'apparaît pas, ton app n'est pas signée avec le bon provisioning profile, et iOS ignorera complètement tes Associated Domains, même si le fichier AASA est parfait.
Conclusion
Les Associated Domains sont un mécanisme élégant qui résout proprement un problème complexe : prouver qu'une app et un site web sont bien contrôlés par la même entité, sans nécessiter d'échange de secrets ni de protocole compliqué. Un fichier JSON servi en HTTPS suffit.
Les cinq services que nous avons couverts répondent à des besoins très différents. Les Universal Links (applinks:) sont incontournables dès que ton app a un pendant web, et c'est la première chose à mettre en place. Le Password AutoFill (webcredentials:) est un gain d'expérience utilisateur énorme pour un coût d'implémentation quasi nul, et il est dommage de s'en passer. Les App Clips (appclips:) sont plus spécialisés et ne valent le coup que si ton produit a une dimension physique ou de découverte contextuelle. Le service activitycontinuation: est aujourd'hui obsolète pour toute nouvelle implémentation. Le mode développeur n'est pas vraiment un service, mais c'est l'outil qui va te sauver plusieurs heures de debug la prochaine fois que tu touches à un AASA.
Si tu dois investir sur un seul de ces services en priorité, mets en place les Universal Links. C'est celui qui a le plus d'impact visible pour tes utilisateurs, et c'est aussi celui qui te formera sur le mécanisme général, ce qui te permettra d'ajouter les autres services beaucoup plus rapidement par la suite.
Tu veux aller plus loin ?
Les Associated Domains, c'est un cas typique où Claude Code change la donne sur un projet iOS : générer un AASA correct, déboguer le universal link qui ne se déclenche pas, intégrer le routing dans une app SwiftUI existante. Sur Keepio, je passe par Claude Code pour ce genre de plomberie au quotidien.
Si tu veux apprendre la vraie méthode pour bosser avec Claude Code en mode dev iOS (agents, hooks, MCP, workflow de debug, et un projet fil rouge complet), j'en ai fait un guide.

Commentaires
Aucun commentaire pour le moment. Sois le premier !