大多数浏览器和
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
-
下载
(你好 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) } }
-
-
正在查找特定内容?在上方输入一个主题,就能直接跳转到相应的精彩内容。
提交你查询的内容时出现错误。请检查互联网连接,然后再试一次。