Implementing App Groups for Data Sharing Between iOS Apps
App Groups is an iOS mechanism allowing multiple apps by the same developer (and their extensions: widgets, Siri Intents, Share Extensions) to read and write to a shared container. Without App Groups, each target lives in an isolated sandbox: widget doesn't see main app data, Today Extension can't transfer a file.
Setup
Enable App Groups in Capabilities for each target that will participate in sharing (main app + all extensions). Group identifier: group.com.yourcompany.yourapp. Same identifier in each target.
Shared UserDefaults
let sharedDefaults = UserDefaults(suiteName: "group.com.yourcompany.yourapp")
sharedDefaults?.set("active", forKey: "userStatus")
sharedDefaults?.synchronize() // Explicit flush — important before exiting extension
Read in widget exactly the same way. Without suiteName — standard UserDefaults reads only from its own sandbox.
Shared Container for Files
let containerURL = FileManager.default.containerURL(
forSecurityApplicationGroupIdentifier: "group.com.yourcompany.yourapp"
)!
let fileURL = containerURL.appendingPathComponent("shared_data.json")
// Write
try data.write(to: fileURL)
// Read in extension
let sharedData = try Data(contentsOf: fileURL)
For CoreData with shared store: NSPersistentContainer is initialized with URL from containerURL(forSecurityApplicationGroupIdentifier:).
WidgetKit: Getting Data from App Group
WidgetKit Timeline Provider runs in a separate process. Get current data for widget:
struct Provider: TimelineProvider {
func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> Void) {
let defaults = UserDefaults(suiteName: "group.com.yourcompany.yourapp")!
let count = defaults.integer(forKey: "pendingTasksCount")
let entry = TaskEntry(date: Date(), count: count)
let timeline = Timeline(entries: [entry], policy: .atEnd)
completion(timeline)
}
}
From main app when updating data: WidgetCenter.shared.reloadAllTimelines() — signal to widget to recalculate timeline.
Timeline Benchmarks
App Groups setup + implementation of shared UserDefaults and file container for two targets — 1 working day, including testing data exchange between main app and extension.







