Developing Live Activities

Voltra provides APIs that make building and testing Live Activities easier during development.

Supported variants

Live Activities in iOS can appear in different contexts, and Voltra supports defining UI variants for each of these contexts. For detailed information about Live Activity design guidelines, see the Apple Human Interface Guidelines.

Lock Screen

The lockScreen variant defines how your Live Activity appears on the lock screen. It can be either a ReactNode directly, or an object with content and optional styling:

const variants = {
  lockScreen: (
    <Voltra.VStack>
      <Voltra.Text>Your content here</Voltra.Text>
    </Voltra.VStack>
  ),
}

Dynamic Island

The island variant defines how your Live Activity appears in the Dynamic Island (available on iPhone 14 Pro and later). The Dynamic Island has three display states:

  • Minimal: A compact pill-shaped view that appears when the activity is in the background
  • Compact: A slightly larger view with leading and trailing regions
  • Expanded: A full-width view with center, leading, trailing, and bottom regions
const variants = {
  island: {
    keylineTint: '#10B981', // Optional tint color for the Dynamic Island keyline
    minimal: <Voltra.Symbol name="checkmark.circle.fill" tintColor="#10B981" />,
    compact: {
      leading: <Voltra.Text>Order</Voltra.Text>,
      trailing: <Voltra.Text>Confirmed</Voltra.Text>,
    },
    expanded: {
      center: <Voltra.Text style={{ fontSize: 16, fontWeight: '600' }}>Order Confirmed</Voltra.Text>,
      leading: <Voltra.Symbol name="checkmark.circle.fill" />,
      trailing: <Voltra.Text>ETA: 15 min</Voltra.Text>,
      bottom: <Voltra.Text style={{ fontSize: 12 }}>Your order is being prepared</Voltra.Text>,
    },
  },
}

Supplemental Activity Families (iOS 18+, watchOS 11+)

The supplementalActivityFamilies variant defines how your Live Activity appears on Apple Watch Smart Stack and CarPlay displays. This variant is optional and works seamlessly with your existing lock screen and Dynamic Island variants.

const variants = {
  lockScreen: (
    <Voltra.VStack>
      {/* iPhone lock screen content */}
    </Voltra.VStack>
  ),
  island: {
    /* Dynamic Island variants for iPhone */
  },
  supplementalActivityFamilies: {
    small: (
      <Voltra.HStack style={{ padding: 12, gap: 8 }}>
        <Voltra.Text style={{ fontSize: 18, fontWeight: '700' }}>12 min</Voltra.Text>
        <Voltra.Text style={{ fontSize: 14, color: '#9CA3AF' }}>ETA</Voltra.Text>
      </Voltra.HStack>
    ),
  },
}

If supplementalActivityFamilies.small is not provided, Voltra will automatically construct it from your Dynamic Island compact variant by combining the leading and trailing content in an HStack.

useLiveActivity

For React development, Voltra provides the useLiveActivity hook for integration with the component lifecycle and automatic updates during development.

Warning

Unfortunately, iOS suspends background apps after approximately 30 seconds. This means that if you navigate away from your app (for example, to check the Dynamic Island or lock screen), live reload and auto-update functionality will be paused.

import { useLiveActivity } from 'voltra/client'
import { Voltra } from 'voltra'

function OrderLiveActivity({ orderId, status }) {
  const variants = {
    lockScreen: (
      <Voltra.VStack style={{ padding: 16, borderRadius: 18, backgroundColor: '#101828' }}>
        <Voltra.Text style={{ color: '#F8FAFC', fontSize: 18, fontWeight: '600' }}>
          {status === 'confirmed' ? 'Order Confirmed' : 'Order Ready'}
        </Voltra.Text>
        <Voltra.Text style={{ color: '#94A3B8', fontSize: 12, marginTop: 8 }}>
          {status === 'confirmed' ? 'Your order is being prepared' : 'Your order is ready for pickup'}
        </Voltra.Text>
        {status === 'ready' && (
          <Voltra.Button onPress="pickup-order" style={{ marginTop: 12 }}>
            I'm Here
          </Voltra.Button>
        )}
      </Voltra.VStack>
    ),
  }

  const { start, update, end, isActive } = useLiveActivity(variants, {
    activityName: `order-${orderId}`,
    autoStart: true, // Automatically start when component mounts
    autoUpdate: true, // Automatically update when variants change
    deepLinkUrl: `myapp://order/${orderId}`,
  })

  // Manual control if needed
  const handleCancelOrder = async () => {
    await end()
  }

  return (
    <View>
      <Text>Live Activity: {isActive ? 'Active' : 'Inactive'}</Text>
      <Button onPress={handleCancelOrder} title="Cancel Order" />
    </View>
  )
}

VoltraView Component

For testing and development, Voltra provides a VoltraView component that renders Voltra JSX components directly in your React Native app. This is useful for:

  • Testing component layouts before deploying to Live Activities
  • Handling user interactions in development
  • Previewing how your Live Activity will look
import { VoltraView } from 'voltra/client'
import { Voltra } from 'voltra'

function MyComponent() {
  const handleInteraction = (event: VoltraInteractionEvent) => {
    console.log('User interacted with:', event.identifier)
    console.log('Payload:', event.payload)
  }

  return (
    <VoltraView
      id="my-test-view"
      onInteraction={handleInteraction}
      style={{ height: 200, borderRadius: 12, overflow: 'hidden' }}
    >
      <Voltra.VStack style={{ padding: 16, backgroundColor: '#101828' }}>
        <Voltra.Text style={{ color: '#F8FAFC', fontSize: 18, fontWeight: '600' }}>Test Live Activity</Voltra.Text>
        <Voltra.Text style={{ color: '#94A3B8', fontSize: 12, marginTop: 8 }}>This is how it will look</Voltra.Text>
        <Voltra.Button id="test-button" style={{ marginTop: 12 }}>
          <Voltra.Text>Test Button</Voltra.Text>
        </Voltra.Button>
      </Voltra.VStack>
    </VoltraView>
  )
}

Props:

  • id: Unique identifier for the view (used for event filtering)
  • children: Voltra JSX components to render
  • style: React Native style for the container
  • onInteraction: Callback for user interactions with buttons/toggles

**Hook Options:**

- `activityName`: Name of the Live Activity
- `autoStart`: Automatically start when component mounts
- `autoUpdate`: Automatically update when variants change
- `deepLinkUrl`: URL to open when Live Activity is tapped

**Hook Returns:**

- `start()`: Start the Live Activity
- `update()`: Update the Live Activity
- `end()`: Stop the Live Activity
- `isActive`: Boolean indicating if the Live Activity is currently active

Need React or React Native expertise you can count on?