StreamVault Plugin API

May 14, 2026 ยท View on GitHub

StreamVault plugins are companion Android APKs. They do not inject code into the main application. Instead, StreamVault discovers installed APKs that expose a bound service with the action com.streamvault.plugin.API and talks to them through Android Messenger IPC.

This keeps the plugin boundary installable, removable, and compatible with Android package isolation while still allowing plugins to add provider, playback, Cast, and configuration capabilities. Configuration can be rendered by StreamVault from a declarative schema, or opened as a native plugin Activity when the plugin needs a richer UI.

Package Discovery

The host queries services for:

<action android:name="com.streamvault.plugin.API" />

The host app must declare the same action in <queries>. Plugin APKs should declare an exported service:

<service
    android:name=".MyPluginService"
    android:exported="true">
    <intent-filter>
        <action android:name="com.streamvault.plugin.API" />
    </intent-filter>
</service>

Plugins can be installed from:

  • A direct HTTP/HTTPS APK URL.
  • A local APK selected with the system file picker.
  • Any manual Android package install. StreamVault detects it after refreshing the Plugins screen.

Manifest

StreamVault first asks the plugin service for its manifest. As a fallback, it reads com.streamvault.plugin.MANIFEST_JSON service metadata, then individual metadata fields if the JSON is missing or invalid.

Example manifest for host-rendered configuration:

{
  "schemaVersion": 1,
  "id": "com.example.plugin",
  "name": "Example Plugin",
  "versionName": "1.0.0",
  "versionCode": 1,
  "description": "Adds external capabilities to StreamVault.",
  "providerName": "Example Provider",
  "configurationMode": "host.schema",
  "configurationActivityAction": "",
  "capabilities": [
    "provider.m3u",
    "playback.prepare",
    "cast.rewriteUrl",
    "configuration.schema"
  ]
}

Example manifest for native Activity configuration:

{
  "schemaVersion": 1,
  "id": "com.example.richplugin",
  "name": "Example Rich Plugin",
  "versionName": "1.0.0",
  "versionCode": 1,
  "description": "Adds a rich native configuration surface.",
  "providerName": "Example Provider",
  "configurationMode": "activity",
  "configurationActivityAction": "com.example.richplugin.CONFIGURE",
  "capabilities": [
    "provider.m3u",
    "configuration.activity"
  ]
}

Recommended fallback metadata:

<meta-data android:name="com.streamvault.plugin.ID" android:value="com.example.plugin" />
<meta-data android:name="com.streamvault.plugin.NAME" android:value="Example Plugin" />
<meta-data android:name="com.streamvault.plugin.VERSION_NAME" android:value="1.0.0" />
<meta-data android:name="com.streamvault.plugin.VERSION_CODE" android:value="1" />
<meta-data android:name="com.streamvault.plugin.DESCRIPTION" android:value="Adds external capabilities to StreamVault." />
<meta-data android:name="com.streamvault.plugin.PROVIDER_NAME" android:value="Example Provider" />
<meta-data android:name="com.streamvault.plugin.CONFIGURATION_MODE" android:value="host.schema" />
<meta-data android:name="com.streamvault.plugin.CONFIGURATION_ACTIVITY_ACTION" android:value="" />
<meta-data android:name="com.streamvault.plugin.CAPABILITIES" android:value="provider.m3u,playback.prepare,cast.rewriteUrl,configuration.schema" />

For Activity configuration, set CONFIGURATION_MODE to activity, set CONFIGURATION_ACTIVITY_ACTION, and advertise configuration.activity.

Capability names:

  • provider.m3u: the plugin can expose an M3U URL that StreamVault imports as a provider when enabled.
  • playback.prepare: the plugin can prepare a stream URL before playback starts.
  • cast.rewriteUrl: the plugin can rewrite a playback URL before Google Cast loads it.
  • configuration.schema: the plugin exposes a declarative configuration schema that StreamVault renders with its own UI.
  • configuration.activity: the plugin exposes a native Android Activity that StreamVault opens for configuration.

IPC Messages

Every request includes:

  • api_version: current value is 1.
  • request_id: opaque ID copied back by the plugin response.

Every response should include:

  • api_version
  • request_id
  • success
  • Optional message

Messages:

IDNamePurpose
1MSG_GET_MANIFESTReturn manifest_json.
2MSG_SET_ENABLEDStart or stop plugin functionality using enabled.
3MSG_GET_STATUSReturn a short status_label and optional message.
4MSG_GET_PROVIDER_URLReturn url and optional provider_name.
5MSG_PREPARE_PLAYBACKPrepare input_url; set handled when relevant.
6MSG_REWRITE_CAST_URLRewrite input_url; return output_url when relevant.
7MSG_GET_CONFIGURATION_SCHEMAReturn configuration_schema_json.
8MSG_GET_CONFIGURATION_VALUESReturn configuration_values_json.
9MSG_SET_CONFIGURATION_VALUESPersist configuration_values_json.
10MSG_RUN_CONFIGURATION_ACTIONRun configuration_action_id.

For playback.prepare and cast.rewriteUrl, plugins should set handled=false when the URL is not theirs. StreamVault then continues with other enabled plugins or the original URL.

MSG_PREPARE_PLAYBACK may also enrich the stream that StreamVault sends to the player. When handled=true and success=true, the plugin can return:

  • output_url: final playable URL. If omitted, StreamVault keeps input_url.
  • stream_type: optional playback hint. Supported values are DASH, HLS, SMOOTH_STREAMING, MPEG_TS, PROGRESSIVE, and RTSP.
  • headers_json: JSON object with HTTP request headers for the media request.
  • user_agent: optional user agent applied to the media request.
  • drm_json: JSON object with DRM information:
{
  "scheme": "clearkey",
  "licenseUrl": "http://127.0.0.1:39077/license/clearkey/channel-id",
  "headers": {
    "Authorization": "Bearer token"
  },
  "multiSession": false,
  "forceDefaultLicenseUrl": true,
  "playClearContentWithoutKey": true
}

scheme accepts widevine, playready, clearkey, or their platform UUID aliases (com.widevine.alpha, com.microsoft.playready, org.w3.clearkey). For SMOOTH_STREAMING + clearkey, StreamVault normalizes the ISML ProtectionHeader into ClearKey PSSH v1 init data before creating the Android MediaDrm session.

Choosing a Configuration Mode

Plugins should choose one primary configuration mode.

Use host.schema when the configuration is mostly fields, switches, selects, and simple actions. StreamVault owns the visual shell, validation placement, focus behavior, typography, controls, and feedback.

Use activity when the plugin needs a custom or highly interactive configuration surface, for example:

  • Runtime dashboards with live state.
  • Source managers with add/edit/delete flows.
  • Channel testing workflows.
  • Embedded logs.
  • Native pairing, sign-in, or device setup.
  • Custom layouts that must look the same when opened directly and from StreamVault.

Do not advertise configuration.schema for a partial or stale schema. If configurationMode is activity, StreamVault treats the Activity as the active configuration path and opens configurationActivityAction instead of loading a host-rendered schema.

For backward compatibility, a plugin that omits configurationMode but advertises configuration.schema is treated as host-rendered. New plugins should set configurationMode explicitly.

Host-Rendered Configuration

Host-rendered configuration lets a plugin describe fields and actions while StreamVault owns the visual implementation.

A plugin opts in with:

  • Manifest field configurationMode: "host.schema".
  • Capability configuration.schema.
  • IPC handlers for messages 7 through 10.

Schema response:

{
  "schemaVersion": 1,
  "title": "Example Plugin",
  "description": "Settings rendered by StreamVault.",
  "sections": [
    {
      "id": "connection",
      "title": "Connection",
      "description": "Endpoint used by this plugin.",
      "fields": [
        {
          "key": "serverUrl",
          "type": "url",
          "label": "Server URL",
          "placeholder": "http://192.168.1.20:8080",
          "required": true
        },
        {
          "key": "token",
          "type": "password",
          "label": "Token",
          "secret": true
        },
        {
          "key": "lanMode",
          "type": "boolean",
          "label": "LAN mode",
          "description": "Expose local URLs to other devices."
        },
        {
          "key": "quality",
          "type": "select",
          "label": "Preferred quality",
          "options": [
            { "value": "auto", "label": "Auto" },
            { "value": "1080p", "label": "1080p" }
          ]
        },
        {
          "key": "status",
          "type": "info",
          "label": "Status",
          "readOnly": true
        }
      ]
    }
  ],
  "actions": [
    {
      "id": "testConnection",
      "label": "Test connection",
      "description": "Ask the plugin to validate its current settings.",
      "refreshAfterRun": true
    }
  ]
}

Supported field types:

  • info: read-only text rendered by StreamVault.
  • text: single-line text.
  • password: single-line secret text.
  • url: URL text field.
  • number: numeric text field.
  • boolean: switch.
  • select: one value from options.
  • textarea: multi-line text.

Values response:

{
  "serverUrl": "http://192.168.1.20:8080",
  "token": "",
  "lanMode": true,
  "quality": "auto",
  "status": "Ready"
}

For MSG_SET_CONFIGURATION_VALUES, StreamVault sends the same JSON object in configuration_values_json. Plugins should persist supported writable keys, ignore unknown or read-only keys, and return success=false with message when validation fails.

For MSG_RUN_CONFIGURATION_ACTION, StreamVault sends configuration_action_id. Plugins should execute the action, return a user-facing message, and refresh their values when refreshAfterRun is true.

Configuration Activity Mode

Activity configuration lets the plugin own the complete configuration UI. StreamVault starts configurationActivityAction with the plugin package set explicitly, so the action does not resolve to another app.

A plugin opts in with:

  • Manifest field configurationMode: "activity".
  • Capability configuration.activity.
  • Manifest field configurationActivityAction.
  • An exported Activity with an intent filter for that action and the DEFAULT category.

Example:

<activity
    android:name=".MyConfigActivity"
    android:exported="true"
    android:label="@string/app_name">
    <intent-filter>
        <action android:name="com.example.richplugin.CONFIGURE" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>

Use Activity mode for flows that cannot be represented faithfully as fields and actions. The HaP plugin is the reference example: it uses Activity mode for runtime state, source management, custom AceStream channels, channel tests, connected clients, and logs.

Native Activity Visual Guidance

Native plugin Activities should feel at home when launched from StreamVault and remain usable when opened directly from Android or Android TV.

Recommended visual and interaction rules:

  • Design TV-first: every important control must be D-pad focusable and readable from couch distance.
  • Keep the style restrained and close to StreamVault: dark background, compact panels, clear focus states, and meaningful status colors for running, stopped, warning, and error states.
  • Collapse heavy or secondary sections by default, especially logs, source editors, and long channel-status lists.
  • Keep layout dimensions stable. Avoid buttons, rows, or status chips changing size when text or loading state changes.
  • Truncate or wrap long URLs, channel names, and error messages so text never overlaps adjacent controls.
  • Use Android resources and the system locale for all user-facing text.
  • Show direct feedback for loading, validation, success, and failure states.
  • Test both entry points: launched directly from the plugin APK and launched from StreamVault's Plugins screen.
  • Test on the same device classes StreamVault supports, including TV devices such as Chromecast and phone-sized devices such as Nexus 5X.

Integration Checklist

Before publishing a plugin:

  • Expose exactly one com.streamvault.plugin.API service.
  • Return a complete manifest from MSG_GET_MANIFEST.
  • Keep service metadata in sync with the runtime manifest as fallback.
  • Choose host.schema or activity as the primary configuration mode.
  • Advertise only capabilities that are fully implemented.
  • Validate user-provided URLs and secrets inside the plugin before persisting them.
  • Return user-facing error messages from IPC failures.
  • Verify install, enable, disable, configure, provider URL, playback prepare, and Cast URL rewrite on real devices.