Creating iOS Widgets with MAUI - Part 3: Communicating between MAUI App and iOS Widget
This is the last part of the series recording how I managed to create a MAUI app that can interact with an iOS widget. In this post, we will explore how to communicate between the iOS widget and the our MAUI app we created from the previous posts. I highly recommend reading the first and second post, Creating iOS Widgets with MAUI - Part 1: Interoperability and Creating iOS Widgets with MAUI - Part 2: Bundling iOS Widget, if you haven’t read them yet, as the topic in this post will require knowledge from the previous ones.
Disclaimer: I am just sharing my personal experience. I do not guarantee the information in this post is 100% correct or accurate. I am not, by any means, expressing that I am an expert in mobile development.
Sharing data between MAUI app and iOS widget
To share data between the MAUI app and the iOS widget, we can use App Groups. App Groups allow multiple apps or extensions to share access to a common container.
We need to make sure both of our MAUI app and the iOS widget are part of the same App Group.
In Xcode:
- Open the widget extension target project created in Part 2.
- Create a
.entitlementsfile for the widget extension if you haven’t done so. Name it to something likeHelloWidgetExtension.entitlements. - Open the
.entitlementsfile and add the following:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.application-groups</key>
<array>
<!-- Replace with your app bundle identifier -->
<string>group.MyOrg.hello-maui-widget</string>
</array>
</dict>
</plist>
Or clicking on the top level project > TARGETS > widget extension > Signing & Capabilities > click ”+ Capability” > App Groups.

There will be a App Groups section shown at the bottom. Click the ”+” button.

Make sure your newly created App Group is checked.

- Do the same for the Xcode App project as well to make sure the provisioning profile managed by Xcode contains this entitlement. Xcode will warns you if you forget to do this when you try to build build the MAUI app.
Note: App Group identifiers must be prefixed with group., it is Apple’s convention.
Back to the MAUI app project:
- Go to
Platforms/iOSfolder, create a new file namedEntitlements.plistif it doesn’t exist. - Copy the same content from the widget extension’s
.entitlementsfile into this file. - Open the MAUI project file to configure the same code sign entitlements as the Xcode App project did by adding the following PropertyGroup:
<PropertyGroup Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">
<CodesignEntitlements>Platforms/iOS/Entitlements.plist</CodesignEntitlements>
</PropertyGroup>
Now we will make use of NSUserDefaults with the App Group to share data.
Note: Although MAUI provides Microsoft.Maui.Storage.Preferences, it defaults to NSUserDefaults.StandardUserDefaults under the hood, which does not support App Groups by design.
Think of it as an in-memory key-value storage that both the MAUI app and the iOS widget can access, just like using Redis. iOS manages when the values are flushed to persistent storage.
What we are trying to do is to have the MAUI app write a value to the shared NSUserDefaults, and call the bridge to have the iOS widget read that value and display it.
- Open
MainPage.xaml.csin your MAUI project, and add the following code above theHelloWorldBridge.SayHelloStaticLib();line we added in Part 1:
// replace with group.[your_app_group_identifier]
using var defaults = new NSUserDefaults("group.MyOrg.hello-maui-widget", NSUserDefaultsType.SuiteName);
defaults.SetString(count.ToString(), "helloValue");
We have just written the current counter value to the shared NSUserDefaults with key helloValue.
Now the last piece of the puzzle is to have the iOS widget read that value and display it.
Reload widget timeline
In part 1, the exported Swift function HelloWorldBridge_SayHello simply logged a hello message. Now we will modify it such that when it is called, it will reload the widget data source.
Open the HelloWorldBridge.swift file we created in Part 1, and modify the function to the following:
@_cdecl("HelloWorldBridge_SayHello")
public func HelloWorldBridge_SayHello() {
WidgetCenter.shared.reloadAllTimelines()
}
This will instruct the singleton WidgetCenter to reload all widget timelines belonging to the containing app. The current timeline will get invalidated, and the system will call the timeline provider to get new data. So the next step is to modify our timeline provider to read the shared data.
Open the HelloWidget.swift file created in Part 2, and modify the getTimeline method in Provider struct generated by Xcode as below:
func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
let defaults = UserDefaults(suiteName: "group.MyOrg.hello-maui-widget")
let helloValue = defaults?.string(forKey: "helloValue") ?? "0"
var entries: [SimpleEntry] = []
let entryDate = Calendar.current.date(byAdding: .minute, value: 1, to: .now)!
let entry = SimpleEntry(date: entryDate, emoji: "😀 Count: \(helloValue)")
entries.append(entry)
let timeline = Timeline(entries: entries, policy: .atEnd)
completion(timeline)
}
What we did here is to read the shared NSUserDefaults with the same app group, get the value for key helloValue, and use it to create a new timeline entry.
When WidgetCenter.shared.reloadAllTimelines() is called from the MAUI app, getTimeline will be invoked, updating the widget’s display and schedule next refresh. We set it to 1 minute for demo purposes, but the actual refresh time is managed by iOS and not guaranteed, subject to WidgetKit’s budget and OS heuristics.
Build the widget extension and copy the updated HelloWidgetExtension.appex to the MAUI project’s Platforms/iOS/PlugIns folder as we did in Part 2.
Rebuild and run the MAUI app again.
Now you should be able to see that when you tap the button in the MAUI app, the counter value is updated in the iOS widget.

🎉 Congratulations! You have successfully created a MAUI app that can communicate with an iOS widget. 👏
After going through this series, you should be able to:
- Create an iOS widget and embed it into a MAUI app.
- Call Swift code from C# in a MAUI app.
- Share data between a MAUI app and its iOS widget using App Groups and
NSUserDefaults.
Hope you find this series helpful. Happy coding!
The full source code of this demo project can be found at my GitHub repository
This post is originally published on Medium.