expo-app-clip

Par expo · skills

Framework (OSS). Ajouter une cible App Clip iOS à une application Expo. À utiliser lorsque l'utilisateur mentionne App Clip, AASA, apple-app-site-association, appclips, smart app banner, ou souhaite publier un iOS Clip léger invoqué depuis une URL aux côtés de son application parente.

npx skills add https://github.com/expo/skills --skill expo-app-clip

Ajouter un App Clip à une application Expo

Prérequis. L'ajout de la cible App Clip est open source. Son déploiement nécessite une adhésion à l'Apple Developer Program, un examen App Store, et le fichier AASA doit être servi en HTTPS sur votre domaine (n'importe quel hôte HTTPS fonctionne ; EAS Hosting en est une option). La compilation via EAS Build ou bunx testflight utilise les minutes de compilation de votre plan EAS. Voir https://expo.dev/pricing et https://developer.apple.com/app-clips/.

Ajoute une cible iOS App Clip à un projet Expo. Le Clip réside dans targets/clip/, est livré avec l'application parent, et est invoqué via une URL du domaine de l'application à travers un fichier Apple App Site Association (AASA).

L'identifiant du bundle de l'application parent devient com.<username>.<app-name> et celui du Clip est automatiquement dérivé en <parent>.clip (par ex. com.bacon.may20.clip).

1. Définir bundleIdentifier et appleTeamId

bun create target avertit si ceux-ci manquent. Ajoutez à app.json :

{
  "expo": {
    "ios": {
      "bundleIdentifier": "com.<username>.<app-name>",
      "appleTeamId": "XX57RJ5UTD"
    }
  }
}

2. Ajouter la cible App Clip

bun create target clip

Cela installe @bacons/apple-targets, l'ajoute au tableau plugins dans app.json, et écrit :

  • targets/clip/expo-target.config.js — le plugin de configuration de la cible
  • targets/clip/Info.plist — Info.plist du Clip
  • targets/clip/AppDelegate.swift, Assets.xcassets, etc.

Choisissez une bonne icône ou réutilisez celle existante définie dans l'application — vérifiez-la avec bunx expo config sous la clé icon ou ios.icon.

3. Configurer les domaines associés

L'application parent et le Clip ont besoin du droit Associated Domains pointant vers le domaine qui héberge le fichier AASA.

Dans app.json, ajoutez les entrées applinks: (parent) et appclips: (invocation du Clip) :

{
  "expo": {
    "ios": {
      "associatedDomains": [
        "applinks:may20.expo.app",
        "appclips:may20.expo.app"
      ]
    }
  }
}

Dans targets/clip/expo-target.config.js, déclarez le droit du Clip :

/** @type {import('@bacons/apple-targets/app.plugin').ConfigFunction} */
module.exports = (config) => ({
  type: "clip",
  icon: "https://github.com/expo.png",
  entitlements: {
    "com.apple.developer.associated-domains": ["appclips:may20.expo.app"],
  },
});

Si vous sautez cette étape, expo prebuild affichera : Apple App Clip may require the associated domains entitlement but none were found.

4. Enregistrer les identifiants de bundle et créer l'entrée App Store

bunx setup-safari

Cela se connecte au compte Apple Developer, enregistre com.bacon.may20, crée l'entrée App Store Connect, et affiche :

  • Un JSON apple-app-site-association de démarrage
  • Une balise <meta name="apple-itunes-app"> avec l'identifiant iTunes
  • ID de l'équipe, ID iTunes et ID de bundle

5. Héberger le fichier AASA

Les App Clips sont invoqués quand iOS récupère https://<your-domain>/.well-known/apple-app-site-association et trouve une entrée appclips correspondante.

mkdir -p public/.well-known
touch public/.well-known/apple-app-site-association

Collez le JSON que setup-safari a affiché, mais ajoutez un bloc appclips pour l'ID d'application complet du Clip (<TeamID>.<ClipBundleID>). La sortie de setup-safari ne couvre que l'application parent :

{
  "applinks": {
    "details": [
      {
        "appIDs": ["XX57RJ5UTD.com.bacon.may20"],
        "components": [{ "/": "*", "comment": "Matches all routes" }]
      }
    ]
  },
  "appclips": {
    "apps": ["XX57RJ5UTD.com.bacon.may20.clip"]
  },
  "activitycontinuation": {
    "apps": ["XX57RJ5UTD.com.bacon.may20"]
  },
  "webcredentials": {
    "apps": ["XX57RJ5UTD.com.bacon.may20"]
  }
}

Notes :

  • Le fichier n'a pas d'extension et aucune exigence Content-Type au-delà d'être servi tel quel. L'export statique Expo Router sert les fichiers dans public/ tels quels.
  • Le bloc appclips permet à une URL du domaine de lancer le Clip.
  • webcredentials est utilisé pour partager les identifiants entre le site web, l'application parent et l'App Clip.
  • activitycontinuation est optionnel et utilisé pour partager le lien entre mobile et bureau. Doit être utilisé avec Head d'expo-router — voir https://docs.expo.dev/router/advanced/apple-handoff/
  • Notation et détails de désactivation de route : https://sosumi.ai/documentation/xcode/supporting-associated-domains

6. Ajouter la balise Smart App Banner meta

Créez src/app/+html.tsx (shell HTML d'Expo Router) et ajoutez la balise de setup-safari. Créez le modèle versionné s'il n'existe pas :

bunx expo customize src/app/+html.tsx

Ajoutez la balise meta au <head> :

import { ScrollViewStyleReset } from "expo-router/html";

export default function Root({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <head>
        <meta charSet="utf-8" />
        <meta httpEquiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <meta name="apple-itunes-app" content="app-id=6771566491" />
        <ScrollViewStyleReset />
      </head>
      <body>{children}</body>
    </html>
  );
}

Pour faire afficher la carte App Clip au lieu de la carte d'installation sur le site web, utilisez :

<meta
  name="apple-itunes-app"
  content="app-id=6771566491, app-clip-bundle-id=com.bacon.may20.clip, app-clip-display=card"
/>

7. Déployer le site web

Le fichier AASA doit être en ligne avant qu'iOS ne fasse confiance à l'association. Utilisez EAS Hosting :

bunx expo export -p web
eas deploy --prod

Cela publie le site (y compris /.well-known/apple-app-site-association) à https://<slug>.expo.app. Vérifiez :

curl https://may20.expo.app/.well-known/apple-app-site-association

8. Dupliquer les permissions

Inspectez les permissions de l'application parent après prebuild :

npx expo config --type introspect

Regardez l'objet infoPlist — dupliquez les clés de permission dans Info.plist du App Clip pour que les API correspondantes puissent être utilisées depuis le Clip.

Définissez deploymentTarget: "17.6" dans la configuration cible du Clip — les App Clips ont une limite de taille minimale plus élevée dans iOS 17.6.

Si l'application utilise les notifications push ou les services de localisation, ajoutez à Info.plist du App Clip pour demander les permissions nécessaires :

<key>NSAppClip</key>
<dict>
  <key>NSAppClipRequestEphemeralUserNotification</key>
  <false/>
  <key>NSAppClipRequestLocationConfirmation</key>
  <true/>
</dict>

9. Compiler et soumettre à TestFlight

bunx testflight

Cela va :

  1. Générer un eas.json s'il manque.
  2. Configurer les identifiants pour les deux cibles (parent + Clip). Chacun obtient son propre profil de provisioning mais peut partager un seul certificat de distribution.
  3. Synchroniser les capacités — notez Enabled: Associated Domains pour la cible Clip.
  4. Compiler, télécharger et planifier une soumission TestFlight.

10. Configurer les métadonnées d'App Clip

Extraire les métadonnées d'App Store existantes en local :

eas metadata:pull

Ajoutez apple.appClip à store.config.json. Jusqu'à 3 URL d'invocation peuvent lancer le Clip depuis une page web :

{
  "configVersion": 0,
  "apple": {
    "appClip": {
      "defaultExperience": {
        "action": "PLAY",
        "releaseWithAppStoreVersion": true,
        "reviewDetail": {
          "invocationUrls": ["https://may20.expo.app/", null, null]
        },
        "info": {
          "en-US": {
            "subtitle": "Instantly native with Expo",
            "headerImage": "store/apple/app-clip/en-US/asc-app-clip.png"
          }
        }
      }
    }
  }
}

headerImage doit être un PNG 1800x1200 sans transparence.

Repoussez vers le magasin :

eas metadata:push

Recommandations d'Apple pour les métadonnées d'App Clip : https://sosumi.ai/documentation/appclip/configuring-the-launch-experience-of-your-app-clip

Ce que vous obtenez

  • Cible application parent : com.bacon.may20
  • Cible App Clip : com.bacon.may20.clip, réside dans targets/clip/
  • AASA hébergé à https://may20.expo.app/.well-known/apple-app-site-association
  • Balise Smart App Banner meta sur chaque route web
  • Chaque route liée à son équivalent natif
  • Build TestFlight de l'application parent avec le Clip intégré

Une fois qu'Apple invoque le Clip depuis une URL du domaine, iOS ouvre le point d'entrée de targets/clip/ qui charge l'application React Native.

Détection native (optionnel)

Pour laisser JS détecter quand il s'exécute dans un App Clip et présenter une invite d'installation pour l'application complète, créez un module Expo local (bunx create-expo-module --local) qui expose navigator.appClip.prompt().

Voir ./references/native-module.md pour le module Swift, l'interface TypeScript et l'utilisation.

Références

  • ./references/native-module.md — Module Expo local pour détecter le contexte d'App Clip et présenter l'invite d'installation SKOverlay

Skills similaires