WidgetKit for Apps

Praveen Bhaskar
7 min readOct 19, 2020

Let’s learn how WidgetKit leverages the power of SwiftUI

Build your WidgetKit!

In my previous post, we have discussed about what is Widget, how a widget works, and some of the guidelines to follow. Now let’s start implementing the widgetKit to make our app more interesting.

Add WidgetKit Extension to your project
File > New >Target or view your project click on + to add a new target, search for WidgetKit and select WidgetKit Extension, click next to add the ProductName for WidgetKit, you will have an option to check or to uncheck the include configuration intent (by default the intent will be checked, which will create an Intent Configuration with intentDefinition file, if you want a Static Configuration uncheck the option) and click Finish. The pop up will be a trigger to Activate “ProductNameExtension” scheme, click the Activate to use this scheme for building and debugging.

Widget Extension

In the .swift file of Widget folder, you will find a struct that conforms to Widget protocol and @main property wrapper on top of it which is an entry point for the widget. The body has a WidgetConfiguration to define either Static/ Intent Configuration. I have developed a sample Covid19 app for demo purpose,

Widget Static Configuration

So here I used Static configuration, which will show static data not configured or customised by the users. The display name and description are to show on the Widget Gallery, where user can Add widgets to the Home screen. Another modifier is to support families, we can pass the different sizes we want in our application.

Static configuration timeline provider

The provider is nothing but a TimelineProvider, that is responsible to give a placeholder, snapshot, and timeline. The data to be passed should conform to TimelineEntry protocol, CovidEntry is the struct here which leads to TimelineEntry protocol that contains Date*, new cases, country and total cases.

Placeholder: Returns the timeline entry which will be shown as Placeholder view.
Snapshot: This method is called by the system when it want us to return an entry as quickly as possible without performing any heavy operation. For example, the view shown in a Widget Gallery.
Timeline: Timelines are a combination of a view and date, which says at what time a particular view should be shown. Basically this timeline handles the WidgetKit refresh policy. The widgets wont run constantly in the background, instead it has 3 types of TimeLineReloadPolicy; atEnd, never and after.
atEnd: A policy that specifies that WidgetKit requests a new timeline after the last date in a timeline passes.
never: A policy that specifies that the app prompts WidgetKit when a new timeline is available.
after: A policy that specifies a future date for WidgetKit to request a new timeline.

Even from the main app, you can reload all the timelines or specific widget with help of WidgetCenter shared instance. For example, your app may receive a background notification, or a user may make a change in the app itself.

WidgetCenter.shared.reloadTimelines(ofKind: “com.mygame.gamestatus”)
WidgetCenter.shared.reloadAllTimelines()
Widget Intent Configuration

In the above pic, for the same example, I just replaced from Static to Indent configuration, a widget with user-configurable and you can see extra parameter to define the Intent. This custom intent is created in intentdefinition file, the same mechanism that Siri Suggestions and Siri Shortcuts use for customising those interactions.

Configuration on Intent Definition file
In this file, make sure the title, description, and the checkbox of Intent is eligible for widgets is checked. You can add the parameter and configure the details to it. For a static list, create an Enum type and add properties to it. These options will be shown to the users on the Edit Widget screen.

Widget Intent definition file with Static list

Now let’s get into a dynamic list, for example, I want to show the list of countries dynamically pulled from the server. So to provide dynamic data, I created custom intent Covid19DynamicType and a new Type called Country. In the Intent editor, select the item in the parameter and check Options are provided dynamically. If you want to enable the search option for the list to be shown, we have an option to check the Intent handler provides search result as the user types.

Widget Intent definition file with dynamic list

WidgetKit loads the intent extension to provide the dynamic data, add an Intent Extension; Choose File > New > Target, and choose the Intent extension. Click Next > enter the name for Intent extension and click finish. Xcode will create a IntentHandler.swift file that contains a class named IntentHandler. Based on indent file, Xcode generates a IntentHandling Protocol (Covid19DynamicTypeIntentHandling). To extend the Intent handler to conforms InExtension and Intent Handling protocols. The provideCountryOptionsCollection(for: searchTerm: with:) method is used to get the dynamic data and when a user does a search this method will be called and return INObjectCollection to its completion handler. Once the user edits the widget and selects a character, the next step is to incorporate that choice into the widget’s display.

Intent Timeline Provider

The Intent Configuration uses IntentTimelineProvider to manage the timeline events for the widgets. After user edits, widgetkit passes the configured value to the getTimeline(for configuration: …) requesting for new timeline entries. In this example, the user lookup for other countries COVID 19 statistics and updates the widgetkit with appropriate content.

WidgetKit Entry View
The UI content of the WidgetKit will be initiated in WidgetConfiguration content handler. You have to pass the timeline entry to display their information in Widget. We can use WidgetFamily environment value to understand the current widget configuration’s size and present respective views.

Widget EntryView

Placeholder View
SwiftUI provides a new modifier called .redacted(reason: .placeholder) , which is used to show the text and image in faded rectangle view.

Placeholder view

Multiple Widgets
To support multiple widget, use WidgetBundle protocol and pass all the available Widgets in the body with function builder @WidgetBundleBuilder. Make sure you move the @main property wrapper to top of the WidgetBundle to consider as an entry point.

Widget Bundle

You can also change the Accent Color and Widget background color of the Widgets from assets option.

Smart Stack
Smart Stacks are a collection of widgets that will automatically rotate to show the right widget at the top and you can also swipe through the widgets. Apple used on-device intelligence to help show the right thing at the top of the stack.

But as a developer, you can help drive this using Siri Shortcuts donations. There’s also a specific WidgetKit API to help the system figure out when your widget will be more relevant, or when something else might be. To enable this feature, check the Intent is eligible for Siri Suggestion from intent definition file.

So for example, if a thunderstorm is happening, your widget can inform the system that has a highly relevant update, and the system will consider surfacing your widget to the top of the stack.

Deep linking
Widgets are designed to support multiple interactions with a deep link into your app. By default when you click the widget it will launch the app without any deeplinks. But if you want to open any specific view then go for the below options;

.widgetURL(_ url: URL?) will make your whole widget clickable and will deep-link to the specified URL.

.Link(destination: URL) to wrap some content into a clickable deep link. This helps when we have multiple options to show in medium and large size Widgets.

Covid 19 Statistic WidgetKit

Conclusion

Finally, we learned about Widgets; How SwiftUI makes the widget more powerful and lightweight on serialising the view and rendering them. Keep your widgets simple and with few interactions, avoid creating a cluttered appearance. Make you application more interesting with Widgets and have fun, you can find COVID 19 WidgetKit project on Github.

Resources

--

--