Building App Widget Extensions (iOS) via Flutter
Sep 12, 2025



Summary
Summary
Summary
Summary
This tutorial walks you through building an iOS home‐screen widget for your Flutter app. You’ll set up a WidgetKit target in Xcode, configure App Groups for shared data, implement a Swift TimelineProvider to feed your widget, and use a Dart MethodChannel to push updates from Flutter. With this integration, you can refresh widget timelines dynamically and display Flutter‐driven content in native iOS extensions.
This tutorial walks you through building an iOS home‐screen widget for your Flutter app. You’ll set up a WidgetKit target in Xcode, configure App Groups for shared data, implement a Swift TimelineProvider to feed your widget, and use a Dart MethodChannel to push updates from Flutter. With this integration, you can refresh widget timelines dynamically and display Flutter‐driven content in native iOS extensions.
This tutorial walks you through building an iOS home‐screen widget for your Flutter app. You’ll set up a WidgetKit target in Xcode, configure App Groups for shared data, implement a Swift TimelineProvider to feed your widget, and use a Dart MethodChannel to push updates from Flutter. With this integration, you can refresh widget timelines dynamically and display Flutter‐driven content in native iOS extensions.
This tutorial walks you through building an iOS home‐screen widget for your Flutter app. You’ll set up a WidgetKit target in Xcode, configure App Groups for shared data, implement a Swift TimelineProvider to feed your widget, and use a Dart MethodChannel to push updates from Flutter. With this integration, you can refresh widget timelines dynamically and display Flutter‐driven content in native iOS extensions.
Key insights:
Key insights:
Key insights:
Key insights:
Setting up the Widget Target: Add a Swift WidgetKit extension in Xcode alongside your Flutter project and align bundle IDs.
Configuring App Groups & Assets: Use App Groups to share UserDefaults data and configure your asset catalog for widget images.
Implementing the Timeline Provider: Write Swift handlers in
getTimeline
andgetSnapshot
to supply widget entries on a refresh policy.Communicating via MethodChannel: Invoke a Dart MethodChannel to write widget data into the shared App Group, then reload timelines from native code.
Platform Integration: Combining Flutter’s cross‐platform logic with native WidgetKit unlocks rich, glanceable experiences on iOS.
Introduction
Building iOS home‐screen widgets can boost user engagement by offering glanceable data and quick actions. While Flutter doesn’t yet provide an official WidgetKit API, you can extend your existing Flutter iOS app to include a native Widget Extension. This guide shows how to set up an Xcode widget target alongside your Flutter module, share data via App Groups, implement a WidgetKit timeline provider in Swift, and use a simple Dart MethodChannel to update widget content. We’ll keep it code‐forward and precise, giving you a solid blueprint to ship widgets in your next mobile development project.
Setting up the Widget Target
Open your Flutter project’s
ios/Runner.xcworkspace
in Xcode.Select the Runner project, click “+” under Targets, and choose “Widget Extension.” Name it (e.g.
MyAppWidget
) and select Swift as the language.In the new widget target settings, update the bundle identifier (e.g.
com.example.myapp.widget
).Ensure “Embed & Sign” is enabled for the Widget target’s “Frameworks, Libraries, and Embedded Content.”
Verify the deployment target matches your main app (iOS 14.0+).
Your directory now includes MyAppWidget
with IntentTimelineProvider.swift
, EntryView.swift
, and MyAppWidget.swift
. You’ll edit these to supply data and render views.
Configuring App Groups & Assets
In Xcode, select your main Runner target, go to “Signing & Capabilities,” and click “+Capability.” Add App Groups and create an identifier, e.g.
group.com.example.myapp
.Add the same App Group to the widget target so both can share data.
In the widget’s Info.plist, confirm
NSExtension
→NSExtensionAttributes
→AppGroup
uses your group ID.Add any widget‐specific images or placeholders to
Assets.xcassets
under the widget’s folder. Use a single common asset catalog or create one in the widget target.
This setup ensures your Flutter app can write data to UserDefaults(suiteName: "group.com.example.myapp")
, and the widget can read it.
Implementing the Timeline Provider
Open IntentTimelineProvider.swift
inside MyAppWidget
:
• Define your entry struct (e.g. SimpleEntry: TimelineEntry
) containing the data fields (text, imageName, date).
• In placeholder(in:)
and getSnapshot
, return a sample entry for the widget gallery.
• In getTimeline(in:completion:)
, read from the shared user defaults, construct one or more entries, and call completion(Timeline(entries: entries, policy: .atEnd))
.
Example outline (no more than 20 lines):
func getTimeline(in context: Context, completion: @escaping (Timeline<SimpleEntry>) -> Void) {
let defaults = UserDefaults(suiteName: "group.com.example.myapp")
let message = defaults?.string(forKey: "widgetMessage") ?? "—"
let entry = SimpleEntry(date: Date(), message: message)
let timeline = Timeline(entries: [entry], policy: .after(Date().addingTimeInterval(60*15)))
completion(timeline)
}
This native code drives how often the widget refreshes and what data it displays.
Communicating via MethodChannel
While the widget itself runs native Swift, your Flutter app can push updates via a MethodChannel call that writes to the shared App Group. In your Dart code:
import 'package:flutter/services.dart';
final _channel = MethodChannel('com.example.myapp/widget');
Future<void> updateWidgetData(String message) async {
await _channel.invokeMethod('updateWidget', {'message': message});
}
Then in your AppDelegate.swift
, handle this call and write to UserDefaults(suiteName: …)
:
func application(_ app: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
let controller = window?.rootViewController as! FlutterViewController
let channel = FlutterMethodChannel(name: "com.example.myapp/widget",
binaryMessenger: controller.binaryMessenger)
channel.setMethodCallHandler { call, result in
if call.method == "updateWidget", let args = call.arguments as? [String: Any],
let text = args["message"] as? String {
let defaults = UserDefaults(suiteName: "group.com.example.myapp")
defaults?.set(text, forKey: "widgetMessage")
WidgetCenter.shared.reloadAllTimelines()
result(nil)
}
}
return super.application(app, didFinishLaunchingWithOptions: launchOptions)
}
Now, whenever you call updateWidgetData(...)
from Flutter, the widget’s timeline provider will fetch the new message and refresh the displayed view.
Vibe Studio

Vibe Studio, powered by Steve’s advanced AI agents, is a revolutionary no-code, conversational platform that empowers users to quickly and efficiently create full-stack Flutter applications integrated seamlessly with Firebase backend services. Ideal for solo founders, startups, and agile engineering teams, Vibe Studio allows users to visually manage and deploy Flutter apps, greatly accelerating the development process. The intuitive conversational interface simplifies complex development tasks, making app creation accessible even for non-coders.
Conclusion
You’ve now integrated a native iOS Widget Extension into a Flutter app by:
• Creating and configuring the Xcode widget target
• Sharing data via App Groups
• Implementing a TimelineProvider in Swift
• Using a Dart MethodChannel to update widget content
This pattern scales to complex data types, multiple families (small, medium, large), and custom intents. By coupling Flutter’s UI code with lightweight native extensions, you deliver a seamless, responsive experience both in the home screen widget and your core application.
Introduction
Building iOS home‐screen widgets can boost user engagement by offering glanceable data and quick actions. While Flutter doesn’t yet provide an official WidgetKit API, you can extend your existing Flutter iOS app to include a native Widget Extension. This guide shows how to set up an Xcode widget target alongside your Flutter module, share data via App Groups, implement a WidgetKit timeline provider in Swift, and use a simple Dart MethodChannel to update widget content. We’ll keep it code‐forward and precise, giving you a solid blueprint to ship widgets in your next mobile development project.
Setting up the Widget Target
Open your Flutter project’s
ios/Runner.xcworkspace
in Xcode.Select the Runner project, click “+” under Targets, and choose “Widget Extension.” Name it (e.g.
MyAppWidget
) and select Swift as the language.In the new widget target settings, update the bundle identifier (e.g.
com.example.myapp.widget
).Ensure “Embed & Sign” is enabled for the Widget target’s “Frameworks, Libraries, and Embedded Content.”
Verify the deployment target matches your main app (iOS 14.0+).
Your directory now includes MyAppWidget
with IntentTimelineProvider.swift
, EntryView.swift
, and MyAppWidget.swift
. You’ll edit these to supply data and render views.
Configuring App Groups & Assets
In Xcode, select your main Runner target, go to “Signing & Capabilities,” and click “+Capability.” Add App Groups and create an identifier, e.g.
group.com.example.myapp
.Add the same App Group to the widget target so both can share data.
In the widget’s Info.plist, confirm
NSExtension
→NSExtensionAttributes
→AppGroup
uses your group ID.Add any widget‐specific images or placeholders to
Assets.xcassets
under the widget’s folder. Use a single common asset catalog or create one in the widget target.
This setup ensures your Flutter app can write data to UserDefaults(suiteName: "group.com.example.myapp")
, and the widget can read it.
Implementing the Timeline Provider
Open IntentTimelineProvider.swift
inside MyAppWidget
:
• Define your entry struct (e.g. SimpleEntry: TimelineEntry
) containing the data fields (text, imageName, date).
• In placeholder(in:)
and getSnapshot
, return a sample entry for the widget gallery.
• In getTimeline(in:completion:)
, read from the shared user defaults, construct one or more entries, and call completion(Timeline(entries: entries, policy: .atEnd))
.
Example outline (no more than 20 lines):
func getTimeline(in context: Context, completion: @escaping (Timeline<SimpleEntry>) -> Void) {
let defaults = UserDefaults(suiteName: "group.com.example.myapp")
let message = defaults?.string(forKey: "widgetMessage") ?? "—"
let entry = SimpleEntry(date: Date(), message: message)
let timeline = Timeline(entries: [entry], policy: .after(Date().addingTimeInterval(60*15)))
completion(timeline)
}
This native code drives how often the widget refreshes and what data it displays.
Communicating via MethodChannel
While the widget itself runs native Swift, your Flutter app can push updates via a MethodChannel call that writes to the shared App Group. In your Dart code:
import 'package:flutter/services.dart';
final _channel = MethodChannel('com.example.myapp/widget');
Future<void> updateWidgetData(String message) async {
await _channel.invokeMethod('updateWidget', {'message': message});
}
Then in your AppDelegate.swift
, handle this call and write to UserDefaults(suiteName: …)
:
func application(_ app: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
let controller = window?.rootViewController as! FlutterViewController
let channel = FlutterMethodChannel(name: "com.example.myapp/widget",
binaryMessenger: controller.binaryMessenger)
channel.setMethodCallHandler { call, result in
if call.method == "updateWidget", let args = call.arguments as? [String: Any],
let text = args["message"] as? String {
let defaults = UserDefaults(suiteName: "group.com.example.myapp")
defaults?.set(text, forKey: "widgetMessage")
WidgetCenter.shared.reloadAllTimelines()
result(nil)
}
}
return super.application(app, didFinishLaunchingWithOptions: launchOptions)
}
Now, whenever you call updateWidgetData(...)
from Flutter, the widget’s timeline provider will fetch the new message and refresh the displayed view.
Vibe Studio

Vibe Studio, powered by Steve’s advanced AI agents, is a revolutionary no-code, conversational platform that empowers users to quickly and efficiently create full-stack Flutter applications integrated seamlessly with Firebase backend services. Ideal for solo founders, startups, and agile engineering teams, Vibe Studio allows users to visually manage and deploy Flutter apps, greatly accelerating the development process. The intuitive conversational interface simplifies complex development tasks, making app creation accessible even for non-coders.
Conclusion
You’ve now integrated a native iOS Widget Extension into a Flutter app by:
• Creating and configuring the Xcode widget target
• Sharing data via App Groups
• Implementing a TimelineProvider in Swift
• Using a Dart MethodChannel to update widget content
This pattern scales to complex data types, multiple families (small, medium, large), and custom intents. By coupling Flutter’s UI code with lightweight native extensions, you deliver a seamless, responsive experience both in the home screen widget and your core application.
Build Flutter Apps Faster with Vibe Studio
Build Flutter Apps Faster with Vibe Studio
Build Flutter Apps Faster with Vibe Studio
Build Flutter Apps Faster with Vibe Studio
Vibe Studio is your AI-powered Flutter development companion. Skip boilerplate, build in real-time, and deploy without hassle. Start creating apps at lightning speed with zero setup.
Vibe Studio is your AI-powered Flutter development companion. Skip boilerplate, build in real-time, and deploy without hassle. Start creating apps at lightning speed with zero setup.
Vibe Studio is your AI-powered Flutter development companion. Skip boilerplate, build in real-time, and deploy without hassle. Start creating apps at lightning speed with zero setup.
Vibe Studio is your AI-powered Flutter development companion. Skip boilerplate, build in real-time, and deploy without hassle. Start creating apps at lightning speed with zero setup.











