WWDC Quick Look 💓 By SwiftGGTeam
Widgets Code-along, part 3: Advancing timelines

Widgets Code-along, part 3: Advancing timelines

Watch original video

Highlight

The third episode of Widget code-along demonstrates handling URLSession within widget extension, using SwiftUI Link to jump to App content, using WidgetBundle to 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:

  • loadLeaderboardData is 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:

  • onBackgroundURLSessionEvents is a modifier on the widget configuration.
  • It corresponds to common application delegate callback responsibilities in Apps.
  • The system provides sessionIdentifier and 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.

(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:

  • Link is the new SwiftUI API named in the session.
  • destination uses the role’s own URL.
  • The original HStack still 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:

  • WidgetBundle is used to declare multiple widgets in the same extension.
  • @main is 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: identifier and displayString by default.
  • These values ​​come from IntentHandler.
  • The option providing process is also called asynchronously, similar to the timeline method.
  • Add CharacterDetail.remoteCharacters to 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 onBackgroundURLSessionEvents on 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 HStack into SwiftUI Link and 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 @main to WidgetBundle and 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 identifier and displayString in IntentHandler, and retrieve the entity through identifier in the widget.

Comments

GitHub Issues · utterances