app-clips

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

App Clips

App Clip

Lightweight, instantly-available versions of your iOS app for in-the-moment experiences or demos. Targets iOS 26+ / Swift 6.2 unless noted.
轻量型、可即时启动的iOS应用版本,适用于即时场景体验或应用演示。除非另有说明,否则目标平台为iOS 26+ / Swift 6.2。

Contents

目录

App Clip Target Setup

App Clip目标设置

An App Clip is a separate target in the same Xcode project as your full app:
  1. File → New → Target → App Clip — Xcode creates the target with the
    com.apple.developer.on-demand-install-capable
    entitlement and a
    Parent Application Identifiers
    entitlement linking back to the full app.
  2. The App Clip bundle ID must be a suffix of the full app's:
    com.example.MyApp.Clip
    .
  3. Xcode adds an Embed App Clip build phase to the full app target automatically.
App Clip是与完整应用位于同一Xcode项目中的独立目标
  1. File → New → Target → App Clip —— Xcode会创建带有
    com.apple.developer.on-demand-install-capable
    权限的目标,并添加关联回完整应用的
    Parent Application Identifiers
    权限。
  2. App Clip的Bundle ID必须是完整应用Bundle ID的后缀:例如
    com.example.MyApp.Clip
  3. Xcode会自动为完整应用目标添加Embed App Clip构建阶段。

Share code between targets

在目标间共享代码

Use Swift packages or shared source files. Add files to both targets, or use the
APPCLIP
active compilation condition:
swift
// In App Clip target Build Settings → Active Compilation Conditions: APPCLIP

#if !APPCLIP
// Full-app-only code (e.g., background tasks, App Intents)
#else
// App Clip specific code
#endif
Prefer local Swift packages for shared modules — add the package as a dependency of both targets.
使用Swift包或共享源文件。将文件添加到两个目标中,或使用
APPCLIP
编译条件:
swift
// 在App Clip目标的Build Settings → Active Compilation Conditions中添加:APPCLIP

#if !APPCLIP
// 仅完整应用可用的代码(如后台任务、App Intents)
#else
// App Clip专属代码
#endif
优先使用本地Swift包作为共享模块——将包添加为两个目标的依赖。

Shared asset catalogs

共享资源目录

Create a shared asset catalog included in both targets to avoid duplicating images and colors.
创建一个包含在两个目标中的共享资源目录,避免重复图片和颜色资源。

Invocation URL Handling

调用URL处理

App Clips receive an
NSUserActivity
of type
NSUserActivityTypeBrowsingWeb
on launch. Handle it with
onContinueUserActivity
:
swift
@main
struct DonutShopClip: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
                .onContinueUserActivity(
                    NSUserActivityTypeBrowsingWeb
                ) { activity in
                    handleInvocation(activity)
                }
        }
    }

    private func handleInvocation(_ activity: NSUserActivity) {
        guard let url = activity.webpageURL,
              let components = URLComponents(url: url, resolvingAgainstBaseURL: true)
        else { return }

        // Extract path/query to determine context
        let locationID = components.queryItems?
            .first(where: { $0.name == "location" })?.value

        // Update UI for this location
    }
}
For UIKit scene-based apps, implement
scene(_:willConnectTo:options:)
for cold launch and
scene(_:continue:)
for warm launch.
Key rule: The full app must handle all invocation URLs identically — when a user installs the full app, it replaces the App Clip and receives all future invocations.
App Clip启动时会收到类型为
NSUserActivityTypeBrowsingWeb
NSUserActivity
。使用
onContinueUserActivity
处理:
swift
@main
struct DonutShopClip: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
                .onContinueUserActivity(
                    NSUserActivityTypeBrowsingWeb
                ) { activity in
                    handleInvocation(activity)
                }
        }
    }

    private func handleInvocation(_ activity: NSUserActivity) {
        guard let url = activity.webpageURL,
              let components = URLComponents(url: url, resolvingAgainstBaseURL: true)
        else { return }

        // 提取路径/查询参数以确定上下文
        let locationID = components.queryItems?
            .first(where: { $0.name == "location" })?.value

        // 根据位置更新UI
    }
}
对于基于UIKit场景的应用,冷启动时实现
scene(_:willConnectTo:options:)
,热启动时实现
scene(_:continue:)
核心规则:完整应用必须以相同方式处理所有调用URL——当用户安装完整应用后,它会替代App Clip并接收所有后续调用。

App Clip Experience Configuration

App Clip体验配置

Configure experiences in App Store Connect after uploading a build containing the App Clip.
上传包含App Clip的构建版本后,在App Store Connect中配置体验。

Default App Clip experience (required)

默认App Clip体验(必填)

  • Provide: header image, subtitle (≤56 chars), call-to-action verb
  • App Store Connect generates a default App Clip link:
    https://appclip.apple.com/id?=<bundle_id>&key=value
  • Supports: QR codes, NFC tags, Messages, Spotlight, other apps
  • 需提供:头部图片、副标题(≤56字符)、行动号召动词
  • App Store Connect会生成默认App Clip链接
    https://appclip.apple.com/id?=<bundle_id>&key=value
  • 支持:二维码、NFC标签、信息应用、Spotlight、其他应用

Demo App Clip link

演示App Clip链接

  • Auto-generated by App Store Connect for demo versions of your app
  • Supports all invocations including physical (App Clip Codes, NFC, QR)
  • Allows larger binary size (up to 100 MB uncompressed)
  • Cannot contain URL parameters
  • 由App Store Connect自动为应用演示版本生成
  • 支持所有调用方式,包括物理方式(App Clip Codes、NFC、二维码)
  • 允许更大的二进制大小(未压缩可达100 MB)
  • 不支持URL参数

Advanced App Clip experiences (optional)

高级App Clip体验(可选)

  • Required for: Maps integration, location association, App Clip Codes, per-location card imagery
  • Each experience has its own invocation URL, header image, and metadata
  • URL prefix matching lets one registered URL cover many sub-paths
  • Use the App Store Connect API to manage large numbers of experiences programmatically
  • 适用于:地图集成、位置关联、App Clip Codes、按位置设置卡片图片
  • 每个体验都有独立的调用URL、头部图片和元数据
  • URL前缀匹配可让一个已注册URL覆盖多个子路径
  • 可使用App Store Connect API批量管理大量体验

Associated domains

关联域名

For custom URLs (not the default Apple-generated link), add entries to the Associated Domains entitlement and host an AASA file:
text
appclips:example.com
对于自定义URL(非苹果生成的默认链接),需在Associated Domains权限中添加条目,并托管AASA文件:
text
appclips:example.com

Size Limits

大小限制

App Clip binaries must stay within strict uncompressed size limits (measured via App Thinning Size Report):
iOS VersionMaximum Uncompressed Size
iOS 15 and earlier10 MB
iOS 1615 MB
iOS 17+ (digital invocations only)100 MB
iOS 17+ (via demo link, all invocations)100 MB
The 100 MB limit on iOS 17+ for non-demo links requires: digital-only invocations, no physical invocation support (no App Clip Codes / NFC / QR), and the App Clip must not support iOS 16 or earlier.
Measure size: Archive the app → Distribute → Export as Ad Hoc/Development with App Thinning → check
App Thinning Size Report.txt
.
Use Background Assets to download additional content post-launch (e.g., game levels) if needed. App Clip downloads cannot use
isEssential
.
App Clip二进制文件必须严格遵守未压缩大小限制(通过App Thinning Size Report测量):
iOS版本最大未压缩大小
iOS 15及更早版本10 MB
iOS 1615 MB
iOS 17+(仅数字调用)100 MB
iOS 17+(通过演示链接,所有调用方式)100 MB
iOS 17+中非演示链接的100 MB限制要求:仅支持数字调用,不支持物理调用(无App Clip Codes / NFC / 二维码),且App Clip不支持iOS 16或更早版本。
测量大小:归档应用 → Distribute → 以Ad Hoc/Development方式导出并启用App Thinning → 查看
App Thinning Size Report.txt
如果需要,可使用Background Assets在启动后下载额外内容(如游戏关卡)。App Clip下载不能使用
isEssential

Invocation Methods

调用方式

MethodRequirements
App Clip CodesAdvanced experience or demo link; NFC-integrated or scan-only
NFC tagsEncode invocation URL in NDEF payload
QR codesEncode invocation URL; works with default or advanced experience
Safari Smart BannersAssociate App Clip with website; add
<meta>
tag
MapsAdvanced experience with place association
MessagesShare invocation URL as text; limited preview with demo links
Siri SuggestionsLocation-based; requires advanced experience for location suggestions
Other appsiOS 17+; use Link Presentation or
UIApplication.open(_:)
方式要求
App Clip Codes高级体验或演示链接;支持集成NFC或仅扫描
NFC标签在NDEF payload中编码调用URL
二维码编码调用URL;适用于默认或高级体验
Safari智能横幅将App Clip与网站关联;添加
<meta>
标签
地图关联地点的高级体验
信息应用以文本形式分享调用URL;演示链接支持有限预览
Siri建议基于位置;位置建议需高级体验
其他应用iOS 17+;使用Link Presentation或
UIApplication.open(_:)

Safari Smart App Banner

Safari智能应用横幅

Add this meta tag to your website to show the App Clip banner:
html
<meta name="apple-itunes-app"
      content="app-id=YOUR_APP_ID, app-clip-bundle-id=com.example.MyApp.Clip,
               app-clip-display=card">
在网站中添加以下meta标签以显示App Clip横幅:
html
<meta name="apple-itunes-app"
      content="app-id=YOUR_APP_ID, app-clip-bundle-id=com.example.MyApp.Clip,
               app-clip-display=card">

Data Migration to Full App

向完整应用迁移数据

When a user installs the full app, it replaces the App Clip. Use a shared App Group container to migrate data:
swift
// In both targets: add App Groups capability with the same group ID

// App Clip — write data
func saveOrderHistory(_ orders: [Order]) throws {
    guard let containerURL = FileManager.default.containerURL(
        forSecurityApplicationGroupIdentifier: "group.com.example.myapp.shared"
    ) else { return }

    let data = try JSONEncoder().encode(orders)
    let fileURL = containerURL.appendingPathComponent("orders.json")
    try data.write(to: fileURL)
}

// Full app — read migrated data
func loadMigratedOrders() throws -> [Order] {
    guard let containerURL = FileManager.default.containerURL(
        forSecurityApplicationGroupIdentifier: "group.com.example.myapp.shared"
    ) else { return [] }

    let fileURL = containerURL.appendingPathComponent("orders.json")
    guard FileManager.default.fileExists(atPath: fileURL.path) else { return [] }
    let data = try Data(contentsOf: fileURL)
    return try JSONDecoder().decode([Order].self, from: data)
}
当用户安装完整应用后,它会替代App Clip。使用共享App Group容器迁移数据:
swift
// 在两个目标中:添加App Groups权限并使用相同的组ID

// App Clip —— 写入数据
func saveOrderHistory(_ orders: [Order]) throws {
    guard let containerURL = FileManager.default.containerURL(
        forSecurityApplicationGroupIdentifier: "group.com.example.myapp.shared"
    ) else { return }

    let data = try JSONEncoder().encode(orders)
    let fileURL = containerURL.appendingPathComponent("orders.json")
    try data.write(to: fileURL)
}

// 完整应用 —— 读取迁移的数据
func loadMigratedOrders() throws -> [Order] {
    guard let containerURL = FileManager.default.containerURL(
        forSecurityApplicationGroupIdentifier: "group.com.example.myapp.shared"
    ) else { return [] }

    let fileURL = containerURL.appendingPathComponent("orders.json")
    guard FileManager.default.fileExists(atPath: fileURL.path) else { return [] }
    let data = try Data(contentsOf: fileURL)
    return try JSONDecoder().decode([Order].self, from: data)
}

Shared UserDefaults

共享UserDefaults

swift
// Write (App Clip)
let shared = UserDefaults(suiteName: "group.com.example.myapp.shared")
shared?.set(userToken, forKey: "authToken")

// Read (Full app)
let shared = UserDefaults(suiteName: "group.com.example.myapp.shared")
let token = shared?.string(forKey: "authToken")
swift
// 写入(App Clip)
let shared = UserDefaults(suiteName: "group.com.example.myapp.shared")
shared?.set(userToken, forKey: "authToken")

// 读取(完整应用)
let shared = UserDefaults(suiteName: "group.com.example.myapp.shared")
let token = shared?.string(forKey: "authToken")

Keychain sharing

Keychain共享

Starting iOS 15.4, App Clip keychain items are accessible to the corresponding full app via the
parent-application-identifiers
and
associated-appclip-app-identifiers
entitlements. Use distinct
kSecAttrLabel
values to distinguish App Clip vs. full app entries.
从iOS 15.4开始,App Clip的Keychain条目可通过
parent-application-identifiers
associated-appclip-app-identifiers
权限被对应的完整应用访问。使用不同的
kSecAttrLabel
值区分App Clip与完整应用的条目。

Sign in with Apple

Apple登录

Store the
ASAuthorizationAppleIDCredential.user
in the shared container so the full app can silently verify without re-prompting login.
ASAuthorizationAppleIDCredential.user
存储在共享容器中,以便完整应用无需重新提示登录即可静默验证。

SKOverlay for Full App Promotion

用于推广完整应用的SKOverlay

Display an overlay recommending the full app from within the App Clip:
在App Clip内显示推荐完整应用的浮层:

SwiftUI

SwiftUI

swift
struct OrderCompleteView: View {
    @State private var showOverlay = false

    var body: some View {
        VStack {
            Text("Order placed!")
            Button("Get the full app") { showOverlay = true }
        }
        .appStoreOverlay(isPresented: $showOverlay) {
            SKOverlay.AppClipConfiguration(position: .bottom)
        }
    }
}
swift
struct OrderCompleteView: View {
    @State private var showOverlay = false

    var body: some View {
        VStack {
            Text("订单已提交!")
            Button("获取完整应用") { showOverlay = true }
        }
        .appStoreOverlay(isPresented: $showOverlay) {
            SKOverlay.AppClipConfiguration(position: .bottom)
        }
    }
}

UIKit

UIKit

swift
func displayOverlay() {
    guard let scene = view.window?.windowScene else { return }

    let config = SKOverlay.AppClipConfiguration(position: .bottom)
    let overlay = SKOverlay(configuration: config)
    overlay.delegate = self
    overlay.present(in: scene)
}
SKOverlay.AppClipConfiguration
automatically resolves to the parent app. Available iOS 14.0+.
Never block the user's task to force installation — show the overlay after task completion.
swift
func displayOverlay() {
    guard let scene = view.window?.windowScene else { return }

    let config = SKOverlay.AppClipConfiguration(position: .bottom)
    let overlay = SKOverlay(configuration: config)
    overlay.delegate = self
    overlay.present(in: scene)
}
SKOverlay.AppClipConfiguration
会自动关联到父应用。支持iOS 14.0+。
切勿强制用户安装应用而阻塞其当前任务——应在任务完成后再显示浮层。

Location Confirmation

位置确认

Use
APActivationPayload
to verify a user's physical location without requesting full location access:
swift
import AppClip
import CoreLocation

func verifyLocation(from activity: NSUserActivity) {
    guard let payload = activity.appClipActivationPayload,
          let url = activity.webpageURL
    else { return }

    // Build the expected region (up to 500m radius)
    let center = CLLocationCoordinate2D(latitude: 37.334722, longitude: -122.008889)
    let region = CLCircularRegion(center: center, radius: 100, identifier: "store-42")

    payload.confirmAcquired(in: region) { inRegion, error in
        if let error = error as? APActivationPayloadError {
            switch error.code {
            case .doesNotMatch:
                // URL doesn't match registered App Clip URL
                break
            case .disallowed:
                // User denied location, or invocation wasn't NFC/visual code
                break
            @unknown default:
                break
            }
            return
        }

        if inRegion {
            // Confirmed — user is at the expected location
        } else {
            // User is not at expected location (e.g., NFC tag was moved)
        }
    }
}
Enable location confirmation in
Info.plist
:
xml
<key>NSAppClip</key>
<dict>
    <key>NSAppClipRequestLocationConfirmation</key>
    <true/>
</dict>
This is lightweight — the system verifies location without granting your App Clip continuous access. The App Clip card shows a note that the clip can verify location. Available iOS 14.0+.
使用
APActivationPayload
验证用户的物理位置,无需请求完整位置权限:
swift
import AppClip
import CoreLocation

func verifyLocation(from activity: NSUserActivity) {
    guard let payload = activity.appClipActivationPayload,
          let url = activity.webpageURL
    else { return }

    // 构建预期区域(半径最大500米)
    let center = CLLocationCoordinate2D(latitude: 37.334722, longitude: -122.008889)
    let region = CLCircularRegion(center: center, radius: 100, identifier: "store-42")

    payload.confirmAcquired(in: region) { inRegion, error in
        if let error = error as? APActivationPayloadError {
            switch error.code {
            case .doesNotMatch:
                // URL与已注册的App Clip URL不匹配
                break
            case .disallowed:
                // 用户拒绝位置访问,或调用方式不是NFC/视觉码
                break
            @unknown default:
                break
            }
            return
        }

        if inRegion {
            // 验证通过——用户位于预期位置
        } else {
            // 用户不在预期位置(例如NFC标签被移动)
        }
    }
}
Info.plist
中启用位置确认:
xml
<key>NSAppClip</key>
<dict>
    <key>NSAppClipRequestLocationConfirmation</key>
    <true/>
</dict>
此方式轻量高效——系统会验证位置,但不会授予App Clip持续位置访问权限。App Clip卡片会显示该片段可验证位置的提示。支持iOS 14.0+。

Lifecycle and Ephemeral Nature

生命周期与临时特性

  • No Home Screen icon — App Clips appear in the App Library and recent apps
  • Automatic removal — the system deletes the App Clip and its data after a period of inactivity (typically ~30 days, system-determined)
  • No persistent state guarantee — treat App Clip storage as ephemeral; migrate important data to the shared container or a server
  • Relaunching — returning to a previously launched App Clip from the App Library uses the last invocation URL; returning from the App Switcher launches without an invocation URL (restore saved state)
  • Notifications — App Clips can request ephemeral notification permission (up to 8 hours) via
    Info.plist
    ; set
    NSAppClipRequestEphemeralUserNotification
    to
    true
  • Location access
    requestWhenInUseAuthorization()
    only; resets daily at 4:00 AM
  • 无主屏幕图标——App Clip会出现在资源库和最近使用的应用列表中
  • 自动移除——系统会在一段时间未使用后删除App Clip及其数据(通常约30天,由系统决定)
  • 无持久状态保证——将App Clip存储视为临时存储;重要数据需迁移到共享容器或服务器
  • 重新启动——从资源库返回之前启动的App Clip会使用最后一次调用URL;从应用切换器返回则会无调用URL启动(需恢复保存的状态)
  • 通知——App Clip可通过
    Info.plist
    请求临时通知权限(最长8小时);将
    NSAppClipRequestEphemeralUserNotification
    设为
    true
  • 位置访问——仅支持
    requestWhenInUseAuthorization()
    ;每天凌晨4:00重置权限

Capabilities and Limitations

功能与限制

Available to App Clips

App Clip可用功能

SwiftUI, UIKit, Core Location (when-in-use), Sign in with Apple, Apple Pay, CloudKit (public database read-only, iOS 16+), Background Assets, StoreKit (
SKOverlay
), Keychain, App Groups, Push Notifications (ephemeral), Live Activities (iOS 16.1+)
SwiftUI、UIKit、Core Location(使用时访问)、Apple登录、Apple Pay、CloudKit(仅公共数据库可读,iOS 16+)、Background Assets、StoreKit(
SKOverlay
)、Keychain、App Groups、推送通知(临时)、Live Activities(iOS 16.1+)

Not available / no-op at runtime

不可用/运行时无效果功能

App Intents, Background Tasks, CallKit, Contacts, CoreMotion, EventKit, HealthKit, HomeKit, MediaPlayer, Messages, NearbyInteraction, PhotoKit, SensorKit, Speech, SKAdNetwork, App Tracking Transparency
App Intents、后台任务、CallKit、联系人、CoreMotion、EventKit、HealthKit、HomeKit、MediaPlayer、信息应用、NearbyInteraction、PhotoKit、SensorKit、语音识别、SKAdNetwork、App Tracking Transparency

Additional restrictions

额外限制

  • No background URL sessions
  • No background Bluetooth
  • No multiple scenes on iPad
  • No on-demand resources
  • No custom URL schemes
  • No in-app purchases (reserve for full app)
  • UIDevice.name
    and
    identifierForVendor
    return empty strings
  • 无后台URL会话
  • 无后台蓝牙
  • iPad不支持多场景
  • 无按需资源
  • 无自定义URL scheme
  • 无应用内购买(保留给完整应用)
  • UIDevice.name
    identifierForVendor
    返回空字符串

Common Mistakes

常见错误

Exceeding App Clip size limit

超出App Clip大小限制

swift
// ❌ DON'T: Include large frameworks or bundled assets
// Importing heavyweight frameworks like RealityKit or large ML models
// pushes the App Clip well over 10–15 MB.

// ✅ DO: Use Asset Catalog thinning, exclude unused architectures,
// strip debug symbols, and split shared code into lean Swift packages.
// Measure with App Thinning Size Report after every change.
swift
// ❌ 错误做法:包含大型框架或捆绑资源
// 导入RealityKit等重量级框架或大型机器学习模型
// 会使App Clip大小远超10–15 MB限制。

// ✅ 正确做法:使用资源目录瘦身、排除未使用架构、
// 剥离调试符号,并将共享代码拆分为轻量Swift包。
// 每次修改后通过App Thinning Size Report测量大小。

Not testing invocation URLs locally

未在本地测试调用URL

swift
// ❌ DON'T: Only test App Clip with a direct Xcode launch
// This skips invocation URL handling and misses bugs.

// ✅ DO: Use the _XCAppClipURL environment variable in the scheme,
// or register a Local Experience in Settings → Developer → Local Experiences
// to test with realistic invocation URLs and App Clip cards.
swift
// ❌ 错误做法:仅通过Xcode直接启动测试App Clip
// 这会跳过调用URL处理,导致遗漏bug。

// ✅ 正确做法:在Scheme中使用_XCAppClipURL环境变量,
// 或在设置→开发者→本地体验中注册本地体验,
// 以真实调用URL和App Clip卡片进行测试。

Not handling the full app replacing the App Clip

未处理完整应用替代App Clip的情况

swift
// ❌ DON'T: Assume only the App Clip receives invocations
// When the user installs the full app, ALL invocations go to it.

// ✅ DO: Share invocation-handling code between both targets.
// The full app must handle every invocation URL the App Clip supports.
#if !APPCLIP
// Full app can additionally show richer features for the same URL
#endif
swift
// ❌ 错误做法:假设只有App Clip会收到调用
// 当用户安装完整应用后,所有调用都会转向完整应用。

// ✅ 正确做法:在两个目标间共享调用处理代码。
// 完整应用必须处理App Clip支持的所有调用URL。
#if !APPCLIP
// 完整应用可针对相同URL提供更丰富的功能
#endif

Storing critical data only in App Clip storage

仅在App Clip存储中保存关键数据

swift
// ❌ DON'T: Store important data in the App Clip's sandboxed container
let fileURL = documentsDirectory.appendingPathComponent("userData.json")
// This data is DELETED when the system removes the App Clip.

// ✅ DO: Write to the shared App Group container or sync to a server
guard let shared = FileManager.default.containerURL(
    forSecurityApplicationGroupIdentifier: "group.com.example.shared"
) else { return }
let fileURL = shared.appendingPathComponent("userData.json")
swift
// ❌ 错误做法:将重要数据存储在App Clip的沙箱容器中
let fileURL = documentsDirectory.appendingPathComponent("userData.json")
// 当系统移除App Clip时,这些数据会被删除。

// ✅ 正确做法:写入共享App Group容器或同步到服务器
guard let shared = FileManager.default.containerURL(
    forSecurityApplicationGroupIdentifier: "group.com.example.shared"
) else { return }
let fileURL = shared.appendingPathComponent("userData.json")

Missing associated domains configuration

缺少关联域名配置

swift
// ❌ DON'T: Configure App Clip experiences in App Store Connect
// without setting up associated domains and the AASA file.
// Invocations from your website and advanced experiences will fail.

// ✅ DO: Add the Associated Domains entitlement with:
//   appclips:example.com
// AND host /.well-known/apple-app-site-association on your server:
// {
//   "appclips": {
//     "apps": ["TEAMID.com.example.MyApp.Clip"]
//   }
// }
swift
// ❌ 错误做法:仅在App Store Connect中配置App Clip体验
// 而未设置关联域名和AASA文件。
// 来自网站和高级体验的调用会失败。

// ✅ 正确做法:在Associated Domains权限中添加:
//   appclips:example.com
// 并在服务器上托管/.well-known/apple-app-site-association文件:
// {
//   "appclips": {
//     "apps": ["TEAMID.com.example.MyApp.Clip"]
//   }
// }

Review Checklist

审核检查清单

  • App Clip target bundle ID is a suffix of the full app's bundle ID
  • Parent Application Identifiers
    entitlement is set correctly
  • Shared code uses Swift packages or compilation conditions (
    APPCLIP
    )
  • onContinueUserActivity(NSUserActivityTypeBrowsingWeb)
    handles invocation URLs
  • Full app handles all invocation URLs the App Clip supports
  • App Thinning Size Report confirms binary is within size limits for target iOS
  • Associated Domains entitlement includes
    appclips:yourdomain.com
    (if using custom URLs)
  • AASA file hosted at
    /.well-known/apple-app-site-association
    (if using custom URLs)
  • Default App Clip experience configured in App Store Connect
  • Shared App Group container used for data the full app needs
  • SKOverlay
    /
    appStoreOverlay
    shown after task completion, never blocking
  • NSAppClipRequestLocationConfirmation
    set in Info.plist if using location verification
  • No reliance on background processing, restricted frameworks, or persistent local storage
  • Tested with Local Experiences (Settings → Developer) and
    _XCAppClipURL
    env var
  • Handles launch without invocation URL (App Switcher / notification re-entry)
  • App Clip目标的Bundle ID是完整应用Bundle ID的后缀
  • Parent Application Identifiers
    权限设置正确
  • 共享代码使用Swift包或编译条件(
    APPCLIP
  • onContinueUserActivity(NSUserActivityTypeBrowsingWeb)
    处理调用URL
  • 完整应用处理App Clip支持的所有调用URL
  • App Thinning Size Report确认二进制大小符合目标iOS版本的限制
  • Associated Domains权限包含
    appclips:yourdomain.com
    (使用自定义URL时)
  • 已在
    /.well-known/apple-app-site-association
    托管AASA文件(使用自定义URL时)
  • 已在App Store Connect中配置默认App Clip体验
  • 使用共享App Group容器存储完整应用需要的数据
  • SKOverlay
    /
    appStoreOverlay
    任务完成后显示,绝不阻塞用户操作
  • 如果使用位置验证,已在Info.plist中设置
    NSAppClipRequestLocationConfirmation
  • 未依赖后台处理、受限框架或持久本地存储
  • 使用本地体验(设置→开发者)和
    _XCAppClipURL
    环境变量进行测试
  • 处理无调用URL的启动场景(应用切换器/通知重新进入)

References

参考资料