版本记录
| 版本号 | 时间 |
|---|---|
| V1.0 | 2020.11.18 星期三 |
前言
App Clips是2020年WWDC新推出的功能,它的功能非常强大,因为它使没有您的应用程序的用户仍可以使用其功能。 从订购咖啡到停车,App Clips有很多很好的用途。 下面我们就一起学习和看一下。感兴趣的可以看下面几篇文章。
1. App Clips详细解析(一) —— 基本概览(一)
开始
首先看下主要内容:
就是一起设计和实现
App Clips,内容来自翻译。
接着看下写作环境:
Swift 5, iOS 14, Xcode 12
下面就是正文啦
在2020年苹果全球开发者大会(WWDC)上,苹果发布了App Clips:较小的按需版本的应用程序,允许用户执行特定任务。
App Clips功能非常强大,因为它们使没有您的应用程序的用户仍然可以使用其功能。从订购咖啡到停车,App Clips有很多很好的用途。更好的是,App Clips提供了发现新应用的绝佳方法!
在本教程中,您将为SwiftyLemonade创建一个App Clip体验,SwiftyLemonade是一个简单的应用程序,可让您使用App Clip购买柠檬水。在此过程中,您将学到:
- What an App Clip is.
- How to add an App Clip target.
- How to share assets and code.
- About App Clip experiences and how to make one.
- How to confirm a user’s location using the Location Confirmation API.
- Working with App Clip notifications.
注意:本教程假定您了解
SwiftUI的基础知识。如果您不熟悉SwiftUI,请先查看SwiftUI: Getting Started tutorial。
注意:您必须安装
Xcode 12才能遵循本教程。您可以在本教程的大部分内容中使用模拟器,但是要测试Location Confirmation API,则需要一台运行iOS 14的设备。为此,您需要先在Starter应用中更新bundle ID,然后才能开始按照本教程的说明进行操作。
打开入门项目。 在入门项目中,您会找到SwiftyLemonade,该应用程序显示了各大Major League Soccer (MLS)体育场上柠檬水摊位的列表。构建并运行以检出该应用程序:

该应用程序显示了位于各个MLS体育场的Swifty柠檬水摊位的列表。 您还可以将一个摊位标记为喜欢,并在单独的标签中查看收藏夹列表:

要收藏柠檬水摊位,请长按列表中的一个项目:

在这里,您可以选择柠檬水摊位,并订购Swifty著名的柠檬水之一。 这对足球迷来说是一个真正的打击:

在Xcode中,查看将要处理的主要文件:
-
LemonadeStand.swift包含一个代表柠檬水摊位的
struct以及要在应用程序中显示的一系列摊位。 -
Lemonade.swift包含代表柠檬水的
struct和两个菜单数组。 - MenuList.swift显示所选柠檬水摊位的柠檬水菜单。
- DetailView.swift显示所选柠檬水的详细信息。
- StandList.swift显示一个可供选择的柠檬水摊位列表。 在这里,您可以长按收藏夹或取消收藏。
-
StandTabView.swift是一个
TabView,用于显示柠檬水摊位或标记为收藏的柠檬水摊位的完整列表。 -
LemonadeStandLocations是一个
Swift软件包,其中包含Swifty Lemonade摊位的位置。
在本教程中,您将构建一个App Clip,将您带到LA Galaxy菜单购买柠檬水。

What Exactly Is an App Clip?
App Clip是应用程序的轻量级版本,它使用户无需安装完整版本的应用程序即可执行特定任务。这使用户可以在需要时立即访问应用的正确部分。要启动App Clip,请扫描NFC标签,QR码或App Clip代码。此流程称为App Clip experience。
如果用户安装了您的应用程序,则App Clip体验将充当该应用程序的切入点。例如,Coffee特许经营应用程序可能会具有App Clip体验,在扫描时会转到您所在的咖啡店的菜单。或者,如果未安装该应用程序,则会从App Store下载相关的App Clip卡。然后将App Clip Card呈现给用户,以启动此流程。作为开发人员,您可以使用App Store Connect配置App Clip Card,但请记住:它们需要一个主应用程序。
注意:如果您想了解有关配置
App Clip的启动体验的更多信息,请查阅Apple’s documentation on Configuring Your App Clip’s Launch Experience。
Adding an App Clip Target
首先,将App Clip target添加到项目中,并将其命名为SwiftyLemonadeClip:

确保将Interface设置为SwiftUI,将Life Cycle设置为SwiftUI App。 然后,在出现提示时单击Activate。 一个名为SwiftyLemonadeClip的新组被添加到Project导航器中:

此外,Xcode为您的App Clip设置名称和bundle identifier。 您可能会注意到,bundle identifier以.Clip作为扩展名:

现在,您已经添加了App Clip target,现在该进行测试了。 构建并运行:

哇! 这里没有太多的事情。 在下一部分中,您将学习如何在app和App Clip target之间共享代码和资源。
Sharing Assets and Code Between Targets
设置好项目后,您就可以开始从App到App Clip共享资源和代码了!
注意:
App Clip和App可以共享很多内容,但不应共享敏感信息。 如果您想了解有关将数据提供给App Clip的相应App的信息,请查阅Apple’s Documentation。
1. Sharing Code and Assets
由于App Clips是主App的轻量级版本,因此将存在依赖性。 返回Xcode,单击SwiftyLemonadeClip target,然后在Frameworks,Libraries, and Embedded Content部分中将LemonadeStandLocations Swift软件包添加为依赖项。 您的App Clip现在可以访问柠檬水摊位的位置:

接下来,共享一些Swift文件。 App Clips将需要了解有关柠檬水摊位的信息。 在项目导航器中单击LemonadeStand.swift,然后在文件检查器中更新target membership,以包括SwiftyLemonadeClip:

完成此操作后,您应该看到很多error:

不用担心! 添加剩余的依赖项后,这些错误将消失。
就像对LemonadeStand.swift一样,更新以下文件的target membership:
- Lemonade.swift
- MenuList.swift
- DetailView.swift
- OrderPlacedView.swift
- StandList.swift
- Assets.xcassets in the SwiftyLemonade group
很好! 没有更多的错误!
Designing the App Clip Experience
App Clip experience是使用URL调用应用程序的切入点。 一个应用程序可能具有许多导致特定任务的App Clip体验URL。 在本教程中,您将在Swifty的一个柠檬水摊位上启动一个App Clip体验URL,其中显示了下订单的菜单。
首先,在SwiftyLemonadeClip下创建一个新的Swift文件,并将其命名为SwiftyLemonadeClipModel.swift。 禁用SwiftyLemonade target,因为新文件只需要对您的App Clip可用:

然后,在SwiftyLemonadeClipModel.swift中,在import Foundation下添加以下代码:
class SwiftyLemonadeClipModel: ObservableObject {
@Published var selectedStand: LemonadeStand?
}
在这里,您创建了一个符合ObservableObject的SwiftyLemonadeClipModel类。 您还添加了@Published属性,以将选定的摊位通知您的App Clip。
接下来,必须在SwiftyLemonadeClipApp.swift中实例化模型。 将以下属性添加到该结构体:
@StateObject private var model = SwiftyLemonadeClipModel()
现在,您必须将此属性提供给App Clip的子视图。 仍在SwiftyLemonadeClipApp.swift中,将body替换为以下内容:
var body: some Scene {
WindowGroup {
//1
ContentView()
.environmentObject(model)
}
}
在上面的代码中,将model设置为环境对象,使其可用于ContentView视图子层次结构。 接下来,您将确定要选择clip的正确摊位。
1. Getting App Clip Experience Data
数据通过App Store Connect中的注册URL传递到App Clip。 注册URL不在本教程的讨论范围之内,但这并不意味着您是失败的团队! 要从URL获取数据,您必须配置App Clip才能这样做。
首先,单击Signing & Capabilities选项卡下的SwiftyLemonadeClip target,然后添加一个名为appClips:swiftyLemonade.example的新Associated Domain:

接下来,App Clip必须解释数据。 返回SwiftyLemonadeClipApp.swift,将body替换为以下内容以从URL获取查询项:
var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(model)
.onContinueUserActivity(
NSUserActivityTypeBrowsingWeb,
perform: handleUserActivity) //1
}
}
// 2
func handleUserActivity(_ userActivity: NSUserActivity) {
//3
guard
let incomingURL = userActivity.webpageURL,
let components = URLComponents(
url: incomingURL,
resolvingAgainstBaseURL: true),
let queryItems = components.queryItems
else {
return
}
//4
guard
let latValue = queryItems.first(where: { $0.name == "lat" })?.value,
let lonValue = queryItems.first(where: { $0.name == "lon" })?.value,
let lat = Double(latValue),
let lon = Double(lonValue)
else {
return
}
//5
print("Latitude: \(lat), Longitude: \(lon)")
}
主要做了这些:
- 1) 注册
NSUserActivityTypeBrowsingWeb的处理程序。当iOS遇到App Clip experience URL时,它将调用此处理程序。 - 2) 处理
URL数据。 - 3) 仅当存在包含
queryItems的URL时才继续执行 - 4) 检查是否存在名为
lat和lon的queryItems,并将它们分配给latValue和lonValue。这些项目代表关联的柠檬水摊位的经度和纬度。如果这些值不存在,则对于此App Clip体验无效。这些值是String类型的,您可以将它们转换为Double类型。 - 5) 将
lat和lon值打印到控制台。
2. Simulating a Clip Launch
要对此进行测试,请创建启动URL。这使您可以模拟从App Clip experience URL启动App Clip。要创建一个,将活动scheme设置为SwiftyLemonadeClip。然后,编辑scheme并通过单击复选框启用_XCAppClipURL环境变量。最后,将其值设置为https://swiftyLemonade.example.com/order?lat=33.8644&lon=-118.2611,如下所示:

您添加的URL的查询参数是lat和lon,它们的值表示柠檬水摊位的纬度和经度。
现在,构建并运行。 您会看到纬度和经度值已打印到控制台:

3. What Lemonade Stand Is This?!
是时候找到离您最近的柠檬水摊位了。 返回SwiftyLemonadeClipApp,在import SwiftUI下,添加以下内容:
import CoreLocation
接下来,在handleUserActivity(_ :)中,用以下代码替换先前添加的print():
//1
let location = CLLocationCoordinate2D(
latitude: CLLocationDegrees(lat),
longitude: CLLocationDegrees(lon))
//2
if let stand = standData.first(where: { $0.coordinate == location }) {
model.selectedStand = stand
//3
print("Welcome to \(stand.title)! :]")
}
这段代码:
- 1) 使用从URL获得的
lat和lon值创建一个CLLocationCoordinate2D变量 - 2) 查询
standData以查找具有匹配位置的第一个值。 如果找到位置,则将其设置为SwiftyLemonadeClipModel中的selectedStand。 - 3) 将
stand名称打印到控制台
要进行检查,请构建并运行并查看打印到控制台的欢迎消息:

您已将App Clip配置为从URL获取数据!

4. Ordering Some Lemonade
现在该为SwiftyLemonade创建App Clip体验了。 在本部分中,您将采用所选的stand并显示其相关菜单。 然后,用户将能够订购一些柠檬水。
首先,在SwiftyLemonadeClip下,打开ContentView.swift。 在ContentView中添加以下属性:
@EnvironmentObject private var model: SwiftyLemonadeClipModel
在这里,您已经添加了先前创建的模型作为环境对象。
接下来,将body替换为以下内容:
var body: some View {
//1
if let selectedStand = model.selectedStand {
//2
NavigationView {
//3
MenuList(stand: selectedStand)
}
}
}
这段代码:
- 1) 检查模型是否具有
selectedStand。 - 2) 添加以
MenuList作为根视图的导航层次结构。 - 3) 实例化
selectedStand的MenuList以显示菜单项列表。
要检查这一点,构建并运行:

现在,您已将模型链接到内容视图,用户可以通过扫描Swifty's LA Galaxy Lemonade Stand上的URL代码订购柠檬水。 App Clip体验应专注于特定任务,例如订购柠檬水。 因此,请注意屏幕底部缺少tab bar,并且没有可供选择的stands列表:

5. Can’t Find a Lemonade Stand?
如果该应用找不到某个位置的柠檬水架怎么办? 向用户显示消息会很好。 打开SwiftyLemonadeClipModel.swift并添加以下属性:
@Published var locationFound = true
此属性跟踪应用程序是否找到柠檬水摊位。 默认情况下是true的,因为它很可能会找到柠檬水摊位。
接下来,打开SwiftyLemonadeClipApp,并在handleUserActivity(_ :)中,在可选绑定代码之后添加else子句,以找到柠檬水摊位:
else {
model.locationFound = false
}
如果该位置没有柠檬水摊位,请将locationFound设置为false。 您还可以根据需要删除print语句,这仅用于调试。
现在,回到SwiftyLemonadeClip下的ContentView.swift,将以下内容添加到body的末尾:
if model.locationFound == false {
Text("Error finding stand.")
}
如果附近没有摊位,则会显示一条好消息。
要对此进行测试,请更新_XCAppClipURL以包含无效的纬度。 将值设置为https://swiftyLemonade.example.com/order?lat=33.8644&lon=0。
构建并运行以查看错误消息:

很好!现在,您已经更新了App Clip,以处理无效的柠檬水摊位。在继续之前,请将_XCAPPClipURL更改回有效URL:https://swiftyLemonade.example.com/order?lat=33.8644&lon=-118.2611。
为了结束本节,您添加了一个App Clip体验,该体验通过使用URL作为启动参数来启动。该URL提供您所处柠檬水摊位的位置,并显示其菜单。您可以从这里下订单。
但是,如果配送中心发生混乱,并且将错误的标签发送到错误的柠檬水摊位,该怎么办?您可能会在其他摊位订购柠檬水!或更糟糕的是,如果有人在商店放置了无效的标签进行欺诈,该怎么办?为避免这种情况,Apple引入了一个新的轻量级Location Confirmation API,您将在下一节中对其进行了解。
Setting up Location Confirmation
苹果与App Clip一起,引入了Location Confirmation API。该框架提供了足够的信息来验证调用的App Clip是否在预期的位置。Location Confirmation API的工作原理是将App Clip的激活负载与用户的位置进行比较。
注意:您需要至少运行
iOS 14的设备来测试位置确认API。在模拟器上,您只会在控制台中看到一条错误消息。
在SwiftyLemonade中,如果您不在正确的位置,则将禁用下订单的选项。为此,请打开SwiftyLemonadeClipModel.swift并添加以下属性:
@Published var paymentAllowed = true
此属性确定用户是否可以订购柠檬水。
要设置位置确认,请打开App Clip的Info.plist。 单击App Clip键旁边的显示三角形,以显示Requests location confirmation键。 将其值更改为YES:

接下来,打开SwiftyLemonadeClipApp.swift,并在import CoreLocation下添加以下代码:
import AppClip
这使您可以访问App Clip有效负载信息以验证用户的位置。
现在,在SwiftyLemonadeClipApp.swift的handleUserActivity(_ :)底部添加以下内容:
//1
guard let payload = userActivity.appClipActivationPayload else {
return
}
//2
let region = CLCircularRegion(
center: location,
radius: 500,
identifier: "stand_location"
)
//3
payload.confirmAcquired(in: region) { inRegion, error in
//4
guard error == nil else {
print(String(describing: error?.localizedDescription))
return
}
//5
DispatchQueue.main.async {
model.paymentAllowed = inRegion
}
}
这段代码:
- 1) 通过启动
App Clip获取有效载荷信息。 如果不存在,请停止执行。 - 2) 使用URL中找到的位置创建一个具有
500米圆形边界的区域。Core Location使用国际单位制作为距离。 如果您不习惯使用这些单位,那么一米就不止一码了。 - 3) 检查是否在
region内激活了App Clip - 4) 如果有
error,请将其记录到控制台进行调试。 - 5)
inRegion指示是否在正确的位置调用了App Clip。 使用此值启用或禁用付款。
注意:如果您想了解
App Clips Activation负载,请查看关于APActivationPayload的Apple’s Documentation。
1. Using Custom Flags
接下来,如果用户不在预期的位置,则禁用下订单的功能。 打开在SwiftyLemonade下的Views组中找到的DetailView.swift。 此视图允许您订购柠檬水。 添加以下代码:
@EnvironmentObject private var model: SwiftyLemonadeClipModel
此代码使DetailView.swift可以访问App Clip的模型。 但是该模型在SwiftyLemonade target中不可用。 如果选择此scheme并尝试构建您的应用程序,则会看到以下错误:

要解决此问题,请使用Swift Compilation Flag将此代码包装在有条件的代码中。 打开您的App Clip target的Build Settings,然后将自定义标志APPCLIP添加到Debug和Release schemes中:

返回到DetailView.swift,使用自定义标志将model包装在条件中:
#if APPCLIP
@EnvironmentObject private var model: SwiftyLemonadeClipModel
#endif
现在,选择App Clip scheme时使用条件中的代码将只编译。 编译应用程序,看看错误消失了!
接下来,App Clip应显示一条警告,提示您付款被禁用。 为此,请在条件之外添加一个属性:
@State private var showWarningAlert = false
此属性确定是否显示警告弹窗。
2. Disabling Ordering
接下来,在placeOrder()内部,在orderPlaced = true之前添加以下代码:
//1
#if APPCLIP
//2
guard model.paymentAllowed else {
//3
showWarningAlert = true
return
}
#endif
这段代码:
- 1) 仅当
scheme中存在自定义标志时,才在条件条件内执行代码。 - 2) 检查
paymentAllowed是否为true。 这意味着App Clip可以下订单。 - 3) 如果不允许付款,则将
showWarningAlert设置为true,并且不执行placeOrder()中的其余代码。
3. Showing an Alert
要在调用placeOrder()时显示alert,请在sheet视图修饰符的右括号后添加以下代码到正文中:
//1
.alert(isPresented: $showWarningAlert) {
//2
Alert(
title: Text("Payment Disabled"),
message: Text("The QR was scanned at an invalid location."),
dismissButton: .default(Text("OK"))
)
}
这段代码:
- 1) 如果
showWarningAlert设置为true,则发出alert - 2) 将
alert配置为具有标题,消息和关闭按钮。 此alert警告用户不允许付款。
您可以再测试一步。 除非您居住在洛杉矶银河系所在地Dignity Health Sports Park 500米范围内,否则您将需要在设备上模拟自己的位置。 这样一来,您无需在Swifty的Lemonade Stand附近就可以订购柠檬水。
4. Simulating Location
要模拟在洛杉矶银河体育场的身影,请在SwiftLemonadeClip组中创建一个GPX文件,并将其命名为LaGalaxy.gpx。 确保选择SwiftLemonadeClip target:

打开LaGalaxy.gpx并将其内容替换为以下内容:
<?xml version="1.0"?>
<gpx version="1.1" creator="Xcode">
<wpt lat="33.8644" lon="-118.2611">
<name>Dignity Health Sports Park</name>
<time>2014-09-24T14:55:37Z</time>
</wpt>
</gpx>
您添加的代码代表Dignity Health Sports Park的GPS坐标。
5. Putting it all Together
最后,要测试每种情况,在构建和运行应用程序时必须设置默认位置。 为此,您必须编辑App Clip的scheme并设置默认位置。
首先,在您不在预期位置的地方测试错误流。 要设置默认位置,请选择SwiftyLemonadeClip scheme,然后选择Edit Scheme:

现在该检查一下您添加的漂亮的错误alert了。 构建并运行该应用程序,然后尝试下订单:

接下来是时候模拟在洛杉矶了。返回并编辑scheme,并将默认位置设置为您先前创建的GPX文件:

现在,在设备中设置了体育场的GPS坐标后,您应该可以订购一些柠檬水了。 构建并运行:

恭喜你! 您已使用Location Confirmation API来验证用户的位置并防止下错订单。
如果柠檬水准备好时能收到通知,那不是很好吗? 这样,您就可以观看比赛而不会错过任何动作。 当短暂的通知在这里时,请不要担心!
Using Ephemeral Notifications
像主应用程序一样,App Clip可以接收通知。 通过在订单准备就绪时通知您,这些可以为App Clip增添巨大价值。 App Clip只能在启动后的很短时间内(最多八个小时)接收通知。
打开您的App Clip的Info.plist并启用临时通知-它与位置确认权限位于同一位置:

这将启用App Clip的通知,但用户可以选择加入App Clip Card。 结果,在SwiftyLemonadeClipApp.swift中,在handleUserActivity(_ :)下面添加以下代码:
func requestNotificationAuthorization() {
//1
let notifCenter = UNUserNotificationCenter.current()
notifCenter.getNotificationSettings { setting in
//2
if setting.authorizationStatus == .ephemeral {
return
}
//3
notifCenter.requestAuthorization(options: .alert) { result, error in
print("""
Authorization Request result: \(result) \
- \(String(describing: error))
""")
}
}
}
这段代码:
- 1) 检索应用程序的通知设置
- 2) 检查是否已授权该应用接收短暂通知。 如果已经授予访问权限,则无需继续。 但是,如果未授予访问权限,则再次请求它。
最后,尽管仍在SwiftyLemonadeClipApp.swift中,将以下代码添加到body的末尾。 确保它出现在WindowGroup的右括号内:
//1
.onAppear {
requestNotificationAuthorization()
}
出现此视图时,此代码调用requestNotificationAuthorization()。
启用通知后,您现在无需错过所有足球比赛。
注意:如果您想了解有关
App Clip通知的更多信息,请查阅 Apple’s Documentation或我们的Push Notifications Tutorial。
在本教程中,您学习了如何:
- 1) Add an App Clip target
- 2) Share assets and code
- 3) Use the Location Confirmation API to verify you are at the correct location
- 4) Set up App Clip notifications
如果您喜欢本教程,请查看SwiftUI by Tutorials.。 您将深入研究如何使用简洁的声明性语言来定义应用程序的UI,以及告别大量令人困惑的UIKit代码。
如果您想了解有关App Clip的更多信息,请查阅 Apple’s Documentation。
后记
本篇主要讲述了
App Clips的一个简单示例,感兴趣的给个赞或者关注~~~
