{"id":13694117,"url":"https://github.com/apple/sample-backyard-birds","last_synced_at":"2025-10-24T12:24:16.184Z","repository":{"id":173399838,"uuid":"642222388","full_name":"apple/sample-backyard-birds","owner":"apple","description":null,"archived":false,"fork":false,"pushed_at":"2023-12-11T19:30:26.000Z","size":3617,"stargazers_count":575,"open_issues_count":2,"forks_count":52,"subscribers_count":26,"default_branch":"main","last_synced_at":"2025-04-04T12:08:53.773Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Swift","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/apple.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-05-18T05:00:17.000Z","updated_at":"2025-03-24T10:53:27.000Z","dependencies_parsed_at":null,"dependency_job_id":"fc1584e6-a070-4cad-85b4-b643ddcc1fa9","html_url":"https://github.com/apple/sample-backyard-birds","commit_stats":null,"previous_names":["apple/sample-backyard-birds"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apple%2Fsample-backyard-birds","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apple%2Fsample-backyard-birds/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apple%2Fsample-backyard-birds/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apple%2Fsample-backyard-birds/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/apple","download_url":"https://codeload.github.com/apple/sample-backyard-birds/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247280272,"owners_count":20912967,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-02T17:01:24.775Z","updated_at":"2025-10-24T12:24:16.108Z","avatar_url":"https://github.com/apple.png","language":"Swift","readme":"# Backyard Birds: Building an app with SwiftData and widgets\n\nCreate an app with persistent data, interactive widgets, and an all new in-app purchase experience.\n\n## Overview\n\nBackyard Birds offers a rich environment in which you can watch the birds that visit your backyard garden. \nYou can monitor their water and food supply to ensure they always have fresh water and plenty to eat, \nor upgrade the game using an in-app purchase to provide tastier food for the birds to eat.\n\n The sample implements its data model using [SwiftData](https://developer.apple.com/documentation/swiftdata) \n for persistence, and integrates seamlessly with SwiftUI using the [`Observable`](https://developer.apple.com/documentation/observation) protocol. \n The game's widgets implement [App Intents](https://developer.apple.com/documentation/AppIntents) for interactive and configurable widgets. The in-app purchase experience uses the [`ProductView`](https://developer.apple.com/documentation/storekit/productview) \n and [`SubscriptionStoreView`](https://developer.apple.com/documentation/storekit/subscriptionstoreview) from StoreKit.\n\nYou can access the source code for this sample\non [GitHub](https://github.com/apple/sample-backyard-birds).\n\n- Note: This sample code project is associated with WWDC23 session 102:\n[State of the Union](https://developer.apple.com/wwdc23/102/).\n\n## Configure the sample code project\n\nTo configure the Backyard Birds app to run on your devices, follow these steps:\n\n1. Open the project in Xcode 15 or later.\n2. Edit the multiplatform target's scheme, and on the Options tab, choose the `Store.storekit` file for StoreKit configuration.\n3. Repeat the previous step for the watchOS target's scheme.\n4. Select the top-level Backyard Birds project.\n5. For all targets, choose your team from the Team menu in the Signing \u0026 Capabilities pane so Xcode can automatically manage your provisioning profile.\n\n## Create a data-driven app\n\nThe app defines its data model by conforming the model objects to [`PersistentModel`](https://developer.apple.com/documentation/swiftdata/persistentmodel) \nusing the [`Model`](https://developer.apple.com/documentation/swiftdata/model()) macro. \nUsing the [`Attribute`](https://developer.apple.com/documentation/swiftdata/attribute(_:originalName:hashModifier:)) macro \nwith the [`unique`](https://developer.apple.com/documentation/swiftdata/schema/attribute/option/unique) \noption ensures that the `id` property is unique.\n\n``` swift\n@Model public class BirdSpecies {\n    @Attribute(.unique) public var id: String\n    public var naturalScale: Double\n    public var isEarlyAccess: Bool\n    public var parts: [BirdPart]\n    \n    @Relationship(deleteRule: .cascade, inverse: \\Bird.species)\n    public var birds: [Bird] = []\n    \n    public var info: BirdSpeciesInfo { BirdSpeciesInfo(rawValue: id) }\n    \n    public init(info: BirdSpeciesInfo, naturalScale: Double = 1, isEarlyAccess: Bool = false, parts: [BirdPart]) {\n        self.id = info.rawValue\n        self.naturalScale = naturalScale\n        self.isEarlyAccess = isEarlyAccess\n        self.parts = parts\n    }\n}\n```\n\n## Construct interactive widgets\n\nBackyard Birds displays interactive widgets by presenting a ``Button`` to refill a backyard's supplies \nwhen the water and food are running low. The app does this by placing a `Button` in the widget's view, \nand passing a `ResupplyBackyardIntent` instance to the\n [`init(intent:label:)`](https://developer.apple.com/documentation/swiftui/button/init(intent:label:)) initializer:\n\n``` swift\nButton(intent: ResupplyBackyardIntent(backyard: BackyardEntity(from: snapshot.backyard))) {\n    Label(\"Refill Water\", systemImage: \"arrow.clockwise\")\n        .foregroundStyle(.secondary)\n        .frame(maxWidth: .infinity)\n        .padding(.vertical, 8)\n        .padding(.horizontal, 12)\n        .background(.quaternary, in: .containerRelative)\n}\n```\n\nThe app allows for configuration of the widget by implementing the \n [`WidgetConfigurationIntent`](https://developer.apple.com/documentation/appintents/widgetconfigurationintent)\n  protocol:\n\n``` swift\nstruct BackyardWidgetIntent: WidgetConfigurationIntent {\n    static let title: LocalizedStringResource = \"Backyard\"\n    static let description = IntentDescription(\"Keep track of your backyards.\")\n    \n    @Parameter(title: \"Backyards\", default: BackyardWidgetContent.all)\n    var backyards: BackyardWidgetContent\n    \n    @Parameter(title: \"Backyard\")\n    var specificBackyard: BackyardEntity?\n    \n    init(backyards: BackyardWidgetContent = .all, specificBackyard: BackyardEntity? = nil) {\n        self.backyards = backyards\n        self.specificBackyard = specificBackyard\n    }\n    \n    init() {\n    }\n    \n    static var parameterSummary: some ParameterSummary {\n        When(\\.$backyards, .equalTo, BackyardWidgetContent.specific) {\n            Summary {\n                \\.$backyards\n                \\.$specificBackyard\n            }\n        } otherwise: {\n            Summary {\n                \\.$backyards\n            }\n        }\n    }\n}\n```\n\n## Provide a new in-app purchase experience\n\nThe sample app uses [`ProductView`](https://developer.apple.com/documentation/storekit/productview) to display several different bird food upgrades available for purchase on a store shelf. \nTo prominently feature an in-app purchase item, the app uses the\n [`.productViewStyle(.large)`](https://developer.apple.com/documentation/storekit/productview/4202371-productviewstyle) modifier:\n\n``` swift\nProductView(id: product.id) {\n    BirdFoodProductIcon(birdFood: birdFood, quantity: product.quantity)\n        .bestBirdFoodValueBadge()\n}\n.padding(.vertical)\n.background(.background.secondary, in: .rect(cornerRadius: 20))\n.productViewStyle(.large)\n```\n\nThe Backyard Birds Pass page displays renewable subscriptions using the\n [`SubscriptionStoreView`](https://developer.apple.com/documentation/storekit/subscriptionstoreview) view. \n The app uses the `PassMarketingContent` view as the content of the `SubscriptionStoreView`:\n\n``` swift\nSubscriptionStoreView(\n    groupID: passGroupID,\n    visibleRelationships: showPremiumUpgrade ? .upgrade : .all\n) {\n    PassMarketingContent(showPremiumUpgrade: showPremiumUpgrade)\n        #if !os(watchOS)\n        .containerBackground(for: .subscriptionStoreFullHeight) {\n            SkyBackground()\n        }\n        #endif\n}\n```\n\n","funding_links":[],"categories":["Sample"],"sub_categories":["RSS"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fapple%2Fsample-backyard-birds","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fapple%2Fsample-backyard-birds","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fapple%2Fsample-backyard-birds/lists"}