Library Version
2.1.1
React Native Version
0.81.5
React Version
19.1.0
Expo Version
Bare react native app using voltra.config.tsx
Minimal Reproduction
You can make it much easier for the Voltra team to reproduce by reducing it to the smallest possible setup:
Minimal Reproduction Steps
Hi @V3RON,
I'm seeing an issue with Android dynamic widgets in a bare React Native application.
Environment
React Native: 0.81.5
Voltra:
Android widget
Bare React Native app (not Expo)
Step 1: Create a widget
messageWidget.android.tsx
import { VoltraAndroid } from '@use-voltra/android';
export function MessageWidget({
unreadCount = 0,
}: {
unreadCount?: number;
}) {
console.log('typeof unreadCount:', typeof unreadCount);
console.log('unreadCount:', unreadCount);
return (
<VoltraAndroid.Column>
<VoltraAndroid.Text>
{unreadCount} unread messages
</VoltraAndroid.Text>
</VoltraAndroid.Column>
);
}
Step 2: Configure widget
{
id: 'MessageWidget',
displayName: 'MessageWidget',
targetCellWidth: 2,
targetCellHeight: 2,
minCellWidth: 2,
minCellHeight: 2,
initialStatePath:
'./widgets/android-messagewidget-initial.tsx',
// Uncommenting this causes the issue
entry: './widgets/messageWidget.android.tsx',
}
Step 3: Generate Voltra artifacts
yarn voltra apply
Step 4: Add widget to the home screen
The widget appears and initially stays in the loading state.
Step 5: Update widget from React Native
await updateAndroidWidget('MessageWidget', [
{
size: {
width: 300,
height: 200,
},
content: (
),
},
]);
Expected Result
The widget should display:
23 unread messages
Actual Result
The widget remains in the loading state.
Android logs show the props are being passed correctly:
typeof unreadCount: number
unreadCount: 23
Additional Observation
When entry is enabled, voltra_initial_states.json is generated in a different format:
{
"MessageWidget": {
"v": 1,
"s": [...],
"variants": {
"300x200": {
...
}
}
}
}
The generated JSON contains the correct text:
"23 unread messages"
which suggests serialization is working correctly.
However, the Android runtime throws:
Failed to parse node for widgetId=MessageWidget:
Unsupported VoltraNode shape:
{
"v": 1,
"s": [...],
"variants": {...}
}
If I remove:
entry: './widgets/messageWidget.android.tsx'
the generated JSON falls back to the older format:
{
"MessageWidget": {
"t": 9,
"c": [...]
}
}
and the parsing error disappears.
Question
Is the dynamic widget format:
{
"v": 1,
"s": [...],
"variants": {...}
}
currently supported by the Android runtime, or am I missing additional configuration required for widgets that use the entry property?
Thanks! 🙏
Additional Information (Optional)
I also verified this using the Voltra widget example provided in the documentation/sample project, where the widget displays the current time and updates it using the updateWidgetData function.
Using the same approach, I replaced the time value with an unread message count and attempted to update the widget dynamically. The updated value is successfully received and rendered during serialization (as confirmed by logs and the generated JSON), but the widget itself remains in the loading state and does not display the updated content on the home screen.
This led me to believe that the update flow itself is working, and the issue may be related to how the generated dynamic widget payload is being parsed or rendered by the Android widget runtime when using the entry configuration.
Library Version
2.1.1
React Native Version
0.81.5
React Version
19.1.0
Expo Version
Bare react native app using voltra.config.tsx
Minimal Reproduction
You can make it much easier for the Voltra team to reproduce by reducing it to the smallest possible setup:
Minimal Reproduction Steps
Hi @V3RON,
I'm seeing an issue with Android dynamic widgets in a bare React Native application.
Environment
React Native: 0.81.5
Voltra:
Android widget
Bare React Native app (not Expo)
Step 1: Create a widget
messageWidget.android.tsx
import { VoltraAndroid } from '@use-voltra/android';
export function MessageWidget({
unreadCount = 0,
}: {
unreadCount?: number;
}) {
console.log('typeof unreadCount:', typeof unreadCount);
console.log('unreadCount:', unreadCount);
return (
<VoltraAndroid.Column>
<VoltraAndroid.Text>
{unreadCount} unread messages
</VoltraAndroid.Text>
</VoltraAndroid.Column>
);
}
Step 2: Configure widget
{
id: 'MessageWidget',
displayName: 'MessageWidget',
targetCellWidth: 2,
targetCellHeight: 2,
minCellWidth: 2,
minCellHeight: 2,
initialStatePath:
'./widgets/android-messagewidget-initial.tsx',
// Uncommenting this causes the issue
entry: './widgets/messageWidget.android.tsx',
}
Step 3: Generate Voltra artifacts
yarn voltra apply
Step 4: Add widget to the home screen
The widget appears and initially stays in the loading state.
Step 5: Update widget from React Native
await updateAndroidWidget('MessageWidget', [
{
size: {
width: 300,
height: 200,
},
content: (
),
},
]);
Expected Result
The widget should display:
23 unread messages
Actual Result
The widget remains in the loading state.
Android logs show the props are being passed correctly:
typeof unreadCount: number
unreadCount: 23
Additional Observation
When entry is enabled, voltra_initial_states.json is generated in a different format:
{
"MessageWidget": {
"v": 1,
"s": [...],
"variants": {
"300x200": {
...
}
}
}
}
The generated JSON contains the correct text:
"23 unread messages"
which suggests serialization is working correctly.
However, the Android runtime throws:
Failed to parse node for widgetId=MessageWidget:
Unsupported VoltraNode shape:
{
"v": 1,
"s": [...],
"variants": {...}
}
If I remove:
entry: './widgets/messageWidget.android.tsx'
the generated JSON falls back to the older format:
{
"MessageWidget": {
"t": 9,
"c": [...]
}
}
and the parsing error disappears.
Question
Is the dynamic widget format:
{
"v": 1,
"s": [...],
"variants": {...}
}
currently supported by the Android runtime, or am I missing additional configuration required for widgets that use the entry property?
Thanks! 🙏
Additional Information (Optional)
I also verified this using the Voltra widget example provided in the documentation/sample project, where the widget displays the current time and updates it using the updateWidgetData function.
Using the same approach, I replaced the time value with an unread message count and attempted to update the widget dynamically. The updated value is successfully received and rendered during serialization (as confirmed by logs and the generated JSON), but the widget itself remains in the loading state and does not display the updated content on the home screen.
This led me to believe that the update flow itself is working, and the issue may be related to how the generated dynamic widget payload is being parsed or rendered by the Android widget runtime when using the entry configuration.