View in English

  • 打开菜单 关闭菜单
  • Apple Developer
搜索
关闭搜索
  • Apple Developer
  • 新闻
  • 探索
  • 设计
  • 开发
  • 分发
  • 支持
  • 账户
在“”范围内搜索。

快捷链接

5 快捷链接

视频

打开菜单 关闭菜单
  • 专题
  • 相关主题
  • 所有视频
  • 关于

更多视频

大多数浏览器和
Developer App 均支持流媒体播放。

  • 简介
  • 转写文稿
  • 代码
  • 简化 app clip

    App Clips 仿佛订购自己最爱的清凉饮料和支付停车费一般,可以为用户提供一种极具“当下”感的良好体验。我们将为你提供指导方针,并分享一些常用的最优方法,帮你打造焦点突出、一致性强的 App Clips,并教会你如何利用 App Clip的通知与地点位置确认等科技,优化用户的转账体验。此外,我们还将向你展示,如何帮助用户从 App Clip进入你的完整版 app。 为了让本节内容发挥最大作用,建议你先行观看“探索 App Clips”以及“设置并关联你的 App Clips”。

    资源

    • App Clips
    • Choosing the right functionality for your App Clip
    • Fruta: Building a Feature-Rich App with SwiftUI
    • Learn more about creating app clips
    • Responding to invocations
      • 高清视频
      • 标清视频

    相关视频

    WWDC20

    • 一键式帐户安全升级
    • 为其它企业创建 app clip
    • 如何设计最佳 App Clips
    • 探索 App Clips
    • 通过更好的隐私建立信任
    • 配置与链接你的 app clips
    • App 内购买项目的新内容
  • 搜索此视频…

    (你好 WWDC 2020) 大家好 欢迎来到 WWDC (简化 APP CLIP) 大家好 欢迎你们 我叫 Yongjun 是 App Clips 团队的工程师 今天 我的同事 Luming 也会参与进来 来谈谈如何简化你的 app clip 体验 大家都知道 app clip 不过是其中一款 app 使用频率不高 只会在你需要它的时候按需交付

    它们由你注册 为 app clip 体验的 URL 调用

    用户也可以在这次体验中 轻松获得你的 app

    今天我会讲到三个话题 首先 设计和构建 app clip 的最佳做法 然后 我将在 app clip 中 展示一个如何简化交易的例子 最后 我将分享一些技巧 来帮助用户从 app clip 转移到你的 app 中 (最佳做法) 让我们谈谈最佳做法

    App clips 是为速度而设计的 与 App Clip 的互动需要快速和专注

    你的 app clip 应该专注于基本任务 以及手头任务所需的指定功能上

    而对于其它庞大或复杂的功能 请将它们保留在你的 app 内

    当你的 app clip 启动时 该功能应立即可用 包括快速获得初步体验所需的所有资产

    不要包括启动屏幕 也不要让用户等待下载后才开始任务

    创建帐户是一项复杂的任务 需要时间和精力 等到人们完成任务后再让他们注册

    在询问用户数据时 要在需要的时候请求许可 并清楚地说明需求原因

    当用户升级到你的 app 时 就会取代 app clip

    你的 app 应该提供与 app clip 相同的 简化体验

    并且确保你的 app clip 与你的 app 具有相同的名称和图标 这样用户就能有一致的体验

    有关 app clip 设计的更多信息 请查看“设计优秀的 App Clips”系列

    要构建 app clip 你需要在 app 的 Xcode 项目中添加一个 new target (组织项目) 你的 app 已经有了资产和类 其中一些将与你的 app clip 共享 (资产目录 app 图标 - 资产 - 类 - 本地化) 确定体验所需的所有资源 包括在你的 app clip Apple bundle 中

    记住 你的 app clip 越小 它就越快到达你的用户那里 所以只添加你所需要的内容

    对于在 app 和 app clip 中 共同使用的资产 将它们拉入共享资产目录

    组织类和本地化字符串文件 可让你在 app 和 app clip 中共享它们

    “通过 Apple 登录” 是获得用户账号的最佳方式

    如果你的服务支持 无需通过 Apple 登录的 联合登录系统 那么 ASWebAuthenticationSession 是使用第三方服务 以进行身份验证的 一个很好的简捷解决方案 它将用户保留在你的 app clip 中 而且不需要切换到 app

    对于已经拥有你的 app 帐户的用户 你也应该提供用户名 - 密码登录

    App Clip 支持密码自动填充 可轻松进行登录

    如果用户使用密码登录 app clip 考虑在用户获得 app 时 提供通过 Apple 登录升级 (身份验证方面的新功能 最大限度地利用 Apple 登录) 要了解在 app 中 支持用户名和密码登录的最佳方式 请查看“身份验证中的创新” 要了解如何提供通过 Apple 登录 以及强密码升级 请参阅“升级保护帐户安全 以通过 Apple 登录和强密码”系列 (隐私) App clips 是很短暂的 你的用户应能信心满满地试用它们 他们的隐私受到了很好的保护

    某些敏感的用户数据不能用于 app clips 它们并非 app clip 提供的便捷体验 所必需的内容 你可以鼓励用户下载 app 以使用这些功能 App clips 可以请求相机 麦克风和蓝牙的权限

    为了保持快速和精简的体验 当用户获得你的 app 时 我们也会传输这些数据 这样你就无需再次进行请求了 要了解更多关于 app clip 和 app 隐私 请查看“通过更好的隐私建立信任”系列 (简化交易) 我们在日常生活中 经常会使用 iOS 应用去处理交易 一次典型的交易涉及多个步骤 让我举例说明一下 假设我想点一杯奶昔

    我走进一家奶昔店 点击 NFC 标签 一个美食 app clip 就启动了 (请求位置访问) app clip 向我请求获取我的位置权限 以找出我在哪家奶昔店

    (下单) 接下来 app clip 显示了供点餐的菜单

    (支付) 我选择我最喜欢的奶昔 然后付钱 (请求发送通知) 然后 app clip 请求我的许可 给我发个通知 告诉我奶昔什么时候好了 (登录) 最后 这个 app clip 显示注册或登录后能获得折扣

    里面有相当多的步骤 让我们看看如何从这一步改进 到这一步

    首先是 位置 你的 app clip 可以通过 像 NFC 标签这样的物理代码来触发

    在我们的奶昔示例中 NFC 标签中的 URL 告诉我们 它是用于哪个奶昔商店的 这样 你就可以获得商店的位置 显示正确的菜单并接受付款 然而 万一标签 放在了错误的商店怎么办? 或者如果有人故意 在这家店里放了不一样的标签呢? 这可能造成混乱 甚至导致欺诈 为了防止这种情况 你需要知道 当用户扫描标签时 他们是否真的位于商店之内

    为此 你需要获取用户的位置 然后用它来匹配商店的位置 (允许 FRUTA 使用你的位置?) 位置确认显示了刚好足够的信息 来完成这一任务

    你不需要完整位置访问权限 (FRUTA 将能够确认 你的位置 - 关闭) 用户有权在 app clip 卡中允许这样做

    当你的 app clip 接收到 来自物理代码的有效载荷时 你可以询问系统 是否在特定位置获取有效载荷 你将得到二进制的“是”或“否”答案 不需要提示

    要启用位置确认 将 NSAppClipRequestLocation- Confirmation 密钥加到 info.plist 中

    启动 app clip 时 请从 NSUserActivity 获取有效负载

    然后通过坐标和半径 以获取代码的区域 你可以把半径设置到 500 米

    最后 代码为 confirmedAcquired(in: region) API 闭包会告诉你结果 这就是位置确认

    接下来是付款 就像在 app 中一样 你的 app clip 可以使用任何支付方式

    Apple Pay 允许人们 快速、安全地进行购物 无需输入信用卡号码

    它是一个伟大的方式 来加快支付体验

    在用户使用你的 app clip 后 你可以利用通知连接到他们

    要在今天发送通知 首先要请求权限 (“FRUTA”想给你发送 通知 - 不允许 - 允许) 使用 app clip 通知 则可在每次启动后 获得长达 8 小时的许可

    用户可以在 app clip 卡中授予权限 (FRUTA 将能够发送 最长 8 小时的通知) 启动后 即可发送通知 不需要提示 在 App Clip 运行期间 你可以随时请求常规权限 (启用 APP CLIP 通知) 要启用 app clip 通知 就要将 NSAppClipRequestEphemeralUser Notification 密钥添加到 info.plist

    要知道用户 是否在 app clip 卡中授予了权限 可在通知设置中检查“授权 - 状态”

    最后 登录 通过 Apple 登录是创建帐户的 一种私密且方便的方式 或者可使用现有账户登录 如果用户已经拥有一个密码最佳帐户 你还可以使用 AuthenticationServices API 简化登录 甚至无需显示登录屏幕

    当把所有这些改进放在一起时

    这样的交易体验就顺畅多了 (NFC - 订购 - 支付 - 登录) 我的用户拥有 app clip 他们随时都能轻松获取你的 app (将用户转换到你的 APP) iOS 为这种做法提供了充足的机会

    在激活 app clip 后 App 横幅则会立即显示 app 的名称 图标以及 App Store 链接

    点击横幅将用户带到 App Store 在那里他们可以安装你的 app

    用户也可以从 App Clips 设置面板 获取你的 app (你的奶昔准备好了) 你的 app clip 可以在视图中嵌入 StoreKit SKOverlay 我们认为 如果在用户完成任务后能显示覆盖 则效果最好 例如 你可以将其放在付款确认页面旁边

    要将 SKOverlay 添加到 app clip 中 使用 appStoreOverlay 修饰符 与 AppClipConfiguration 进行配置 想要深入了解 SKOverlay 请观看“App 内购买项目的新内容”视频 (使用安全 App Group 在设备上传输数据) 你的 app clip 可能想要传递用户数据 到你的 app 中 如购物清单或订购历史记录 则可使用安全 App Group 来执行此操作

    此安全 App Group 只能在 app clip 和 app 之间访问

    当用户安装你的 app 时 在删除 app clip 后 App Group 会转移到 你的 app 中

    如果用户已经通过 App Group 登录到 app clip 就可以自动登录到 app 做法如下 在你的 app clip 中 当用户通过 Apple 登录时 将 sharedAppGroup 中的用户 ID 保存为文件或数据库

    在用户升级到 app 后 就可从 App Group 读取所保存的用户 ID

    然后使用 iOS 授权 app ID 提供程序验证用户 ID

    要是用户已经登录到 app clip 中 就可让他们无缝登录到 app

    说到这 我想交给 Luming 来为大家演示一下 Luming 到你了 谢谢你 Yongjun 简化 app clip 体验的演讲很精彩 我叫 Luming 是 App Clips 团队的工程师 今天 我将为大家示范 如何简化 App Clips 体验 要是没有顺畅体验 在启动一个 app clip 后 你的用户可能会看到这样的内容 他们必须当场决定是否允许位置访问 以及是否允许通知访问 完全不是流畅的体验 就让我们看看如何简化这些权限请求吧 我们先来看看通知 App clips 可以请求 8 小时的临时通知 而不会发出警报 我打开了 Fruta Xcode 项目 首先看一下 app clip 的 info.plist 我扩展了 NSAppClipDictionary 然后设置 NSAppClip RequestEphemeralUser Notification 的 Boolean 值设置为“是” 现在回到 FrutaClip.swift 在我们请求通知授权之前 我们可以检查 app clip 是否已经被授权为 临时通知状态

    这是 iOS 14 中 为 app clip 引入的新数值 如果我们已经获得临时通知状态 就不需要提示用户发出警报 让我们在设备上构建并安装片段

    (构建成功)

    虽仍然有位置提示 但不再有通知权限的提示了 我们来验证一下 如果转到设置 并查看 Fruta 的通知设置 就会看到一个“将在8小时内关闭”选项 这表示 Fruta app clip 已经被给予 一个 8 小时的临时通知 与物理调用相关联

    真巧啊 看来我的奶昔准备好了 而且临时通知也被确认起作用了 接下来 由于 app clip 可以请求 一次性的位置确认 当通过物理调用方法 如 NFC 或 QR 码启动时 我们来看看它的设置 就像在 info.plist 中的 NSAppClipDictionary 下设置 临时通知一样 我们需要为位置确认做的事情 也非常类似 这一次 我将改为把 NSAppClip RequestLocationConfirmation 的 Boolean 值设置为“是” 然后回到 FrutaClip.swift 我可以删除现有代码 使用核心位置 API 以显式请求位置更新

    由于我已在项目设置中链接了 AppClip.framework 所以我将在这里导入框架

    接下来 在 HandleUserActivity 中 我将获得 app clip 激活有效负载 以及要从 URL 验证的位置纬度和经度

    在这之后 我将实例化我想确认的区域

    然后 我将对有效负载调用 confirmacquestinregion

    然后 要是用户在该地区的话 我将只允许使用 Apple Pay

    我将再次构建并运行 app clip

    (构建成功) 在 Fruta 总部 QR 码发货团队将 Fruta 库比蒂诺市的 QR 码打印输出 与 Fruta 旧金山的 QR 码打印输出 混在了一起 要是没有位置确认 那么毫无戒心的顾客 最终可能会错买了别人的奶昔 幸亏 位置确认能为我们提供防护 让我们看看位置确认 是如何在行动中保护你和你的客户的 我现在就在 Fruta 库比蒂诺市 我会扫描这个属于 Fruta 旧金山的 QR 码

    现在 如果我启动了 app clip 然后尝试订购 你会看到位置正在确认中 而我不被允许支付奶昔 因为我不在旧金山 而 Fruta 商店就在旧金山 (付款被禁用以保护你) 现在 让我们回到 Xcode 并使用 Xcode 模拟我们的设备 就像它在旧金山的中心一样 我们真的在以光速旅行 而且远程传物技术也有很大的进展 让我们再扫描一遍同一个 QR 码

    这次 如果我打开 app clip 就可以照常付款了 (完成) 最后 让我们看看如何将凭据 从 app clip 迁移到完整的 app 正如我的同事 Yongjun 在讲座中所解释的那样 我已经建立了一个安全的群组容器 在 app 和 app clip 之间共享 我将打开 OrderPlaceView.swift

    在通过 Apple 登录成功后 我们就可将授权凭证写入组容器中

    为了方便用户升级到完整的 app 这也是配置 StoreKit 覆盖层的绝佳机会

    并且可在通过 Apple 登录成功后 立即显示出来 而你的用户就完成了一次交易 然后 当我们第一次推出完整的 app 时 我们可以在 frutamodel.swift 中 添加一些代码来迁移凭据

    我只会在构建时迁移帐户信息 不是用于 app clip 而是用于主 app 我们将从组容器中读取保存的用户 ID 实例化一个新的 ASAuthorizationAppleIDProvider 并获取其凭证状态 我们再运行一遍这个片段

    (构建成功) 这次 我要下单

    (谢谢你的订单) 等订单准备了 我就会通过 Apple 登录 (你的奶昔准备好了)

    对于你的用户来说 这是获得完整 app 的大好机会 让他们的登录信息自动迁移过来 所以我们添加了这个 UI SKOverlay 正如 Yongjun 前面所解释的 我们就有了这个

    由于我们刚刚对 app 进行了更改 以处理帐户迁移 目前还没有提交到 App Store 让我们构建并运行 app 来模拟完整 app 的升级 在目标方案选择中 我将选择完整 app 进行构建并在设备上运行它 (构建成功)

    如你所见 我们已自动登录 而我所有的奖赏就在那里等着我 (奖励卡) 现在你已经了解到如何设置临时通知 以及一次性位置确认 以及如何将用户数据从 app clip 迁移到完整的 app 这是我的 “简化你的 app clip 体验”的演示 交回给你了 Yongjun 谢谢你 Luming 太棒了 我学会了如何使用位置确认 以及 app clip 通知 回顾一下 在这段视频中 我们谈到了设计和构建 app clip 的 最佳做法 然后我们在 app clip 中介绍了 如何简化交易 最后 我们还学到了 帮助用户转移到你的 app 的思路 谢谢 我希望你能好好享受 WWDC

    • 7:53 - Confirm a physical code's location.

      import AppClip
      
      guard let payload = userActivity.appClipActivationPayload else {
          return
      }
      
      let region = CLCircularRegion(center: CLLocationCoordinate2D(latitude: 37.3298193,        
          longitude: -122.0071671), radius: 100, identifier: "apple_park")
      
      payload.confirmAcquired(in: region) { (inRegion, error) in
      
      }
    • 9:24 - Query if user has granted app clip notification on app clip card.

      import UserNotifications
      
      let center = UNUserNotificationCenter.current()
      
      center.getNotificationSettings { (settings) in
         if settings.authorizationStatus == .ephemeral {
              // User has already granted ephemeral notification.
          }
      
      }
    • 10:49 - Embed SKOverlay to your app clip

      import SwiftUI
          import StoreKit
      
          struct ContentView : View {
              @State private var finishedPaymentFlow = false
      
              var body: some View {
                  NavigationView {
                      CheckoutView($finishedPaymentFlow)
                  }
                  .appStoreOverlay(isPresented: $finishedPaymentFlow) {
                      SKOverlay.AppClipConfiguration(position: .bottom)
                  }
              }
          }
    • 11:32 - Save user ID in app clip's secure app group.

      // Automatically log in with Sign in with Apple
      import AuthenticationServices
      
      SignInWithAppleButton(.signUp, onRequest: { _ in
      }, onCompletion: { result in
          switch result {
          case .success(let authorization):
              guard let secureAppGroupURL = 
                  FileManager.default.containerURL(forSecurityApplicationGroupIdentifier:
                      "group.com.example.apple-samplecode.fruta")
                  else { return };
              guard let credential = authorization.credential as? ASAuthorizationAppleIDCredential 
                  else { return }
              save(userID: credential.user, in: secureAppGroupURL)
          case .failure(let error):
              print(error)
         }
      })
    • 11:55 - Automatically sign in users to your app if they have signed into your app clip.

      import AuthenticationServices
      
      let provider = ASAuthorizationAppleIDProvider()
      guard let secureAppGroupURL =
          FileManager.default.containerURL(forSecurityApplicationGroupIdentifier:   
              "group.com.example.apple-samplecode.fruta")
          else { return };
      let user = readUserID(in: secureAppGroupURL)
      provider.getCredentialState(forUserID: user) { state, error in
          if state == .authorized {
             loadFavoriteSmoothies(userID: user)
         }
      }

Developer Footer

  • 视频
  • WWDC20
  • 简化 app clip
  • 打开菜单 关闭菜单
    • iOS
    • iPadOS
    • macOS
    • Apple tvOS
    • visionOS
    • watchOS
    打开菜单 关闭菜单
    • Swift
    • SwiftUI
    • Swift Playground
    • TestFlight
    • Xcode
    • Xcode Cloud
    • SF Symbols
    打开菜单 关闭菜单
    • 辅助功能
    • 配件
    • App 扩展
    • App Store
    • 音频与视频 (英文)
    • 增强现实
    • 设计
    • 分发
    • 教育
    • 字体 (英文)
    • 游戏
    • 健康与健身
    • App 内购买项目
    • 本地化
    • 地图与位置
    • 机器学习
    • 开源资源 (英文)
    • 安全性
    • Safari 浏览器与网页 (英文)
    打开菜单 关闭菜单
    • 完整文档 (英文)
    • 部分主题文档 (简体中文)
    • 教程
    • 下载 (英文)
    • 论坛 (英文)
    • 视频
    打开菜单 关闭菜单
    • 支持文档
    • 联系我们
    • 错误报告
    • 系统状态 (英文)
    打开菜单 关闭菜单
    • Apple 开发者
    • App Store Connect
    • 证书、标识符和描述文件 (英文)
    • 反馈助理
    打开菜单 关闭菜单
    • Apple Developer Program
    • Apple Developer Enterprise Program
    • App Store Small Business Program
    • MFi Program (英文)
    • News Partner Program (英文)
    • Video Partner Program (英文)
    • 安全赏金计划 (英文)
    • Security Research Device Program (英文)
    打开菜单 关闭菜单
    • 与 Apple 会面交流
    • Apple Developer Center
    • App Store 大奖 (英文)
    • Apple 设计大奖
    • Apple Developer Academies (英文)
    • WWDC
    获取 Apple Developer App。
    版权所有 © 2025 Apple Inc. 保留所有权利。
    使用条款 隐私政策 协议和准则