Generated targets
The config plugin, or npx voltra apply, creates and updates the extension targets for you.
Voltra turns JSX into SwiftUI and Jetpack Compose Glance. You and your agent ship Live Activities, Dynamic Island layouts and widgets on iOS and Android without writing Swift or Kotlin.
Works with Live Activities, Dynamic Island, iOS widgets, Android widgets, Ongoing notifications, SwiftUI, Jetpack Compose Glance, Expo, React Native CLI, APNs, FCM.
[01] What you get
Lock screen and Dynamic Island layouts, started and updated from JS.
Read moreWidgets on iOS and Android, from the same React workflow.
Read morePersistent status updates on Android, built in JSX.
Read moreRender on your server and send over APNs or FCM.
Read moreWidgets fetch their own content from your server, per instance.
Read moreVoltraWidgetPreview renders a widget inside your app while you build it.
React Native style props, plus SwiftUI and Glance modifiers where you need them.
Read moreuseLiveActivity reloads your Live Activity as you edit, with no rebuild.
[02] Push updates
Render a Live Activity on your server from the same components and send it over APNs. Widgets update over FCM on Android. Your app doesn’t need to be running.
Read the push guideimport { Voltra, renderLiveActivityToString } from '@use-voltra/ios-server'
const payload = renderLiveActivityToString({
lockScreen: (
<Voltra.VStack style={{ padding: 16 }}>
<Voltra.Text>Driver arrived</Voltra.Text>
<Voltra.Text>Ready for pickup</Voltra.Text>
</Voltra.VStack>
),
})[03] How it works
import { Voltra } from '@use-voltra/ios'
import { startLiveActivity } from '@use-voltra/ios-client'
const ui = (
<Voltra.VStack style={{ padding: 16 }}>
<Voltra.Symbol name="car.fill" />
<Voltra.Text>Driver en route</Voltra.Text>
<Voltra.Text>ETA 12 min</Voltra.Text>
</Voltra.VStack>
)
await startLiveActivity({ lockScreen: ui })Preview
Add the platform package for JSX and the client package for runtime APIs.
$ npm install @use-voltra/ios @use-voltra/ios-clientAdd the Voltra plugin to app.json. It wires the widget and Live Activity extension targets.
app.json → pluginsGenerate the native projects, then start your app as usual.
$ npx expo prebuild --cleanimport { Voltra } from '@use-voltra/ios'
import { useLiveActivity } from '@use-voltra/ios-client'
export function OrderTracker({ orderId }: { orderId: string }) {
const ui = (
<Voltra.VStack style={{ padding: 16 }}>
<Voltra.Text>Order #{orderId}</Voltra.Text>
<Voltra.Text>Driver en route · ETA 12 min</Voltra.Text>
</Voltra.VStack>
)
useLiveActivity({ lockScreen: ui }, {
activityName: `order-${orderId}`,
autoStart: true,
})
return null
}@use-voltra/ios-clientLive Activities, Dynamic Island and home screen widgets, rendered as SwiftUI.Set up iOS import { VoltraAndroid } from '@use-voltra/android'
import { updateAndroidWidget } from '@use-voltra/android-client'
await updateAndroidWidget(
'my_widget',
<VoltraAndroid.Column style={{ padding: 16 }}>
<VoltraAndroid.Text>Driver en route</VoltraAndroid.Text>
<VoltraAndroid.Text>ETA 12 min</VoltraAndroid.Text>
</VoltraAndroid.Column>
)@use-voltra/android-clientHome screen widgets and ongoing notifications, rendered as Jetpack Compose Glance.Set up Android import { Voltra, renderLiveActivityToString } from '@use-voltra/ios-server'
const payload = renderLiveActivityToString({
lockScreen: (
<Voltra.VStack style={{ padding: 16 }}>
<Voltra.Text>Driver arrived</Voltra.Text>
<Voltra.Text>Ready for pickup</Voltra.Text>
</Voltra.VStack>
),
})[04] Native, without native code
The config plugin, or npx voltra apply, creates and updates the extension targets for you.
Both the JS and native layers check payload sizes against each platform’s limits.
@use-voltra/ios-server and @use-voltra/android-server render payloads in your backend, apart from the app.
Components, hooks and the plugin config ship TypeScript definitions.
[05] FAQ
npx voltra apply updates the native project instead of the Expo config plugin.@use-voltra/ios-server renders the same JSX to a payload you send over APNs, and @use-voltra/android-server does the same for widgets over FCM.