Skip to content

Plugin System Implementation - v1 (android)#201

Open
mayansharma wants to merge 3 commits intomainfrom
feat/plugin
Open

Plugin System Implementation - v1 (android)#201
mayansharma wants to merge 3 commits intomainfrom
feat/plugin

Conversation

@mayansharma
Copy link
Collaborator

@mayansharma mayansharma commented Mar 2, 2026

Android Internal Plugin System (Current PR State)

Context

This change evolves the earlier plugin work into an internal-only plugin architecture for Android, intended to migrate existing NativeBridge features gradually into internal plugins.

Key intent:

  1. no external/app plugin authoring for now,
  2. core team owns plugin implementation,
  3. end-users only toggle features via WEBVIEW_CONFIG.

What’s Included

1) Isolated plugin bridge surface (web)

Export:

  1. catalyst-core/PluginBridge

API:

  1. bridge.init()
  2. bridge.emit({ pluginId, command, data })
  3. bridge.callback({ pluginId, eventName, handler })
  4. bridge.unregister({ pluginId, eventName })

2) Android runtime plugin dispatch

Runtime path:

  1. PluginBridge.kt receives JSON payload from JS.
  2. Validates pluginId and command from generated index.
  3. Instantiates plugin and invokes handle(command, data, bridge).
  4. Plugin emits callbacks through PluginBridgeContext.callback(...).
  5. Errors are routed via __bridge__/PLUGIN_BRIDGE_ERROR.

3) Internal-only plugin composition (Android)

Composer now discovers plugins only from core internal directories:

  1. src/native/internal-plugins
  2. packaged dist/native/internal-plugins

No app-level discovery from <app-root>/plugin|plugins|catalyst-plugins.


4) Config-driven feature toggles (WEBVIEW_CONFIG.plugins)

Users control plugin enablement only from config/config.json:

{
    "WEBVIEW_CONFIG": {
        "plugins": {
            "echo": true
        }
    }
}

Toggle resolution:

  1. match manifest.configKey first,
  2. fallback to plugin id,
  3. unknown toggle keys hard-fail build,
  4. conflicting configKey + id values hard-fail build.

Default policy:

  1. plugins are disabled by default unless explicitly set true.

5) Strict cleanup semantics

Composer now reconciles plugin mutations strictly on each build:

  1. generated plugin source tree is rewritten,
  2. plugin assets are rewritten,
  3. plugin-managed Android permissions are reconciled (including legacy cleanup),
  4. plugin-managed Gradle dependencies are reconciled (including legacy cleanup).

This ensures disabling a plugin removes its managed side effects from composed outputs.


6) Manifest contract (Android, current)

Required:

  1. id
  2. version
  3. commands (non-empty)
  4. android.className

Optional:

  1. configKey (recommended for user-facing toggle names)
  2. callbacks
  3. android.permissions
  4. android.dependencies

Example Internal Plugin (Echo)

Folder:

src/native/internal-plugins/echo-plugin/
  manifest.json
  android/io/yourname/androidproject/plugins/internal/echo/EchoPlugin.kt

Manifest:

{
    "id": "io.catalyst.echo",
    "configKey": "echo",
    "version": "1.0.0",
    "commands": ["log"],
    "callbacks": ["onLogged"],
    "android": {
        "className": "io.yourname.androidproject.plugins.internal.echo.EchoPlugin",
        "permissions": [],
        "dependencies": []
    }
}

Web usage:

import pluginBridge from "catalyst-core/PluginBridge"

pluginBridge.init()

pluginBridge.callback({
    pluginId: "io.catalyst.echo",
    eventName: "onLogged",
    handler: (payload) => console.log("native callback", payload),
})

pluginBridge.emit({
    pluginId: "io.catalyst.echo",
    command: "log",
    data: { message: "Echo log from web" },
})

@deputydev-agent
Copy link

DeputyDev will no longer review pull requests automatically.To request a review, simply comment #review on your pull request—this will trigger an on-demand review whenever you need it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant