Ch5. expo-widgets 홈 화면 위젯
iOS WidgetKit·Android Glance 기반 위젯 개발과 데이터 동기화
핵심 요약
expo-widgets는 React 컴포넌트와 Expo UI로 iOS 홈 화면 위젯과 Live Activities를 정의하고, Config Plugin이 prebuild 때 Widget Extension·App Group·entitlements를 자동 생성합니다.- SDK 56 changelog는 Widgets·Live Activities를 stable로 발표했지만 API reference에는 alpha 배너가 남아 있어, 핵심 기능이라면 패키지 버전을 고정하고 실기기 회귀 테스트를 돌립니다.
- 위젯 함수는
'widget'지시문을 쓰고createWidget이름은 app config의widgets[].name과 일치해야 합니다. - Live Activities는 start·update·end·getPushToken·push-to-start 흐름을 제공하고
contentDate로 오래된 payload를 폐기합니다. - 위젯 props는 작고 직렬화 가능한 스냅샷으로 유지하고, 토큰·개인정보·큰 이미지는 App Group이 아닌 앱 저장소나 서버 조회로 분리합니다.
개요
expo-widgets는 React 컴포넌트와 Expo UI로 iOS 홈 화면 위젯과 Live Activities를 정의하고,
Config Plugin이 prebuild 시 Widget Extension, App Group, entitlements를 생성하는 시스템입니다.
SDK 56 상태 해석
SDK 56 changelog는 iOS Widgets와 Live Activities를 stable로 올렸다고 발표했습니다. 다만 지금도 API reference에는 alpha 배너가 남아 있어서, 엔터프라이즈 핵심 기능이라면 패키지 버전을 고정하고 실제 디바이스 회귀 테스트를 함께 돌립니다.
아키텍처
Config Plugin 기준선
{
"expo": {
"plugins": [
[
"expo-widgets",
{
"groupIdentifier": "group.com.company.app",
"enablePushNotifications": true,
"widgets": [
{
"name": "StatusWidget",
"displayName": "Status",
"description": "핵심 상태를 한눈에 보여줍니다.",
"supportedFamilies": ["systemSmall", "systemMedium"]
}
]
}
]
]
}
}Config Plugin이 위젯 extension target, App Group, Live Activities push entitlement를 관리합니다. 수동으로 고친 native target은 CNG를 재생성하면 사라지니, plugin 설정을 source of truth로 둡니다.
위젯 작성 패턴
import { Text, VStack } from '@expo/ui/swift-ui';
import { font } from '@expo/ui/swift-ui/modifiers';
import { createWidget, type WidgetEnvironment } from 'expo-widgets';
type StatusWidgetProps = {
label: string;
count: number;
};
function StatusWidget(props: StatusWidgetProps, env: WidgetEnvironment) {
'widget';
return (
<VStack>
<Text modifiers={[font({ weight: 'bold', size: 16 })]}>{props.label}</Text>
<Text>{props.count}</Text>
<Text>{env.widgetFamily}</Text>
</VStack>
);
}
export default createWidget('StatusWidget', StatusWidget);위젯 이름은 app config의 widgets[].name과 일치해야 합니다.
Live Activities
Live Activities는 잠금 화면과 Dynamic Island에 실시간 정보를 표시합니다.
| 패턴 | 설명 |
|---|---|
createLiveActivity | Live Activity factory 생성 |
start(props, deepLink) | 앱에서 Live Activity 시작 |
update(props) | 상태 즉시 갱신 |
end(policy, props, contentDate) | 종료와 stale payload 방지 |
getPushToken() | APNs 서버 갱신용 activity별 push token |
addPushToStartTokenListener | 서버에서 사용자 인터랙션 없이 시작하는 push-to-start 흐름 |
프로덕션 데이터 규칙
- 위젯 props는 작고 직렬화 가능한 스냅샷으로 유지합니다.
- 큰 이미지, 토큰, 개인정보는 App Group에 저장하지 말고 앱 내부 저장소나 서버 조회로 분리합니다.
- deep link는 위젯·Live Activity·push notification이 같은 route contract를 쓰게 맞춥니다.
- Live Activity push payload에는 서버 생성 시각을 넣고
contentDate로 오래된 업데이트를 폐기합니다. - iOS 버전·기기마다 렌더링이 크게 달라지니
systemSmall,systemMedium, Lock Screen accessory family를 각각 캡처 테스트합니다.
주의사항
- 공식 API reference의 상태 표기가 changelog와 아직 어긋납니다. 릴리스마다 문서와 패키지 changelog를 같이 확인합니다.
- iOS 전용입니다. Android Glance에 해당하는 기능은 native로 따로 구현하거나 앞으로의 Expo 지원을 기다려야 합니다.
- Expo Go가 아니라 development build에서 검증합니다.
- 위젯 내부에서는 인터랙티브 요소와 네트워크 작업이 제한됩니다.
- App Group 데이터 크기 제한 (위젯은 경량 데이터만 참조)