Highlight
The third episode of Widget code-along demonstrates handling URLSession within widget extension, using SwiftUI
Linkto jump to App content, usingWidgetBundleto expose multiple widgets, and providing dynamic options for configuration through Intent Extension.
Core Content
Episode 3 continues from a project that already has a basic timeline. The new Leaderboard widget will display roles sorted by health. Problems arise: the widget needs to fetch data, each row needs to jump to the character details in the app, and it also needs to appear in the widget gallery together with the original Ranger Detail widget.
These requirements are stuck at the boundary of widget extension. Network requests cannot be assumed to be taken over by the host App; the clickable area must fall within the widget’s SwiftUI view; there can only be one @main in the same extension. If you directly import the writing methods in the app, developers will quickly encounter these boundaries.
Apple breaks down the boundaries one by one in this code-along: the timeline provider uses a completion handler to support asynchronous requests; the widget itself responds to the URLSession it creates, including the background session; SwiftUI Link can turn a line of widget content into a deep link entry; WidgetBundle is responsible for putting multiple widgets into the same extension; Intent Extension replaces the original hard-coded configuration list with dynamic options.
The end result is a widget that is closer to a real app. It can fetch data, jump to specified content, provide multiple entries in an extension, and allow the configuration list to follow changes in remote data.
Detailed Content
1. Get data in widget extension
(01:28) The Leaderboard widget’s data comes from the loadLeaderboardData asynchronous request on CharacterDetail. The transcript clearly states that the timeline provider API uses a completion handler to make asynchronous tasks such as network fetch easy to access.
There are no public Code tab snippets for this session. Only the calling forms that appear in the transcript are retained below, and the business implementation is not completed.
CharacterDetail.loadLeaderboardData
URLSession
data task
Key points:
loadLeaderboardDatais an asynchronous entry of Leaderboard data.- The timeline provider relies on completion handlers to wait for asynchronous tasks to complete.
- session is demonstrated in a normal in-process URL session.
- This request uses a local file to simulate remote fetch; in actual projects, remote Web service is usually called.
(02:20) The background session has a special point in the widget: it will not start the extension’s hosting app when it is completed. Widget will respond to all URLSession created by itself, including background session.
onBackgroundURLSessionEvents
sessionIdentifier
completion block
Key points:
onBackgroundURLSessionEventsis a modifier on the widget configuration.- It corresponds to common application delegate callback responsibilities in Apps.
- The system provides
sessionIdentifierand completion block. - transcript only explains that the management method is the same as in the App, and does not expand on the specific queue or persistence strategy.
2. Use SwiftUI Link to jump within the widget
(03:20) Each row in the Leaderboard is a HStack in AllCharactersView. The goal is to directly open the character’s information page when clicking on a character.
Link(destination: character.url) {
HStack {
...
}
}
Key points:
Linkis the new SwiftUI API named in the session.destinationuses the role’s own URL.- The original
HStackstill holds the contents of this line. - When you click on a widget row, the system will highlight the row and open the corresponding character details.
3. Use WidgetBundle to expose multiple widgets
(04:36) There are Leaderboard widget and Ranger Detail widget in the project, but there can only be one @main in a process. The solution is to move @main from a single widget to a bundle.
@main -> WidgetBundle
WidgetBundle -> Leaderboard widget
WidgetBundle -> Ranger Detail widget
Key points:
WidgetBundleis used to declare multiple widgets in the same extension.@mainis placed on the bundle instead of on two widgets separately.- The result of the demonstration in the session is that both the Leaderboard widget and the Ranger Detail widget appear in the widget gallery.
- This structure is suitable for an App to provide multiple information entrances.
4. Use Intent Extension to provide dynamic configuration options
(05:31) The previous episode already had configurable widgets, but the list of options was hardcoded. In the third episode, the parameter type of SiriKit intent is changed to custom type, and the dynamic list is provided by Intent Extension.
IntentHandler
identifier
displayString
CharacterDetail.remoteCharacters
Intent identifier -> characterFromName
Key points:
- Custom intent type has two attributes:
identifieranddisplayStringby default. - These values come from
IntentHandler. - The option providing process is also called asynchronously, similar to the timeline method.
- Add
CharacterDetail.remoteCharactersto the option list in session to simulate obtaining more characters from the network. - When the widget reads the user’s selection, it uses the intent identifier to retrieve the corresponding role.
(08:01) The configuration interface finally appears with the original options Power Panda, Egghead, and Spouty, and the remote options Mr. Spook, Cake, and Octo. After the user selects Mr. Spook, a widget on the Home Screen displays the character.
Core Takeaways
1. Make a remote ranking widget
- What to do: Put the server leaderboard on the Home Screen and sort by latest score or status.
- Why it’s worth doing: session clearly demonstrates that the Leaderboard widget obtains the role list through an asynchronous request.
- How to start: First connect the timeline provider to the existing fetch method; if the request may be completed in the background, then connect
onBackgroundURLSessionEventson the widget configuration.
2. Make a clickable list widget
- What to do: Let each row of the widget open the corresponding details page in the app.
- Why it’s worth doing: session demonstrates wrapping
HStackinto SwiftUILinkand pointing the destination to the role URL. - How to start: Prepare a URL for each entity in the list, using
Link(destination:)outside the widget row.
3. Use one extension to provide multiple widgets
- What: Provides both overview widgets and detail widgets.
- Why it’s worth doing: The session demonstrates that the Leaderboard widget and the Ranger Detail widget enter the widget gallery at the same time through
WidgetBundle. - How to start: Move
@maintoWidgetBundleand list multiple widgets in the bundle body.
4. Configure server-side driven widgets
- What: Let users see the latest projects, devices, roles, or people they follow when configuring the widget.
- Why it’s worth doing: session extends the hard-coded list into dynamic options through Intent Extension.
- How to start: Change the intent parameters to custom type, return options with
identifieranddisplayStringinIntentHandler, and retrieve the entity through identifier in the widget.
Related Sessions
- Widgets Code-along, part 1: The adventure begins — Start by creating a widget project, provider, and basic timeline.
- Widgets Code-along, part 2: Alternate timelines — Continue to talk about timeline, system intelligence, multiple widget families and configurations.
- Build SwiftUI views for widgets — Talk about how to use SwiftUI to build glanceable views suitable for widgets.
- Add configuration and intelligence to your widgets — Dive into capabilities related to configurable widgets, Siri suggestions, and Smart Stack.
- Design great widgets — Complete widget design principles from the perspective of content, color, size, layout and typography.
Comments
GitHub Issues · utterances