Snowball iOS Widget Development from Zero to One
This article details the end‑to‑end process of building a Snowball iOS Widget with WidgetKit, covering design principles, lifecycle, data sharing via App Groups, SwiftUI view construction, Intent configuration, and deployment considerations, providing code examples and practical tips for mobile developers.
In WWDC 2020 Apple introduced WidgetKit , a framework that enables developers to create widgets that can appear on the iOS and macOS home screens. Unlike shortcuts, widgets focus on information display and have strict runtime limitations, making user‑experience design a key challenge for the Snowball team.
WidgetKit Overview
The Snowball team studied the WWDC20 sessions on widgets before starting design. Core widget requirements include simple, timely content, appropriate display timing, and personalized layouts for different sizes.
Widget Core Elements
Simple, clear content is preferred over complex UI.
Widgets must display the right content at the right time, supporting pre‑rendering and reusable update strategies.
Personalization allows different content for various widget sizes and user configurations.
Widget Limitations
No animations – only static pages.
No drag, scroll, or complex controls such as Switch.
Interaction is limited to a URL tap that opens the host app.
Refresh frequency is controlled by the system’s machine‑learning scheduler.
Widget Lifecycle
A widget runs as an app extension with a lifecycle similar to a normal app process, but refreshes are scheduled by the system. The system calls the widget three times:
When the user adds the widget, placeholder(in:) is invoked to show a placeholder.
During preview, getSnapshot(for:in:completion:) creates a snapshot.
After the widget is placed on the home screen, getTimeline(for:in:completion:) provides future timeline entries and update policies.
Tip: Render an appropriate view for the snapshot and fetch network data when refreshing the timeline.
Snowball Widget Design
Snowball aims to surface market data, favorite stocks, hot topics, and a calendar via widgets. Three sizes are offered for the favorite‑stock widget (large, medium, small).
Design references include the WWDC sessions “Design great Widgets” and “Meet WidgetKit”.
0x01 Environment Setup
Widgets are separate app extensions with their own storage. The extension needs networking, image caching, and persistence libraries. Swift and SwiftUI knowledge is required.
Network Communication
Widgets can use URLSession . Snowball wraps networking with Alamofire + SwiftyJSON . The required pods are added to the widget target in the Podfile :
target 'Snowball' do
...
target 'SnowballWidgets' do
inherit! :search_paths
pod 'Alamofire', '~> 5.0.2'
pod 'SwiftyJSON', '~> 5.0.0'
...
end
endData Sharing
Since an app extension cannot directly communicate with its host app, Apple provides App Groups for shared data via UserDefaults or FileManager . Snowball stores the access_token and user preferences in a shared UserDefaults suite identified by the App Group ID defined in Info.plist .
init?(suiteName suitename: String?)
// or
func addSuite(named suiteName: String)Example of a shared UserDefaults wrapper:
public extension UserDefaults {
@UserDefaultsWrapper(key: "com.xxx.Widgets.token")
@objc static var WidgetToken: String?
@UserDefaultsWrapper(key: "com.xxx.Widgets.stockColor", defaultValue: 0)
@objc static var WidgetStockColor: Bool
...
}0x02 SwiftUI & Custom View
SwiftUI is used to build the widget UI. Layout is performed in three steps: the parent provides an estimated size, the child computes its actual size, and the parent finalizes the layout.
Size can be determined automatically, set manually with frame + position , or constrained with aspectRatio . Example of manual positioning for a logo background:
func logoPosition(_ contentSize: CGSize) -> CGPoint {
let offset: CGFloat = logoSize / 3
if edge == .top {
return CGPoint(x: contentSize.width - offset, y: offset)
} else {
return CGPoint(x: contentSize.width - offset, y: contentSize.height - offset)
}
}Preview providers are used to test multiple states:
struct LogoView_Previews: PreviewProvider {
static var previews: some View {
Group {
LogoBackgroundView(edge: .top, style: .custom(.blue99))
LogoBackgroundView(edge: .top, style: .custom(.gold))
LogoBackgroundView(edge: .bottom, style: .custom(.gold))
.environment(\.colorScheme, .dark)
}
.previewContext(WidgetPreviewContext(family: .systemMedium))
}
}Portfolio List Item
The favorite‑stock list item ( PortfolioItemView ) is built with less than 50 lines of SwiftUI code. When data is available, the view is wrapped in a Link to open the corresponding stock page in the Snowball app. Custom Button actions are not supported; only Link or WidgetURL can trigger navigation.
0x03 Editing Your Favorites
Snowball allows users to select up to six stocks for the widget. This is achieved with the Intents framework, which provides a configuration UI defined in an IntentDefinition file. The generated PortfolioSelectionIntent class is used by an IntentTimelineProvider to supply timeline entries based on the user’s choices.
Key steps:
Enable “Include Configuration Intent” in the widget target to generate the intent definition.
Define a Portfolio class for stock data and mark the intent as “Dynamic Optional” with “provides search results”.
Implement PortfolioSelectionIntentHandler and conform to PortfolioSelectionIntentHandling in IntentHandler.swift .
Return the selected stocks in getTimeline(for:in:completion:) of the IntentTimelineProvider .
After completing these steps, the widget can be tested on iOS 14 devices.
Conclusion
Developing widgets involves many moving parts—lifecycle management, data sharing, SwiftUI layout, and Intent configuration—but SwiftUI’s preview system and WidgetKit’s declarative API make the process efficient. Widgets, despite their limitations, enrich the home‑screen experience by delivering timely market data and news.
Only static text and images are supported; real‑time updates are system‑controlled.
Widgets increase product exposure and provide personalized entry points for users.
One‑tap access shortens the path to core functionality.
Snowball Engineer Team
Proactivity, efficiency, professionalism, and empathy are the core values of the Snowball Engineer Team; curiosity, passion, and sharing of technology drive their continuous progress.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.