Reading Time: 9 minutes

On the Android platform, widgets have been there for ages. Widgets on Android are interactive mini-apps or extensions of a larger app. For example, you can display the weather overview, a mini music player on the phone’s home page, or an interactive background.

With iOS 14, Apple finally introduced widgets to their platform. However, unlike Android, the devices on iOS are static and will only display relevant information to the user. There is no kind of interaction, animation, or input.

As stated on the Apple website, widgets display glanceable relevant information from an app. Widgets allow users to open the related app for more details quickly. An app can provide multiple customizable widgets with each their unique look, layout, and information. For example, you can display the latest news in a list or display a calendar, but interactive mini-apps, such as a media player, are not supported.

Overall, a widget can add to your overall app experience, hopefully triggering users to open your app more often.

This blog post goes into the basic setup of a widget on iOS.

Basic Setup

We first need to build a super simple news app to get started. In this case, it will be a list of news items retrieved from NewsAPI.org. The final result will be a news list displayed in a widget. Code will be shared between the widget and the real app.

1. Create a simple app to get started

Boot up Xcode and create an App project. Make sure SwiftUI is enabled.

If you run this app, it will display a content view with “Hello world” in it.

widgets in swift egeniq
making widgets in swift egeniq

2. Create an Account on NewsAPI.org

In order to create the datasets and retrieve the data, we need an account on NewsAPI.org. So visit the website, create an account and get the API key.

3. Setup the dataset

On NewsAPI.org, take note of the following JSON:

Copy to Clipboard

Basically NewsAPI will return a list of articles containing the following:

– A status
– Number results
– The articles

This can all be mapped to a struct. So create the following file and fill in the following:

Copy to Clipboard

By complying to Codable, this makes it possible for the JSONDecoder to map the JSON to the struct later on when using the API Service.

Of course this also means we need to map the articles to a struct. The articles array inside of the list, have the following JSON.

Copy to Clipboard

This can all be mapped to a struct. To create the following file and fill in the following:

Copy to Clipboard

The Identifiable protocol is needed for the list view, we will be using the title as an ID for now.

API service

In order to retrieve the data from News API, we need a simple API service which will retrieve the JSON and convert it to a Codable Dataset. So create the following:

Copy to Clipboard

In general, this simple class will try to retrieve the data and convert it to our Codable models.

The architecture and setup of the news app

For this example, we will be using a simple MVVM architecture with some Redux properties. For that, we create a view model for retrieving the data from News API with an observable state, which will contain the data.

So add a new file to the project and name it view model and fill in the following code:

Copy to Clipboard

In this class, we have an observable state, in which a subscriber can figure out which state ViewModel is in.

The Constants enum will contain one of the example URLs of NewsAPI.org and uses categories for filtering.
Please make sure to fill in your API key into the Constants enum before running this code.

ViewModel will have different observable states. This can be `loading` in which case it tries to retrieve the data. Or it can be success, in which case the ViewModel has retrieved a dataset, or it can have the error state.

When using this class and calling the getDataIfNeeded method, the ViewModel will automatically retrieve the JSON from NewsAPI.org and convert it to `NewsArticle`-models. These models can then be used to populate the view.

The getDataIfNeeded method also has functionality for filtering based on category.

In order to use this class, the view needs to have ViewModel as an observable object and the view needs to call the getDataIfNeeded() method upon viewAppear or on pull-to-refresh.

Modify the ContentView to the following code:

Copy to Clipboard
how to make widgets swift egeniq

Setup of the Widget

If everything went well and the News app is displaying a list of NewsArticles it is time to add the widget.

Go to targets and add the ‘Widget Extension’, give it a name and make sure to activate the scheme

swift and widgets egeniq

You will end up with a new directory in your project which contains the Widget classes you’ll need:

– The Widget main class (MyWidget.swift)
– IntentDefinition
– Info.plist
– Resources

widget files in swift

widget files in swift egeniq

widget files in swift egeniq

6.2

If you run the widget scheme, the simulator will now display a simple time widget.

starting swift widgets egeniq

6.3

For now, we only need to check the main Widget Swift file. We will get back later to the IntentDefinition.
The widget code looks like this:

Copy to Clipboard

How do widgets work?

Widgets work using a timeline. The timeline is visible inside of the ‘Provider struct’.
The timeline can be best described as a card deck, in which iOS will just grab and display the next card on top and discard the previous card after a certain amount of time. Each item in the timeline object is an entry that contains data and a date. The data is the information displayed to the user and the date is the position on the timeline. The timeline also contains a refresh policy. This can be either ‘never’, ‘at the end’ when the widget has processed and displayed all the data on the timeline or after a ‘certain date’.

To display the timeline entry, there is an ‘entry-view’, which is the content.

Other methods such getSnapshot and placeholder are used for the iOS configuration flow or when displaying the widget in its initial state.

For our example we will use only one entry which will be a list of news article titles and we will refresh once every 15 minutes.

Configuring the widget to display news items

o in order to get our news data into the widget extension we will be needing to add the news classes to the widget extension.
For the following classes, go to the inspector and add the classes to the widget target.

– NewsArticle
– NewsArticleList
– ViewModel
– APIService

how to make swift widgets

Now your app code is shared with the widget which allows us to use them in the widget.

Adjusting the news app classes

Since widgets are static and the OS is responsible for updating them, we cannot use ObservedObjects inside of them. We need to modify the ViewModel, so a widget is able to retrieve the data correctly.

Modify the ViewModel as follows:

Copy to Clipboard

By adding a completion handler to getDataIfNeeded method, we should be able to get the data without observing a property.
Create the following struct for the NewsEntry.

Copy to Clipboard

This will be our entry which will be placed into the timeline. In general we have multiple states.
For the placeholder and the getSnapshot we will be using the idle state. This state is a neutral state when there isn’t any data downloaded yet.
The success state will be displaying the news articles and the error state will display an error in the widget when something went wrong.
Since widgets are static and relatively small, we also want to limit the number of articles to a maximum of 4.

Update the provider code to the following

Copy to Clipboard

As seen above, the viewModel has been added as an object and will retrieve the data set. As for placeholder and getSnapshot, both will set an idle state. Notice that in the timeline method, the articles will be limited to a max of 4 and that, when something goes wrong, an error entry will be injected. Also notice that the timeline refresh policy will update after 15 minutes.

Implementing the widget view

Modify the WidgetEntryView so it looks like this:

Copy to Clipboard

9.1

Now the widget will render the news item as a list. It will also handle the different states of the entry.
However, this code will not run or render properly. The reason is that the text might be too large for the widget and we might want to support only one or two sizes. For this update the Main Widget Struct and the preview:

Copy to Clipboard

9.2

Build and run your widget extension project.

Congrats, you got your first simple widget working!

IntentDefinition adding widget configuration

Each widget has a backside which can be used to configure the widget. Setting this up is easy.

First open your MyWidget.intentdefinition. In the IntentDefinition edit screen, click on the small plus sign at the bottom left corner. Select enum and name it Category.

Now we are going to map the enum from our viewModel to the IntentDefinition, so we can apply a query filter to our widget.
Add the following cases to the enum:

– general
– business
– entertainment
– health
– science
– sports
– technology

making of swift widgets

Great now we have an enum, but we also need to add it to the IntentDefinition as a property. For that, while on the IntentDefinition edit screen, click on configuration.
In the configuration screen of the IntentDefinition, add a property named category and make sure it uses the just created enum as a ‘Type’.

swift widgets egeniq

Now compile your app and widget by running build, but do not run it yet.

Now navigate to the getTimeline function of the IntentTimelineProvider class. Notice that the configuration (ConfigurationIntent) object has a new property, named category. Now this can be used as a filter for retrieving the data. Modify the timeline function so it looks like this:

Copy to Clipboard

Now the timeline will get the news items using a filter.
To test this, build and run the app and widget.

When the widget appears, long press it and select edit.

widget in swift egeniq _2

Notice that it will flip and display a button in which you can select something.

how to make widgets in swift egeniq _3

Select a category and tap outside the widget. Notice that the widget will retrieve a different dataset based on the filtering you selected.

Finally, lets style the widget a little bit.

Styling the widget

Our widget looks a bit boring, so let’s improve a couple of things. Add the following struct to the widget extension project.

Copy to Clipboard

This view will handle the downloading of the images. As widgets do not support async downloaded images, you need to create something custom. This struct is one way of downloading the images.

What will happen in this struct is that the NetworkImageView will try to download the image data if the url is valid. After that it will display the image in an ImageView. If this fails it will display a ‘No Image’-text.

Adjust the entry view so it looks like this:

Copy to Clipboard

Compile and run your widget to see the result. It should display an image and a title which have been limited to 2 lines per news entry.

Congrats! This is your first widget!

Making widgets in swift egeniq_4

Written by Alex Wiersma

Software Engineer

After multiple jobs, Alex discovered that his true passion was to develop software. QA is awesome, PM is challenging, and Android is cool. But iOS is the bomb, and it is Alex’s expertise.

Published on: September 6th, 2022

Newsletter

Become an app expert? Leave your e-mail.

nederlandse loterij en egeniq
pathe thuis en egeniq
rpo and egeniq
mvw en egeniq
rtl and egeniq