WWDC Quick Look 💓 By SwiftGGTeam
Build light and fast App Clips

Build light and fast App Clips

观看原视频

Highlight

Apple 在 iOS 15 中为 App Clip 提供了更严格的体积限制和更丰富的发现场景,开发者需要通过系统化的体积优化策略、正确的元数据配置以及位置验证 API,确保用户能在扫描 App Clip Code 或访问网页时即时获得轻量体验。

核心内容

体积限制是硬门槛

App Clip 的核心价值在于”即时可用”。用户扫描一个二维码或轻触 NFC 标签,几秒内就要进入功能界面。这个体验承诺背后有一个硬性约束:体积必须足够小,才能在移动网络下快速下载。

Apple 对 App Clip 的体积有明确限制。开发过程中需要反复验证,避免到了提交审核时才发现超标。Xcode 提供了生成体积报告的功能,可以导出每个设备变体的 IPA 文件,查看未压缩大小。

从 Fruta 样本看优化路径

演讲者用一个修改过的 Fruta 示例演示了完整的优化流程。这个示例故意放大了体积,用来展示常见的”陷阱”。

生成体积报告后,发现所有设备变体的大小都差不多。这说明 app thinning 没有生效,资源文件可能以非最优方式打包。

解压 IPA 检查内容,发现几个问题:

  • 图片以独立 bundle 资源形式存在,没有放进 Asset Catalog
  • 包含了一个文档 zip 和 README 文件
  • 链接了一个不必要的框架
  • 本地化文件夹可能包含冗余内容

基础优化步骤

检查编译优化设置

确保 Archive 构建使用 Release 配置,且优化级别设置为默认的”最小体积、最快速度”。

使用 Asset Catalog

Asset Catalog 有两个好处:

  1. Xcode 构建时自动优化媒体资源
  2. 支持 App Thinning,用户只下载适合其设备的资源变体

将 App 和 App Clip 共享的图片放入共享的 Asset Catalog,仅 App 使用的图片放入独立的 Catalog,并从 App Clip 目标中排除。

清理不必要的文件

用 Target Membership 编辑器排除 README、文档 zip 等不属于安装产物的文件。

精简代码

检查 Build Phases 中的源文件列表,移除 App Clip 不需要的功能模块。Fruta 示例中,recipe 和 rewards 功能属于完整 App,可以从 Clip 目标中移除。

管理本地化字符串

创建专门的字符串文件供 App Clip 使用,避免包含完整 App 的所有本地化内容。

高级优化策略

评估外部依赖

App Clip 应该只链接必要的框架。优先使用系统内置框架:

  • Sign in with Apple 替代自定义登录
  • Apple Pay 替代自建支付
  • NSURLSession 处理网络请求
  • RealityKit / Metal 处理 3D 图形

图片格式选择

  • 需要透明度或高频细节(锐利边缘):用 PNG
  • 非摄影类素材:尝试 PNG8,可大幅减小体积
  • 摄影类素材:用 JPEG,适当提高压缩比
  • 图标和界面控件:用 SVG 格式,或使用 SF Symbols

SF Symbols 提供了 2000 多个可配置符号,支持多种字重和尺寸,自动与文本标签对齐,且原生支持动态字体。

// [14:18](https://developer.apple.com/videos/play/wwdc2021/10013/?time=858)
label.text = "Hello"

let textStyle = UIFont.TextStyle.largeTitle

label.font = .preferredFont(forTextStyle: textStyle)
let config = UIImage.SymbolConfiguration(textStyle: textStyle)

imageView.image = UIImage(systemName: "pencil.and.outline", withConfiguration: config)

// Align baseline of text and symbol image
imageView.firstBaselineAnchor.constraint(equalTo: label.firstBaselineAnchor).isActive = true

关键点:

  • UIFont.TextStyle.largeTitle 同时用于标签字体和符号配置
  • UIImage.SymbolConfiguration(textStyle:) 让符号与文本使用相同尺寸体系
  • firstBaselineAnchor 约束确保符号和文本基线对齐

运行时构建变体

不要为同一素材的多种展示形式准备多张图片。用一个基础图片,在运行时通过代码构建不同变体。

延迟加载

如果优化后仍超标,考虑从 CDN 延迟加载部分资源。App Clip 中打包低分辨率占位图,启动后用 AsyncImage 逐步替换为高分辨率版本。

确保 App Clip 正确展示

元数据配置

在 App Store Connect 中,每个 App Clip 必须有一个默认体验(Default Experience),用于 Safari 和 Messages 中的展示。如需支持二维码、NFC、App Clip Code 等物理调用方式,还需添加高级体验(Advanced Experience)。

配置更改需要时间传播到设备,不会立即生效。

网页 Meta Tag

在网页的 <head> 中添加正确的 meta tag,才能触发 App Clip 卡片展示。

<!-- [18:08](https://developer.apple.com/videos/play/wwdc2021/10013/?time=1088) -->
<meta name="apple-itunes-app" content="app-id=myAppStoreID, app-clip-bundle-id=appClipBundleID, app-clip-display=card">

关键点:

  • app-id:App Store ID
  • app-clip-bundle-id:App Clip 的 bundle ID
  • app-clip-display=card:以卡片形式展示

验证 Universal Links 关联

调用域名必须通过 Associated Domains entitlements 和 AASA 文件与 App / App Clip 建立安全关联。配置错误会导致 App Clip 无法展示。

排查常见问题

如果 Safari 中看不到 App Clip 卡片:

  1. 检查 meta tag 语法
  2. 确认 app-clip-bundle-id 正确
  3. 验证网页 URL 与 App Clip 体验的关联配置
  4. 检查 entitlements 中的 Associated Domains
  5. 确认 AASA 文件可访问且格式正确

App Clip 专属功能

位置验证

App Clip 可以通过 APActivationPayload 验证用户是否位于特定地理区域,适用于需要确认到店场景的应用。

// [27:41](https://developer.apple.com/videos/play/wwdc2021/10013/?time=1661)
if let activationPayload = userActivity?.appClipActivationPayload {
  activationPayload.confirmAcquired(in: region) { inRegion, error in
    if let error = error as? APActivationPayloadError {
      if error.code == APActivationPayloadError.disallowed {
        // User denied permission
        // Or invocation was not from visual code or NFC
      } else if error.code == APActivationPayloadError.doesNotMatch {
        // Activation payload is not the most recent
        // Catch in testing. Handle as above.
      }
    } else if error == nil {
      // Platform was able to determine location
      // OK to check inRegion
    }
  }
}

关键点:

  • confirmAcquired(in:) 验证用户是否通过视觉码或 NFC 在指定区域内激活
  • disallowed 错误表示用户拒绝权限或调用方式不符合要求
  • doesNotMatch 错误表示激活载荷已过期,测试中需要捕获
  • 成功回调中 inRegion 参数指示用户是否在区域内

测试建议

  • 使用 Network Link Conditioner 在不同带宽条件下测试
  • 验证 App Clip 在慢速网络下仍能在合理时间内完成任务
  • 测试位置验证的各种边界情况

详细内容

生成体积报告的完整流程

  1. 选择完整 App scheme
  2. Product > Archive
  3. Organizer 中点击 Distribute App
  4. 选择 Development
  5. 选择 App Clip 目标
  6. App Thinning 下拉菜单选择 All compatible device variants
  7. 确保 Rebuild from bitcode 已勾选
  8. 导出后打开 App Thinning Size Report.txt
  9. 查看每个设备变体的未压缩大小

检查 IPA 内容

# 将 .ipa 重命名为 .zip 并解压
mv AppClip.ipa AppClip.zip
unzip AppClip.zip

# 查看 Payload 内容
cd Payload/AppClip.app
ls -la

关注以下内容:

  • .bundle 中的独立图片资源
  • 不必要的文档文件
  • 未使用的框架
  • 过大的本地化文件夹
  • 可执行文件大小

Asset Catalog 分离策略

SharedAssets.xcassets    # App 和 Clip 共享
AppOnlyAssets.xcassets   # 仅 App 使用

在 Target Membership 中排除 AppOnlyAssets.xcassets 的 App Clip 成员资格。

图片优化检查清单

场景推荐格式备注
需要透明度PNG无损压缩
非摄影类、颜色少PNG8大幅减少体积
摄影类、可接受有损JPEG调整压缩比
图标、控件SVG / SF Symbols矢量,任意尺寸

核心启发

1. 为线下场景设计即时体验

  • 做什么:为餐厅、零售店、停车场等线下场景创建 App Clip,用户扫码即可点餐、支付、取车
  • 为什么值得做:App Clip 消除了下载完整 App 的摩擦,转化率远高于传统方式
  • 怎么开始:在 Xcode 中添加 App Clip target,配置 Associated Domains,实现核心任务流程

2. 用 SF Symbols 替代自定义图标

  • 做什么:将界面中的自定义图标全部替换为 SF Symbols
  • 为什么值得做:SF Symbols 内置于系统,不增加 App Clip 体积,且自动支持动态字体和深色模式
  • 怎么开始:浏览 SF Symbols app 选择合适的符号,使用 UIImage(systemName:) 加载

3. 实现基于位置的验证

  • 做什么:为到店服务添加地理位置验证,确保用户确实在门店附近
  • 为什么值得做:防止远程滥用,为商家提供更可信的用户到店数据
  • 怎么开始:使用 APActivationPayload.confirmAcquired(in:) API,传入 CLRegion

4. 构建渐进式资源加载

  • 做什么:App Clip 中打包低质量占位资源,启动后从 CDN 加载高清版本
  • 为什么值得做:突破体积限制的同时保证最终体验质量
  • 怎么开始:使用 SwiftUI 的 AsyncImage 或 UIKit 的异步图片加载方案

5. 建立体积监控流程

  • 做什么:在 CI 流程中加入 App Clip 体积检查,每次提交自动验证
  • 为什么值得做:避免临近发布时才发现体积超标,减少紧急优化风险
  • 怎么开始:编写脚本调用 xcodebuild archive,解析 Size Report,设置阈值告警

关联 Session

评论

GitHub Issues · utterances