Backyard Birds:使用 SwiftData 和小部件构建应用程序
Backyard Birds:使用 SwiftData 和小部件构建应用程序
创建具有持久数据、交互式小部件和全新应用内购买体验的应用。
概述
Backyard Birds 提供了一个丰富的环境,您可以在其中观看访问您后院花园的鸟类。您可以监控它们的水和食物供应,以确保它们始终有淡水和充足的食物,或者使用应用程序内购买升级游戏,为鸟类提供更美味的食物。
该示例使用SwiftData实现其数据模型
以实现持久性,并使用该协议与 SwiftUI 无缝集成Observable
。游戏的小部件为交互式和可配置的小部件实施App Intents 。应用内购买体验使用ProductView
和SubscriptionStoreView
来自 StoreKit。
您可以在GitHub上访问此示例的源代码。
配置示例代码项目
要将 Backyard Birds 应用配置为在您的设备上运行,请执行以下步骤:
- 在 Xcode 15 或更高版本中打开项目。
- 编辑多平台目标的方案,然后在“选项”选项卡上,选择
Store.storekit
用于 StoreKit 配置的文件。 - 对 watchOS 目标的方案重复上一步。
- 选择顶级 Backyard Birds 项目。
- 对于所有目标,从 Signing & Capabilities 窗格中的 Team 菜单中选择您的团队,以便 Xcode 可以自动管理您的配置文件。
创建数据驱动的应用程序
该应用程序通过使模型对象符合PersistentModel
使用Model
宏来定义其数据模型。Attribute
将宏与选项一起使用unique
可确保该id
属性是唯一的。
@Model public class BirdSpecies {
@Attribute(.unique) public var id: String
public var naturalScale: Double = 1
public var isEarlyAccess: Bool
public var parts: [BirdPart]
@Relationship(.cascade, inverse: \Bird.species)
public var birds: [Bird]
@Transient
public var info: BirdSpeciesInfo { BirdSpeciesInfo(rawValue: id) }
public init(info: BirdSpeciesInfo, naturalScale: Double = 1, isEarlyAccess: Bool = false, parts: [BirdPart]) {
self.id = info.rawValue
self.naturalScale = naturalScale
self.isEarlyAccess = isEarlyAccess
self.parts = parts
}
}
构建交互式小部件
Backyard Birds 显示交互式小部件,方法Button
是在水和食物不足时重新填充后院的供应品。该应用程序通过Button
在小部件的视图中放置一个并将ResupplyBackyardIntent
实例传递给
init(intent:label:)
初始化程序来完成此操作:
Button(intent: ResupplyBackyardIntent(backyard: BackyardEntity(from: snapshot.backyard))) {
Label("Refill Water", systemImage: "arrow.clockwise")
.foregroundStyle(.secondary)
.frame(maxWidth: .infinity)
.padding(.vertical, 8)
.padding(.horizontal, 12)
.background(.quaternary, in: .containerRelative)
}
该应用程序允许通过实施
WidgetConfigurationIntent
协议来配置小部件:
struct BackyardWidgetIntent: WidgetConfigurationIntent {
static let title: LocalizedStringResource = "Backyard"
static let description = IntentDescription("Keep track of your backyards.")
@Parameter(title: "Backyards", default: BackyardWidgetContent.all)
var backyards: BackyardWidgetContent
@Parameter(title: "Backyard")
var specificBackyard: BackyardEntity?
init(backyards: BackyardWidgetContent = .all, specificBackyard: BackyardEntity? = nil) {
self.backyards = backyards
self.specificBackyard = specificBackyard
}
init() {
}
static var parameterSummary: some ParameterSummary {
When(\.$backyards, .equalTo, BackyardWidgetContent.specific) {
Summary {
\.$backyards
\.$specificBackyard
}
} otherwise: {
Summary {
\.$backyards
}
}
}
}
提供全新的应用内购买体验
该示例应用程序用于ProductView
显示商店货架上可供购买的几种不同的鸟食升级。为了突出显示应用内购买项目,该应用使用修饰符
.productViewStyle(.large)
:
ProductView(id: product.id) {
BirdFoodProductIcon(birdFood: birdFood, quantity: product.quantity)
.bestBirdFoodValueBadge()
}
.padding(.vertical)
.background(.background.secondary, in: .rect(cornerRadius: 20))
.productViewStyle(.large)
Backyard Birds Pass 页面使用该
SubscriptionStoreView
视图显示可续订的订阅。该应用程序使用PassMarketingContent
视图作为内容SubscriptionStoreView
:
SubscriptionStoreView(
groupID: passGroupID,
visibleRelationships: showPremiumUpgrade ? .upgrade : .all
) {
PassMarketingContent(showPremiumUpgrade: showPremiumUpgrade)
#if !os(watchOS)
.containerBackground(for: .subscriptionStoreFullHeight) {
SkyBackground()
}
#endif
}