Use App Groups and the ExtensionStorage API to share data between your app and extensions
Targets like widgets, share extensions, and App Clips run in separate processes and can’t directly access your app’s data. App Groups provide a shared container for storing data accessible to all your targets.
App Groups create a shared storage area identified by a group ID (e.g., group.com.yourapp.data). All targets with the same App Group entitlement can read and write to this storage using NSUserDefaults.
import { ExtensionStorage } from "@bacons/apple-targets";// Create storage instance with your App Group IDconst storage = new ExtensionStorage("group.com.yourapp.data");// Store a stringstorage.set("userName", "Evan");// Store a numberstorage.set("score", 42);// Store an objectstorage.set("user", { name: "Evan", score: 42,});// Store an array of objectsstorage.set("leaderboard", [ { name: "Alice", score: 100 }, { name: "Bob", score: 90 },]);// Remove a keystorage.set("oldKey", undefined);// orstorage.remove("oldKey");
import { ExtensionStorage } from "@bacons/apple-targets";const storage = new ExtensionStorage("group.com.yourapp.data");// Get a value (returns string | null)const userName = storage.get("userName");// Parse JSON for objectsconst userJson = storage.get("user");if (userJson) { const user = JSON.parse(userJson); console.log(user.name, user.score);}
After updating shared data, reload your widgets to reflect the changes:
import { ExtensionStorage } from "@bacons/apple-targets";const storage = new ExtensionStorage("group.com.yourapp.data");// Update datastorage.set("score", 100);// Reload all widgetsExtensionStorage.reloadWidget();// Or reload a specific widget by kindExtensionStorage.reloadWidget("widget");
For Control Widgets:
ExtensionStorage.reloadControls();// Or reload a specific controlExtensionStorage.reloadControls("com.yourapp.control");
class ExtensionStorage { constructor(suiteName: string); // Store a value (undefined removes the key) set( key: string, value: | string | number | Record<string, string | number> | Array<Record<string, string | number>> | undefined ): void; // Get a value (returns null if not found) get(key: string): string | null; // Remove a key remove(key: string): void;}
class ExtensionStorage { // Reload all widgets or a specific widget by kind static reloadWidget(name?: string): void; // Reload all controls or a specific control by kind static reloadControls(name?: string): void;}