This documentation is available as Markdown for AI agents and LLMs. See the full Markdown index or append .md to any documentation URL.
This is documentation for the next SDK version. For up-to-date documentation, see the latest version (SDK 57).
Expo 小组件
一个使用 Expo UI 组件构建 iOS 主屏幕小组件和实时活动的库。
重要 此库在 Expo Go 应用中不可用 — 请使用 开发构建 来试用它。
expo-widgets 使你能够使用 Expo UI 组件创建 iOS 主屏幕小组件和实时活动,而无需编写原生代码。它提供了一个简单的 API,用于创建和更新小组件的时间线,以及启动和管理实时活动。你可以使用 expo/ui 组件和修饰器来构建布局。

使用 expo-widgets 和 TypeScript 构建原生 iOS 主屏幕小组件。
已知限制
- 频繁的实时活动更新。 要提高频繁推送更新的预算,请在你的 Info.plist 中将
NSSupportsLiveActivitiesFrequentUpdates设置为true。系统仍可能会限制更新频率,用户也可以在设置中禁用频繁更新。 - Widget 运行时。 标记为
'widget'的组件内部代码运行在隔离的运行时中,只能使用@expo/ui/swift-ui组件,不能使用 React hooks、应用状态或异步工作。参见 “widget”指令。
安装
- npx expo install expo-widgetsIf you are installing this in an existing React Native app, make sure to install expo in your project.
在 app config 中配置
如果您的项目中使用了 config plugins(持续原生生成(CNG)),您可以通过其内置的 config plugin 来配置 expo-widgets。该插件允许您配置各种无法在运行时设置、且需要构建新的应用二进制文件后才会生效的属性。
Example app.json with config plugin
{ "expo": { "plugins": [ [ "expo-widgets", { "widgets": [ { "name": "MyWidget", "displayName": "My Widget", "description": "A sample home screen widget", "ios": { "supportedFamilies": ["systemSmall", "systemMedium", "systemLarge"] } } ] } ] ] } }
Configurable properties
| Name | Default | Description |
|---|---|---|
bundleIdentifier | "<app bundle identifier>.ExpoWidgetsTarget" | 小组件扩展目标的 bundle 标识符。如果未指定,默认为 |
groupIdentifier | "group.<app bundle identifier>" | 主应用与小组件之间用于通信和数据共享的 app group 标识符,小组件运行需要它。如果未指定,默认为 |
enablePushNotifications | false | 是否为 Live Activities 启用推送通知。启用后,会添加 |
widgets | - | 小组件配置数组。数组中的每个小组件都会在您的小组件扩展中生成一个单独的小组件类型。 |
widgets[].name | - | 小组件的内部名称(标识符)。它将用作 Swift struct 名称,并且应是有效的 Swift 标识符(不能包含空格或特殊字符)。它必须与传给 |
widgets[].displayName | - | 小组件在用户将其添加到主屏幕时,会在小组件库中显示的面向用户的名称。 |
widgets[].description | - | 对小组件功能的简短描述。它会显示在小组件库中,帮助用户了解该小组件的用途。 |
widgets[].ios.supportedFamilies | - | 此小组件支持的小组件尺寸数组。可用选项:
|
widgets[].ios.contentMarginsDisabled | false | 当您为小组件禁用内容边距时,系统不会自动在小组件内容周围添加边距,您需要负责为不同上下文指定小组件内容周围的边距和内边距。 |
widgets[].ios.initialLayout | - | 注册该小组件与 |
widgets[].ios.configuration | - | 使小组件可配置。用户选择的值会在运行时通过
|
顶层的supportedFamilies和contentMarginsDisabled选项是ios.supportedFamilies和ios.contentMarginsDisabled的弃用别名。请优先使用上面所示的嵌套ios形式。
包含所有选项的完整示例
{ "expo": { "plugins": [ [ "expo-widgets", { "bundleIdentifier": "com.example.myapp.widgets", "groupIdentifier": "group.com.example.myapp", "enablePushNotifications": true, "widgets": [ { "name": "StatusWidget", "displayName": "Status", "description": "Shows your current status at a glance", "ios": { "contentMarginsDisabled": true, "supportedFamilies": ["systemSmall", "systemMedium"] } }, { "name": "WeatherWidget", "displayName": "Weather", "description": "Shows the weather for a city you choose", "ios": { "supportedFamilies": ["systemSmall", "systemMedium"], "configuration": { "title": "Choose a city", "description": "Pick which city to show the weather for", "parameters": { "city": { "title": "City", "type": "enum", "default": "sf", "values": [ { "name": "San Francisco", "value": "sf" }, { "name": "New York", "value": "nyc" } ], "dynamic": true } } } } }, { "name": "LockScreenWidget", "displayName": "Quick View", "description": "View info on your Lock Screen", "ios": { "supportedFamilies": [ "accessoryCircular", "accessoryRectangular", "accessoryInline" ] } } ] } ] ] } }
使用
'widget' 指令
传递给 createWidget 和 createLiveActivity 的组件必须以 'widget' 指令开头。该指令会告诉打包器将该组件编译成一个单独的 JavaScript bundle,它会在 widget 扩展内的隔离运行时中运行,而不是在你应用的 React Native 运行时中运行。
由于这种隔离,带有 'widget' 标记的组件内部代码受到限制:
- 它只能渲染
@expo/ui/swift-ui组件和修饰器。标准的 React Native 组件(例如来自react-native的View和Text)不可用。 - 它不能使用 React hooks(
useState、useEffect等)、组件状态或上下文。函数必须是纯函数,并且同步返回其布局。 - 它不能执行异步工作、导入其他模块,或访问你应用的运行时或内存中的状态。
- 它不能引用在组件函数外部声明的任何内容,包括同一文件中的普通顶层
const。打包器只会序列化函数体,因此模块作用域的值在运行时不会存在。请将每个常量和辅助函数都声明在 widget 函数内部,或者通过 props 传入。
widget 所需的所有数据都必须通过它的 props(由 updateSnapshot、updateTimeline,或 Live Activity 的 start 和 update 设置)以及 environment 参数传入。要使用图片,请从你的应用中将它们写入 widgetsDirectory,并通过路径引用它们。
import { Text } from '@expo/ui/swift-ui'; import { createWidget, type WidgetEnvironment } from 'expo-widgets'; // 在模块作用域中声明 — 不会包含在 widget bundle 中。 const CITY_NAMES: Record<string, string> = { sf: 'San Francisco' }; const CityWidget = (props: object, environment: WidgetEnvironment<{ city: string }>) => { 'widget'; // 运行时抛出错误:找不到变量:CITY_NAMES return <Text>{CITY_NAMES[environment.configuration.city]}</Text>; }; export default createWidget('CityWidget', CityWidget);
将 CITY_NAMES 移到 CityWidget 内部(或者通过 props 传入解析后的值)即可修复。
小组件
前提:创建小组件
先使用 createWidget 函数创建一个小组件,并传入带有 'widget' 指令标记的小组件组件。该组件接收你的小组件 props 作为第一个参数,WidgetEnvironment 对象作为第二个参数。
import { Text, VStack } from '@expo/ui/swift-ui'; import { font, foregroundStyle } from '@expo/ui/swift-ui/modifiers'; import { createWidget, type WidgetEnvironment } from 'expo-widgets'; type MyWidgetProps = { count: number; }; const MyWidget = (props: MyWidgetProps, environment: WidgetEnvironment) => { 'widget'; return ( <VStack> <Text modifiers={[font({ weight: 'bold', size: 16 }), foregroundStyle('#000000')]}> 计数:{props.count} </Text> <Text>所属尺寸:{environment.widgetFamily}</Text> </VStack> ); }; export default createWidget('MyWidget', MyWidget, { count: 0 });
小组件名称('MyWidget')必须与 应用配置 中小组件配置里的 name 字段一致。
可选的第三个参数提供在小组件时间线更新之前使用的初始 props。
基础小组件
更新小组件的一个有效方式是使用 updateSnapshot 方法。这会创建一个仅包含单个条目的小组件时间线,并立即显示。
下面的示例接续自 创建小组件。
import MyWidget from './MyWidget'; // 更新小组件 MyWidget.updateSnapshot({ count: 5 });
时间线小组件
使用 updateTimeline 方法可以在特定时间安排小组件更新。系统会根据时间线自动更新小组件。
下面的示例接续自 创建小组件。
import MyWidget from './MyWidget'; MyWidget.updateTimeline([ { date: new Date(), props: { count: 1 } }, { date: new Date(Date.now() + 3600000), props: { count: 2 } }, // 距现在 1 小时 { date: new Date(Date.now() + 7200000), props: { count: 3 } }, // 距现在 2 小时 { date: new Date(Date.now() + 10800000), props: { count: 4 } }, // 距现在 3 小时 ]);
读取当前时间线
使用 getTimeline 读取当前为某个小组件安排的条目,包括过去和未来的条目。
import MyWidget from './MyWidget'; const entries = await MyWidget.getTimeline(); // [{ date: Date, props: { count: number } }, ...]
重新加载小组件
使用 reload 可强制系统立即刷新小组件的内容和时间线,例如在底层数据发生变化之后。
import MyWidget from './MyWidget'; MyWidget.reload();
响应式小组件
使用 environment 参数使布局适配当前小组件尺寸和渲染上下文。
import { HStack, Text, VStack } from '@expo/ui/swift-ui'; import { createWidget, type WidgetEnvironment } from 'expo-widgets'; type WeatherWidgetProps = { temperature: number; condition: string; }; const WeatherWidget = (props: WeatherWidgetProps, environment: WidgetEnvironment) => { 'widget'; // 根据尺寸渲染不同布局 if (environment.widgetFamily === 'systemSmall') { return ( <VStack> <Text>{props.temperature}°</Text> </VStack> ); } if (environment.widgetFamily === 'systemMedium') { return ( <HStack> <Text>{props.temperature}°</Text> <Text>{props.condition}</Text> </HStack> ); } // systemLarge 和其他情况 return ( <VStack> <Text>温度:{props.temperature}°</Text> <Text>天气:{props.condition}</Text> <Text>更新时间:{environment.date.toLocaleTimeString()}</Text> </VStack> ); }; const Widget = createWidget('WeatherWidget', WeatherWidget); export default Widget; Widget.updateSnapshot({ temperature: 72, condition: '晴朗', });
适配渲染环境
除了 widgetFamily 和 date 之外,environment 对象还描述了系统如何以及在哪里绘制小组件,因此你可以据此调整布局:
colorScheme:'light'或'dark'。widgetRenderingMode:主屏幕小组件为'fullColor',锁屏小组件为'vibrant'(系统会将其去饱和为自适应单色外观),而在 iOS 18 及更高版本中,染色小组件为'accented'。可用它来选择在每种模式下都易于阅读的颜色。isLuminanceReduced:当显示需要降低亮度时为true(例如常亮显示)。可通过降低内容的整体亮度来适配,例如使用描边形状而不是填充形状。widgetContentMargins:当未禁用内容边距时,系统建议的边距(top、bottom、leading、trailing)。showsWidgetLabel:对于辅助小组件,指示是否可以显示辅助标签。
交互式小组件
小组件可以包含诸如 Button 之类的交互控件。按钮的 onPress 回调返回的值会成为小组件的新 props。运行时会持久化该值并在设备上重新加载小组件,无需正在运行的应用进程。这是让小组件响应点击并自行更新的主要方式。交互式小组件需要 iOS 17 或更高版本。
import { Button, Text, VStack } from '@expo/ui/swift-ui'; import { createWidget } from 'expo-widgets'; type CounterProps = { count: number; }; const CounterWidget = (props: CounterProps) => { 'widget'; return ( <VStack> <Text>计数:{props.count}</Text> <Button label="递增" target="increment" onPress={() => ({ count: props.count + 1 })} /> </VStack> ); }; export default createWidget('CounterWidget', CounterWidget, { count: 0 });
如果你还想让正在运行的应用与小组件交互保持同步,可以给控件添加一个 target 标识符(如上所示),并使用 addUserInteractionListener 监听点击。监听器会接收小组件的 name 作为 source,以及控件的 target。与 onPress 不同,它只会在应用进程存活时触发,因此应将其用于把交互同步到应用状态,而不是作为小组件的更新机制。
import { addUserInteractionListener } from 'expo-widgets'; const subscription = addUserInteractionListener(event => { if (event.source === 'CounterWidget' && event.target === 'increment') { // 小组件已经通过 onPress 自行更新;在这里将更改同步到应用状态。 console.log('小组件中的计数已递增'); } }); // 之后,当你不再需要更新时: subscription.remove();
使用 widgetsDirectory 共享图片
小组件无法访问应用沙盒中的文件,因此要在小组件中显示图片,必须将其放入共享的 app group 容器中。widgetsDirectory 是一个 file:// URL 字符串,指向一个应用及其小组件都可读取的目录。先从应用将图片写入那里,然后在小组件中通过路径引用它。
import { widgetsDirectory } from 'expo-widgets'; // `widgetsDirectory` 是一个指向与你的小组件共享目录的 file:// URL。 console.log(widgetsDirectory);
仅当未配置 app group 时,widgetsDirectory才为null。groupIdentifier配置插件选项会自动设置一个(默认回退到group.<bundle identifier>),因此在正常使用时它是可用的。
可配置小组件
当你为小组件添加 ios.configuration 时,用户可以长按小组件并编辑其参数。他们选择的值会通过 environment.configuration 传递给你的小组件。通过向 createWidget(以及 WidgetEnvironment)传入第二个类型参数来为配置类型化。可配置小组件需要 iOS 17 或更高版本。
import { Text, VStack } from '@expo/ui/swift-ui'; import { createWidget, type WidgetEnvironment } from 'expo-widgets'; type WeatherProps = { temperature: number; }; type WeatherConfiguration = { city: string; }; const WeatherWidget = ( props: WeatherProps, environment: WidgetEnvironment<WeatherConfiguration> ) => { 'widget'; return ( <VStack> <Text>{environment.configuration.city}</Text> <Text>{props.temperature}°</Text> </VStack> ); }; export default createWidget<WeatherProps, WeatherConfiguration>('WeatherWidget', WeatherWidget);
动态枚举选项
当选项列表只在运行时才知道时,例如登录后加载的工作区,请在 应用配置 中为枚举参数设置 dynamic: true。在应用提供如下所示的运行时选项之前,应用配置中的 values 数组会作为后备列表使用:
WeatherWidget.setConfigurationParameterEnum('city', [ { name: '当前城市', value: 'current' }, { name: '旧金山', value: 'sf' }, { name: '纽约', value: 'nyc' }, ]);
实时活动
Live Activity 会在受支持的设备上于锁屏和灵动岛中显示实时信息。
前提条件:创建 Live Activity
Live Activity 布局必须使用 createLiveActivity 只创建一次,并标记 'widget' 指令。组件会将你的 props 作为第一个参数,将 LiveActivityEnvironment 对象作为第二个参数。它会返回一个对象,描述每种展示形态的布局:锁屏 banner、灵动岛的紧凑和最小状态,以及展开后的灵动岛区域。
重要
createLiveActivity会在运行时完全注册一个 Live Activity,而库内置的 Live Activity target 会对其进行渲染。不要 在 app config 中为其添加widgets[]条目。widgets[]数组仅用于主屏幕和锁屏 widget,而没有supportedFamilies的条目会生成一个无效的 widget target,导致构建失败。你传给createLiveActivity的name只需要与这次createLiveActivity调用匹配,不需要与 app config 中的 widget 匹配。
import { Image, Text, VStack } from '@expo/ui/swift-ui'; import { font, foregroundStyle, padding } from '@expo/ui/swift-ui/modifiers'; import { createLiveActivity, type LiveActivityEnvironment } from 'expo-widgets'; type DeliveryActivityProps = { etaMinutes: number; status: string; }; const DeliveryActivity = (props: DeliveryActivityProps, environment: LiveActivityEnvironment) => { 'widget'; const accentColor = environment.isLuminanceReduced ? '#FFFFFF' : '#007AFF'; return { banner: ( <VStack modifiers={[padding({ all: 12 })]}> <Text modifiers={[font({ weight: 'bold' }), foregroundStyle(accentColor)]}> {props.status} </Text> <Text>预计到达:{props.etaMinutes} 分钟</Text> </VStack> ), compactLeading: <Image systemName="box.truck.fill" color={accentColor} />, compactTrailing: <Text>{props.etaMinutes} 分钟</Text>, minimal: <Image systemName="box.truck.fill" color={accentColor} />, expandedLeading: ( <VStack modifiers={[padding({ all: 12 })]}> <Image systemName="box.truck.fill" color={accentColor} /> <Text modifiers={[font({ size: 12 })]}>配送中</Text> </VStack> ), expandedTrailing: ( <VStack modifiers={[padding({ all: 12 })]}> <Text modifiers={[font({ weight: 'bold', size: 20 })]}>{props.etaMinutes}</Text> <Text modifiers={[font({ size: 12 })]}>分钟</Text> </VStack> ), expandedBottom: ( <VStack modifiers={[padding({ all: 12 })]}> <Text>司机:John Smith</Text> <Text>订单 #12345</Text> </VStack> ), }; }; export default createLiveActivity('DeliveryActivity', DeliveryActivity);
布局对象支持以下区域:
banner:主要的锁屏展示。bannerSmall:用于 CarPlay 和 watchOS 的紧凑锁屏展示。若省略,则回退到banner。compactLeading、compactTrailing、minimal:灵动岛的紧凑和最小状态。expandedLeading、expandedTrailing、expandedCenter、expandedBottom:展开后灵动岛的各个区域。
environment 对象还暴露了 isLuminanceReduced、isActivityFullscreen、isActivityUpdateReduced 和 activityFamily,以便你根据当前展示形态调整布局。
启动 Live Activity
下面的示例延续自 创建 Live Activity。
import { Button, View } from 'react-native'; import DeliveryActivity from './DeliveryActivity'; function App() { const startDeliveryTracking = () => { // 启动 Live Activity const instance = DeliveryActivity.start( { etaMinutes: 15, status: '您的配送正在路上', }, 'myapp://deliveries/12345' ); // 存储实例 }; return ( <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}> <Button title="Start delivery tracking" onPress={startDeliveryTracking} /> </View> ); } export default App;
可选的第二个参数是与 Live Activity 关联的 URL。当用户点按该活动时,系统会使用该 URL 打开你的应用,因此你可以通过 linking 路由到相关页面(例如使用 Expo Router 的深度链接)。
更新 Live Activity
下面的示例延续自 启动 Live Activity。
import { LiveActivity } from 'expo-widgets'; function updateDelivery(instance: LiveActivity<DeliveryActivityProps>) { instance.update({ etaMinutes: 2, status: '配送即将送达!', }); }
恢复活动中的 Live Activity
Live Activity 可以在启动它的应用进程结束后继续存在。请在工厂上使用 getInstances 来检索当前处于活动状态的该类型活动,例如在应用重新启动后对其进行更新或结束。
import DeliveryActivity from './DeliveryActivity'; const activeInstances = DeliveryActivity.getInstances(); for (const instance of activeInstances) { await instance.update({ etaMinutes: 5, status: 'Almost there' }); }
结束 Live Activity
使用 end 来结束 Live Activity。您可以选择关闭策略,按需提供最终内容状态,并传入 contentDate,以便系统忽略过期更新。
import { after, type LiveActivity } from 'expo-widgets'; async function completeDelivery(instance: LiveActivity<DeliveryActivityProps>) { await instance.end( after(new Date(Date.now() + 15 * 60 * 1000)), { etaMinutes: 0, status: '已送达', }, new Date() ); }
您也可以在关闭策略中使用 'default' 或 'immediate' 来替代 after(date)。
通过推送通知进行远程更新
当 enablePushNotifications 为 true 时,你可以通过 Apple Push Notification service(APNs)从服务器远程更新 Live Activities。
- 使用
addPushToStartTokenListener接收应用级的 push-to-start token,这样你的服务器就可以远程启动一个 Live Activity(需要 iOS 17.2 或更高版本)。 - 使用
instance.getPushToken()或instance.addPushTokenListener()获取某个正在运行的特定 Live Activity 的 token,这样你的服务器就可以向该活动发送更新。
import { addPushToStartTokenListener } from 'expo-widgets'; import DeliveryActivity from './DeliveryActivity'; const pushToStartSubscription = addPushToStartTokenListener(event => { console.log('Push-to-start token:', event.activityPushToStartToken); }); async function startDeliveryTracking() { const instance = DeliveryActivity.start({ etaMinutes: 15, status: 'Your delivery is on the way', }); const pushToken = await instance.getPushToken(); console.log('Per-activity token:', pushToken); const subscription = instance.addPushTokenListener(event => { console.log('Updated push token:', event.activityId, event.pushToken); }); // 稍后,当您不再需要更新时: subscription.remove(); } // 稍后,当您不再需要更新时: pushToStartSubscription.remove();
将 token 发送到你的服务器并用它推送更新。该通知必须使用 liveactivity 推送类型(apns-push-type 请求头)以及 <your bundle identifier>.push-type.liveactivity 的 apns-topic。其 aps 负载包含 event(start、update 或 end)、timestamp 和与活动 props 匹配的 content-state。content-state 必须与 expo-widgets 使用的内部内容状态一致:将 name 设为你传给 createLiveActivity 的名称,并将 props 设为该活动 props 的 JSON 字符串。对即时更新使用 apns-priority: 10,对低优先级更新使用 apns-priority: 5。timestamp、dismissal-date 和其他 APNs 日期字段均为以秒为单位的 Unix 时间戳。
要远程启动 Live Activity,请向 push-to-start token 发送一个 start 事件:
{ "aps": { "timestamp": 1778832000, "event": "start", "attributes-type": "LiveActivityAttributes", "attributes": {}, "content-state": { "name": "DeliveryActivity", "props": "{\"etaMinutes\":15,\"status\":\"Your delivery is on the way\"}" }, "alert": { "title": "Delivery started", "body": "Your delivery is on the way" } } }
远程启动需要 iOS 17.2 或更高版本。如果你希望 APNs 为将来的更新提供一个新的按活动 token,请在 iOS 18 或更高版本的 aps 负载中包含 input-push-token: 1。
要远程更新 Live Activity,请向该活动的按活动 token 发送一个 update 事件:
{ "aps": { "timestamp": 1778832300, "event": "update", "content-state": { "name": "DeliveryActivity", "props": "{\"etaMinutes\":2,\"status\":\"Delivery arriving soon!\"}" } } }
要远程结束 Live Activity,请发送带有最终内容状态的 end 事件:
{ "aps": { "timestamp": 1778832600, "event": "end", "content-state": { "name": "DeliveryActivity", "props": "{\"etaMinutes\":0,\"status\":\"Delivered\"}" }, "dismissal-date": 1778833200 } }
关于精确的负载结构和请求头,请参阅 Apple 的 使用 ActivityKit 推送通知启动和更新 Live Activities。
API
import { createWidget, createLiveActivity } from 'expo-widgets';
Constants
Type: string
A directory that can be used to store shared images for widgets. The contents of this directory are accessible by both the main app and widgets.
Classes
Represents a Live Activity instance. Provides methods to update its content and end it.
LiveActivity Methods
| Parameter | Type | Description |
|---|---|---|
| listener | (event: PushTokenEvent) => void | Callback invoked when a new push token is available. |
Adds a listener for push token update events on this Live Activity instance. The token can be used to send content updates to this specific activity via APNs.
EventSubscriptionAn event subscription that can be used to remove the listener.
| Parameter | Type | Description |
|---|---|---|
| dismissalPolicy(optional) | LiveActivityDismissalPolicy | Controls when the Live Activity is removed from the Lock Screen after ending.
Can be |
| props(optional) | T | Final content properties to update after the activity ends. |
| contentDate(optional) | Date | The time the data in the payload was generated. If this is older than a previous update or push payload, the system ignores this update. |
Ends the Live Activity.
Promise<void>Returns the push token for this Live Activity, used to send push notification updates via APNs.
Returns null if push notifications are not enabled or the token is not yet available.
Promise<string | null>Manages Live Activity instances of a specific type. Use it to start new activities and retrieve currently active ones.
LiveActivityFactory Methods
Returns all currently active instances of this Live Activity type.
LiveActivity[]| Parameter | Type | Description |
|---|---|---|
| props | T | The initial content properties for the Live Activity. |
| url(optional) | string | An optional URL to associate with the Live Activity, used for deep linking. |
| staleDate(optional) | Date | When set, the system may de-emphasize the activity after this date if content has not been refreshed. |
Starts a new Live Activity with the given properties.
LiveActivity<T>The new Live Activity instance.
Represents a widget instance. Provides methods to manage the widget's timeline.
Widget Methods
Returns the current timeline entries for the widget, including past and future entries.
Promise<WidgetTimelineEntry[]>| Parameter | Type |
|---|---|
| parameterName | keyof ConfigurationType & string |
| options(optional) | WidgetConfigurationEnum[] |
Replaces the runtime options for a dynamic enum configuration parameter. The app config values remain the fallback when no runtime options are set.
void| Parameter | Type | Description |
|---|---|---|
| props | PropsType | The properties to display in the widget. |
Sets the widget's content to the given props immediately, without scheduling a timeline.
void| Parameter | Type | Description |
|---|---|---|
| entries | WidgetTimelineEntry[] | Timeline entries, each specifying a date and the props to display at that time. |
Schedules a series of updates for the widget's content and reloads the widget.
voidMethods
| Parameter | Type | Description |
|---|---|---|
| name | string | The Live Activity name. Must match the |
| liveActivity | LiveActivityComponent<T> | The Live Activity component, marked with the |
Creates a Live Activity Factory for managing Live Activities of a specific type.
LiveActivityFactory<T>| Parameter | Type | Description |
|---|---|---|
| name | string | The widget name. Must match the |
| widget | (props: PropsType, context: WidgetEnvironment<ConfigurationType>) => Element | The widget component, marked with the |
| initialProps(optional) | PropsType | The initial properties to display before the widget timeline is updated. |
Creates a Widget instance.
Widget<PropsType, ConfigurationType>Event subscriptions
| Parameter | Type | Description |
|---|---|---|
| listener | (event: PushToStartTokenEvent) => void | Callback function to handle push-to-start token events. |
Adds a listener for push-to-start token events. This token can be used to start live activities remotely via APNs.
EventSubscriptionAn event subscription that can be used to remove the listener.
| Parameter | Type | Description |
|---|---|---|
| listener | (event: UserInteractionEvent) => void | Callback function to handle user interaction events. |
Adds a listener for widget interaction events (for example, button taps).
EventSubscriptionAn event subscription that can be used to remove the listener.
Types
| Property | Type | Description |
|---|---|---|
| onExpoWidgetsPushToStartTokenReceived | (event: PushToStartTokenEvent) => void | Function that is invoked when a push-to-start token is received. event: PushToStartTokenEventToken event details. |
| onExpoWidgetsUserInteraction | (event: UserInteractionEvent) => void | Function that is invoked when user interacts with a widget. event: UserInteractionEventInteraction event details. |
Literal type: string
The level of detail the view is recommended to have. The system can update the levelOfDetail value based on user proximity or other system specific factors and allow content customization adapting to show different levels of details.
simplified— The system recommends showing a simplified view with less details.default— The system has no specific recommendation for the level of detail.
Acceptable values are: 'simplified' | 'default'
A function that returns the layout for a Live Activity.
| Parameter | Type |
|---|---|
| props | T |
| environment | LiveActivityEnvironment |
Literal type: union
Dismissal policy for ending a live activity.
'default'- The system’s default dismissal policy for the Live Activity.'immediate'- The system immediately removes the Live Activity that ended.after(date)- The system removes the Live Activity that ended at the specified time within a four-hour window.
Acceptable values are: 'default' | 'immediate' | ReturnType<after>
| Property | Type | Description |
|---|---|---|
| activityFamily(optional) | ActivityFamily | Only for: iOS 18+ The size family of the current Live Activity. |
| colorScheme | 'light' | 'dark' | The color scheme of the activity's environment. |
| isActivityFullscreen(optional) | boolean | Only for: iOS 16.1+ Whether the activity is currently displayed in fullscreen. |
| isActivityUpdateReduced(optional) | boolean | Only for: iOS 18+ A Boolean value that indicates whether the Live Activity update synchronization rate is reduced. |
| isLuminanceReduced(optional) | boolean | Only for: iOS 16+ Whether the activity is displayed in a context with reduced luminance. |
| levelOfDetail(optional) | LevelOfDetail | Only for: iOS 26+ The level of detail the view is recommended to have. |
| Property | Type | Description |
|---|---|---|
| onExpoWidgetsTokenReceived | (event: PushTokenEvent) => void | Function that is invoked when a push token is received for a live activity. event: PushTokenEventToken event details. |
Defines the layout sections for an iOS Live Activity.
| Property | Type | Description |
|---|---|---|
| banner | ReactNode | The main banner content displayed in Notifications Center. |
| bannerSmall(optional) | ReactNode | The small banner content displayed in CarPlay and WatchOS. Falls back to |
| compactLeading(optional) | ReactNode | The leading content in the compact Dynamic Island presentation. |
| compactTrailing(optional) | ReactNode | The trailing content in the compact Dynamic Island presentation. |
| expandedBottom(optional) | ReactNode | The bottom content in the expanded Dynamic Island presentation. |
| expandedCenter(optional) | ReactNode | The center content in the expanded Dynamic Island presentation. |
| expandedLeading(optional) | ReactNode | The leading content in the expanded Dynamic Island presentation. |
| expandedTrailing(optional) | ReactNode | The trailing content in the expanded Dynamic Island presentation. |
| minimal(optional) | ReactNode | The minimal content shown when the Dynamic Island is in its smallest form. |
Event emitted when a push token is received for a live activity.
| Property | Type | Description |
|---|---|---|
| activityId | string | The ID of the live activity. |
| pushToken | string | The push token for the live activity. |
Event emitted when a push-to-start token is received.
| Property | Type | Description |
|---|---|---|
| activityPushToStartToken | string | The push-to-start token for starting live activities remotely. |
Event emitted when a user interacts with a widget.
| Property | Type | Description |
|---|---|---|
| source | string | Widget that triggered the interaction. |
| target | string | Button/toggle that was pressed. |
| timestamp | number | Timestamp of the event. |
| type | 'ExpoWidgetsUserInteraction' | The event type identifier. |
| Property | Type | Description |
|---|---|---|
| name | string | User-visible option label. |
| subtitle(optional) | string | Only for: iOS Optional secondary text displayed to user. |
| value | string | Value available in |
| Property | Type | Description |
|---|---|---|
| colorScheme(optional) | 'light' | 'dark' | The color scheme of the widget's environment. |
| configuration | T | Only for: iOS 17+ Widget configuration parameters. |
| date(optional) | Date | Only for: iOS The date of this timeline entry. |
| isLuminanceReduced(optional) | boolean | Only for: iOS 16+ A Boolean value that indicates whether the display or environment currently requires reduced luminance. When you detect this condition, lower the overall brightness of your view. For example, you can change large, filled shapes to be stroked, and choose less bright colors. |
| levelOfDetail(optional) | LevelOfDetail | Only for: iOS 26+ The level of detail the view is recommended to have. |
| showsWidgetLabel(optional) | boolean | Only for: iOS 16+ A Boolean value that indicates whether an accessory family widget can display an accessory label. |
| widgetContentMargins(optional) | {
bottom: number,
leading: number,
top: number,
trailing: number
} | Only for: iOS 17+ The content margins for the widget. |
| widgetFamily(optional) | WidgetFamily | Only for: iOS The widget family. |
| widgetRenderingMode(optional) | WidgetRenderingMode | Only for: iOS 16+ The widget's rendering mode, based on where the system is displaying it. |
Literal type: string
The widget family (size).
systemSmall- Small square widget (2x2 grid).systemMedium- Medium widget (4x2 grid).systemLarge- Large widget (4x4 grid).systemExtraLarge- Extra large widget (iPad only, 6x4 grid).accessoryCircular- Circular accessory widget for the Lock Screen.accessoryRectangular- Rectangular accessory widget for the Lock Screen.accessoryInline- Inline accessory widget for the Lock Screen.
Acceptable values are: 'systemSmall' | 'systemMedium' | 'systemLarge' | 'systemExtraLarge' | 'accessoryCircular' | 'accessoryRectangular' | 'accessoryInline'
Literal type: string
The rendering mode of the widget as provided by WidgetKit.
fullColor— Home screen widgets (default).accented— Tinted widgets (iOS 18+) and watchOS.vibrant— Lock screen widgets.
Acceptable values are: 'fullColor' | 'accented' | 'vibrant'
| Property | Type | Description |
|---|---|---|
| date | Date | Date when widget should update. |
| props | T | Props to be passed to the widget. |