Plugin Configuration (Android)

The Voltra Expo config plugin accepts Android-specific configuration options in your app.json or app.config.js:

{
  "expo": {
    "plugins": [
      [
        "voltra",
        {
          "groupIdentifier": "group.your.bundle.identifier",
          "android": {
            "enableNotifications": true,
            "widgets": [
              {
                "id": "weather",
                "displayName": "Weather Widget",
                "description": "Shows current weather conditions",
                "targetCellWidth": 2,
                "targetCellHeight": 2,
                "initialStatePath": "./widgets/weather-initial.tsx",
                "previewImage": "./assets/widgets/weather-preview.png"
              }
            ]
          }
        }
      ]
    ]
  }
}

Android-Specific Configuration

android.enableNotifications (optional)

Enables Android notification-related manifest plumbing used by Voltra features such as ongoing notifications.

When enabled, the config plugin adds:

  • android.permission.POST_NOTIFICATIONS
  • android.permission.POST_PROMOTED_NOTIFICATIONS
  • voltra.VoltraOngoingNotificationDismissedReceiver

This does not grant runtime notification permission automatically. Your app still needs to request notification permission on Android 13 and above.

For setup and usage examples, see Managing Android Ongoing Notifications.

android.widgets (optional)

Array of widget configurations for Home Screen widgets. Each widget will be available in the Android widget picker.

Widget Configuration Properties:

  • id: Unique identifier for the widget (alphanumeric with underscores only)
  • displayName: Name shown in the widget picker
  • description: Description shown in the widget picker
  • targetCellWidth: Target widget width in grid cells (1-5, required)
  • targetCellHeight: Target widget height in grid cells (1-5, required)
  • minCellWidth: (optional) Minimum width in grid cells (defaults to targetCellWidth)
  • minCellHeight: (optional) Minimum height in grid cells (defaults to targetCellHeight)
  • minWidth: (optional) Minimum width in dp (overrides minCellWidth calculation)
  • minHeight: (optional) Minimum height in dp (overrides minCellHeight calculation)
  • resizeMode: (optional) Widget resize behavior ("none" | "horizontal" | "vertical" | "horizontal|vertical", default: "horizontal|vertical")
  • widgetCategory: (optional) Widget category ("home_screen" | "keyguard" | "home_screen|keyguard", default: "home_screen")
  • initialStatePath: (optional) Path to a file that exports initial widget state (see Widget Pre-rendering)
  • previewImage: (optional) Path to preview image for widget picker (PNG/JPG/WebP)
  • previewLayout: (optional) Path to custom XML layout for widget picker preview (Android 12+)
  • serverUpdate: (optional) Enable server-driven updates. See Server-driven widgets for full details.
    • url: The Voltra SSR endpoint URL
    • intervalMinutes: Update interval in minutes (default: 15, minimum 15 per WorkManager)
    • refresh: Show a native refresh button (default: false)

Widget Sizing

Grid Cells vs Density-Independent Pixels (dp)

Android uses grid cells to define widget sizes. By default, the formula is:

  • minWidth/minHeight (dp) = (cellCount × 70) - 30

Example:

  • 2 cells = (2 × 70) - 30 = 110 dp
  • 4 cells = (4 × 70) - 30 = 250 dp

You can override this with explicit minWidth and minHeight in dp.

Standard Dimensions

FamilyCellsDefault DPTypical Use
Small2×1110 × 40Quick glance info
Medium2×2110 × 110Main widget size
Large4×2250 × 110Rich content
Extra Large4×4250 × 250Complex layouts

Widget Picker Previews

When users add a widget to their home screen, Android displays a preview in the widget picker. Voltra supports three preview methods, with automatic fallback:

Preview Priority Chain

  1. previewLayout (Android 12+) - Custom XML layout for scalable preview
  2. previewImage (All versions) - Static image or auto-generated layout
  3. Default - System placeholder layout

Using previewImage

Static preview image for all Android versions:

{
  "widgets": [
    {
      "id": "weather",
      "displayName": "Weather Widget",
      "targetCellWidth": 2,
      "targetCellHeight": 2,
      "previewImage": "./assets/widgets/weather-preview.png"
    }
  ]
}

When only previewImage is specified, Voltra automatically generates a layout that displays the image with proper scaling.

Using previewLayout

Custom XML layout for scalable previews (Android 12+):

{
  "widgets": [
    {
      "id": "todos",
      "displayName": "Todo Widget",
      "targetCellWidth": 2,
      "targetCellHeight": 2,
      "previewLayout": "./assets/widgets/todos-preview.xml"
    }
  ]
}

Example todos-preview.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="16dp"
    android:background="#FFFFFF">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Todo List"
        android:textSize="18sp"
        android:textStyle="bold" />

    <!-- Add more layout elements here -->

</LinearLayout>

The preview layout is rendered at the widget's target size and displayed in the widget picker.

Combined Preview Setup

For best results across Android versions:

{
  "widgets": [
    {
      "id": "weather",
      "displayName": "Weather Widget",
      "targetCellWidth": 2,
      "targetCellHeight": 2,
      "previewImage": "./assets/widgets/weather-preview.png",
      "previewLayout": "./assets/widgets/weather-preview.xml",
      "initialStatePath": "./widgets/weather-initial.tsx"
    }
  ]
}

This configuration:

  • Uses previewLayout on Android 12+ (scalable, accurate preview)
  • Falls back to previewImage on Android 11 and earlier
  • Shows actual widget content on home screen via initialStatePath (when available)

Widget Pre-rendering

Use initialStatePath to provide pre-rendered widget state:

{
  "widgets": [
    {
      "id": "weather",
      "displayName": "Weather Widget",
      "targetCellWidth": 2,
      "targetCellHeight": 2,
      "initialStatePath": "./widgets/weather-initial.tsx"
    }
  ]
}

When the app is built, Voltra pre-renders the widget at the specified path and bundles it as voltra_initial_states.json. The widget displays this content immediately when first added to the home screen, before any dynamic updates.

See Widget Pre-rendering for details on creating initial state files.

Example Configuration

{
  "expo": {
    "plugins": [
      [
        "voltra",
        {
          "groupIdentifier": "group.com.example.app",
          "android": {
            "enableNotifications": true,
            "widgets": [
              {
                "id": "voltra",
                "displayName": "Voltra Widget",
                "description": "Voltra logo widget",
                "minCellWidth": 2,
                "minCellHeight": 2,
                "targetCellWidth": 2,
                "targetCellHeight": 2,
                "resizeMode": "horizontal|vertical",
                "widgetCategory": "home_screen",
                "initialStatePath": "./widgets/android-voltra-widget-initial.tsx",
                "previewImage": "./assets/voltra-icon.jpg"
              },
              {
                "id": "interactive_todos",
                "displayName": "Interactive Todos",
                "description": "Quick todo list widget",
                "targetCellWidth": 2,
                "targetCellHeight": 2,
                "previewLayout": "./assets/widgets/todos-preview.xml"
              }
            ]
          }
        }
      ]
    ]
  }
}

Need React or React Native expertise you can count on?