add-app-clip
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseAdd an App Clip to an Expo App
为Expo应用添加App Clip
Adds an iOS App Clip target to an Expo project. The Clip lives in , ships alongside the parent app, and is invoked from a URL on the app's domain via an Apple App Site Association (AASA) file.
targets/clip/The parent app's bundle ID becomes and the Clip's is automatically derived as (e.g. ).
com.<username>.<app-name><parent>.clipcom.bacon.may20.clip为Expo项目添加iOS App Clip目标。该Clip位于目录下,与主应用一同分发,可通过应用域名上的URL,借助Apple App Site Association(AASA)文件调用。
targets/clip/主应用的Bundle ID将变为,Clip的Bundle ID会自动派生为(例如)。
com.<username>.<app-name><parent>.clipcom.bacon.may20.clip1. Set bundleIdentifier
and appleTeamId
bundleIdentifierappleTeamId1. 设置bundleIdentifier
和appleTeamId
bundleIdentifierappleTeamIdbun create targetapp.jsonjson
{
"expo": {
"ios": {
"bundleIdentifier": "com.<username>.<app-name>",
"appleTeamId": "XX57RJ5UTD"
}
}
}如果缺少这些配置,会发出警告。请在中添加:
bun create targetapp.jsonjson
{
"expo": {
"ios": {
"bundleIdentifier": "com.<username>.<app-name>",
"appleTeamId": "XX57RJ5UTD"
}
}
}2. Add the App Clip target
2. 添加App Clip目标
sh
bun create target clip- — the target's config plugin
targets/clip/expo-target.config.js - — Clip Info.plist
targets/clip/Info.plist - ,
targets/clip/AppDelegate.swift, etc.Assets.xcassets
Pick a good icon or reuse the existing one defined in the app — check it with under the or key.
bunx expo configiconios.iconsh
bun create target clip- —— 目标的配置插件
targets/clip/expo-target.config.js - —— Clip的Info.plist文件
targets/clip/Info.plist - 、
targets/clip/AppDelegate.swift等文件Assets.xcassets
选择合适的图标或复用应用中已定义的图标 —— 可通过查看或键下的配置。
bunx expo configiconios.icon3. Wire up associated domains
3. 关联域名配置
The parent app and the Clip each need the Associated Domains entitlement pointing at the domain that hosts the AASA file.
In , add both (parent) and (Clip invocation) entries:
app.jsonapplinks:appclips:json
{
"expo": {
"ios": {
"associatedDomains": [
"applinks:may20.expo.app",
"appclips:may20.expo.app"
]
}
}
}In , declare the Clip's entitlement:
targets/clip/expo-target.config.jsjs
/** @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"],
},
});If you skip this,will print:expo prebuild.Apple App Clip may require the associated domains entitlement but none were found
主应用和Clip都需要关联域名权限,指向托管AASA文件的域名。
在中,添加(主应用)和(Clip调用)条目:
app.jsonapplinks:appclips:json
{
"expo": {
"ios": {
"associatedDomains": [
"applinks:may20.expo.app",
"appclips:may20.expo.app"
]
}
}
}在中,声明Clip的权限:
targets/clip/expo-target.config.jsjs
/** @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"],
},
});如果跳过此步骤,会输出:expo prebuild(Apple App Clip可能需要关联域名权限,但未找到)。Apple App Clip may require the associated domains entitlement but none were found
4. Register bundle IDs and create the App Store entry
4. 注册Bundle ID并创建App Store条目
sh
bunx setup-safariThis logs in to the Apple Developer account, registers , creates the App Store Connect entry, and prints:
com.bacon.may20- A starter JSON
apple-app-site-association - A tag with the iTunes app id
<meta name="apple-itunes-app"> - Team ID, iTunes ID, and Bundle ID
sh
bunx setup-safari这会登录Apple开发者账户,注册,创建App Store Connect条目,并输出:
com.bacon.may20- 初始的JSON文件
apple-app-site-association - 包含iTunes应用ID的标签
<meta name="apple-itunes-app"> - 团队ID、iTunes ID和Bundle ID
5. Host the AASA file
5. 托管AASA文件
App Clips are invoked when iOS fetches and finds a matching entry.
https://<your-domain>/.well-known/apple-app-site-associationappclipssh
mkdir -p public/.well-known
touch public/.well-known/apple-app-site-associationPaste the JSON printed, but add an block for the Clip's full app ID (). The output of only covers the parent app:
setup-safariappclips<TeamID>.<ClipBundleID>setup-safarijson
{
"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:
- The file has no extension and no requirements beyond being served as-is. Expo Router static export serves files in
Content-Typeverbatim.public/ - The block is what lets a URL on the domain launch the Clip.
appclips - is used for sharing credentials between the website, parent app, and the App Clip.
webcredentials - is optional and used for sharing the link between mobile and desktop. Must be used with
activitycontinuationfrom expo-router — see https://docs.expo.dev/router/advanced/apple-handoff/Head - Notation and route-disabling details: https://sosumi.ai/documentation/xcode/supporting-associated-domains
当iOS获取并找到匹配的条目时,App Clip会被调用。
https://<your-domain>/.well-known/apple-app-site-associationappclipssh
mkdir -p public/.well-known
touch public/.well-known/apple-app-site-association粘贴输出的JSON,但需添加块,对应Clip的完整应用ID()。的输出仅包含主应用的配置:
setup-safariappclips<TeamID>.<ClipBundleID>setup-safarijson
{
"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"]
}
}注意事项:
- 该文件无扩展名,且除了原样提供外无Content-Type要求。Expo Router静态导出会原样提供目录下的文件。
public/ - 块是让域名上的URL启动Clip的关键。
appclips - 用于在网站、主应用和App Clip之间共享凭据。
webcredentials - 是可选的,用于在移动设备和桌面设备之间共享链接。必须与expo-router的
activitycontinuation一同使用 —— 详见https://docs.expo.dev/router/advanced/apple-handoff/Head - 符号和路由禁用细节:https://sosumi.ai/documentation/xcode/supporting-associated-domains
6. Add the Smart App Banner meta tag
6. 添加智能应用横幅元标签
Create (Expo Router's HTML shell) and add the tag from . Create the versioned template if it doesn't exist:
src/app/+html.tsxsetup-safarish
bunx expo customize src/app/+html.tsxAdd the meta tag to the :
<head>tsx
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>
);
}To make the website show the App Clip card instead of the install card, use:
html
<meta
name="apple-itunes-app"
content="app-id=6771566491, app-clip-bundle-id=com.bacon.may20.clip, app-clip-display=card"
/>创建(Expo Router的HTML外壳)并添加输出的标签。如果不存在版本化模板,可创建:
src/app/+html.tsxsetup-safarish
bunx expo customize src/app/+html.tsx在中添加元标签:
<head>tsx
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>
);
}若要让网站显示App Clip卡片而非安装卡片,可使用:
html
<meta
name="apple-itunes-app"
content="app-id=6771566491, app-clip-bundle-id=com.bacon.may20.clip, app-clip-display=card"
/>7. Deploy the website
7. 部署网站
The AASA file must be live before iOS will trust the association. Use EAS Hosting:
sh
bunx expo export -p web
eas deploy --prodThis publishes the site (including ) at . Verify:
/.well-known/apple-app-site-associationhttps://<slug>.expo.appsh
curl https://may20.expo.app/.well-known/apple-app-site-associationAASA文件必须在线,iOS才会信任该关联。使用EAS Hosting:
sh
bunx expo export -p web
eas deploy --prod这会将网站(包括)发布到。验证:
/.well-known/apple-app-site-associationhttps://<slug>.expo.appsh
curl https://may20.expo.app/.well-known/apple-app-site-association8. Mirror permissions
8. 镜像权限
Inspect the parent app's permissions after prebuild:
sh
npx expo config --type introspectLook at the object — mirror the permission keys in the App Clip's so matching APIs can be used from the Clip.
infoPlistInfo.plistSet in the Clip's target config — App Clips have a higher minimum size limit in iOS 17.6.
deploymentTarget: "17.6"If the app uses push notifications or location services, add to the App Clip's to request the necessary permissions:
Info.plistxml
<key>NSAppClip</key>
<dict>
<key>NSAppClipRequestEphemeralUserNotification</key>
<false/>
<key>NSAppClipRequestLocationConfirmation</key>
<true/>
</dict>预构建后检查主应用的权限:
sh
npx expo config --type introspect查看对象 —— 在App Clip的中镜像权限键,以便Clip可以使用匹配的API。
infoPlistInfo.plist在Clip的目标配置中设置 —— iOS 17.6中App Clip的最小大小限制更高。
deploymentTarget: "17.6"如果应用使用推送通知或定位服务,需在App Clip的中添加配置以请求必要权限:
Info.plistxml
<key>NSAppClip</key>
<dict>
<key>NSAppClipRequestEphemeralUserNotification</key>
<false/>
<key>NSAppClipRequestLocationConfirmation</key>
<true/>
</dict>9. Build and submit to TestFlight
9. 构建并提交至TestFlight
sh
bunx testflightThis will:
- Generate an if missing.
eas.json - Set up credentials for both targets (parent + Clip). Each gets its own provisioning profile but can share a single Distribution Certificate.
- Sync capabilities — note for the Clip target.
Enabled: Associated Domains - Build, upload, and schedule a TestFlight submission.
sh
bunx testflight这会:
- 如果缺少则生成该文件。
eas.json - 为两个目标(主应用 + Clip)设置凭据。每个目标都有自己的配置文件,但可以共享一个分发证书。
- 同步功能 —— 注意Clip目标的(已启用:关联域名)。
Enabled: Associated Domains - 构建、上传并安排TestFlight提交。
10. Configure App Clip metadata
10. 配置App Clip元数据
Pull existing App Store metadata to local:
sh
eas metadata:pullAdd to . Up to 3 invocation URLs can launch the Clip from a web page:
apple.appClipstore.config.jsonjson
{
"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"
}
}
}
}
}
}The must be a 1800x1200 PNG with no opacity.
headerImagePush back to the store:
sh
eas metadata:pushApple's recommended App Clip metadata guidelines: https://sosumi.ai/documentation/appclip/configuring-the-launch-experience-of-your-app-clip
将现有App Store元数据拉取到本地:
sh
eas metadata:pull在中添加。最多可设置3个调用URL,用于从网页启动Clip:
store.config.jsonapple.appClipjson
{
"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将元数据推回商店:
sh
eas metadata:pushWhat you get
你将获得的内容
- Parent app target:
com.bacon.may20 - App Clip target: , lives in
com.bacon.may20.cliptargets/clip/ - AASA hosted at
https://may20.expo.app/.well-known/apple-app-site-association - Smart App Banner meta tag on every web route
- Every route linked to its native counterpart
- TestFlight build of the parent app with the Clip embedded
Once Apple invokes the Clip from a URL on the domain, iOS opens 's entry point which loads the React Native app.
targets/clip/- 主应用目标:
com.bacon.may20 - App Clip目标:,位于
com.bacon.may20.clip目录下targets/clip/ - 托管在的AASA文件
https://may20.expo.app/.well-known/apple-app-site-association - 每个网页路由上的智能应用横幅元标签
- 每个路由都链接到对应的原生组件
- 包含Clip的主应用TestFlight构建版本
一旦Apple从域名上的URL调用Clip,iOS会打开的入口点,加载React Native应用。
targets/clip/Native detection (optional)
原生检测(可选)
To let JS detect when it's running inside an App Clip and present an install prompt for the full app, create a local Expo module () that exposes .
bunx create-expo-module --localnavigator.appClip.prompt()See ./references/native-module.md for the Swift module, TypeScript interface, and usage.
为了让JS检测是否在App Clip中运行,并显示主应用的安装提示,可创建本地Expo模块(),暴露方法。
bunx create-expo-module --localnavigator.appClip.prompt()详见./references/native-module.md中的Swift模块、TypeScript接口及使用方法。
References
参考资料
- ./references/native-module.md — Local Expo module to detect App Clip context and present the SKOverlay install prompt
- ./references/native-module.md —— 用于检测App Clip上下文并显示SKOverlay安装提示的本地Expo模块