Skip to content

SoDaHo/FMXPluginFramework

Repository files navigation

FMXPluginFramework

A headless, BPL-based plugin framework for Delphi FMX applications. Plugin lifecycle, service registration, event brokering, keybindings, and logging -- with zero UI opinions.

The internal package name is FMXPluginFramework.

Why

Born from porting a monolithic VCL application to FMX for cross-platform support (Windows + Linux), and splitting it into modular, independently deployable plugins along the way. Extracted as a standalone framework so it can be reused across projects and patched independently from any host application. Made open-source to save other Delphi developers the research and boilerplate needed to build a BPL plugin system from scratch.

Key Concepts

  • 100% Headless Core -- The framework .dpk contains only logic. No forms, no menus, no UI.
  • BPL Plugin System -- Plugins are runtime packages (.bpl/.dylib/.so) loaded dynamically via LoadPackage.
  • Self-Registration -- Plugins register in their initialization section. No configuration beyond plugins.json.
  • Shared Singleton -- All BPLs share the same TServiceRegistry instance via runtime-package linking.
  • Optional Helpers -- Ready-made MainForm, Settings UI, Splash, and Bootstrap. Not required.

Architecture

Host App
  |-- links with: rtl, fmx, FMXPluginFramework (runtime packages)
  |-- loads plugins at startup via TBPLLoader
  +-- Plugin A, Plugin B, ... all share TServiceRegistry

Interfaces

Interface Purpose Docs
IPlugin Lifecycle (ID, name, version, description, icon, init, finalize) API, BasicApp
IFrameProvider Plugin provides a TFrame API, BasicApp
IStartupView Plugin declares itself as startup screen (optional) API
IFrameLifecycle Frame reacts to show/hide (optional, iOS-style) API
IPluginSettings Plugin provides settings pages API, BasicApp
IPluginSettingsTree Hierarchical settings tree API, BasicApp
IMenuProvider Plugin defines menus, host builds UI API, BasicApp
INavigationHost Host provides frame navigation API, BasicApp
ILogger File logging with rotation API, BasicApp
IEventBroker Publish/Subscribe events API, EventBrokerDemo
IShortcutRegistry Context-aware keybindings API, ShortcutDemo

Custom interfaces for plugin-to-plugin communication: API, CustomServiceDemo

The loader also provides event hooks for pre-load validation (OnValidateModule), progress reporting (OnProgress), and skip notification (OnModuleSkipped). See API reference.

Quick Start

See the BasicApp example for a complete host app in 5 lines, or the API reference for all details. Minimal host:

begin
  Application.Initialize;
  TPluginBootstrap.Run(
    TBootstrapConfig.Create('MyApp', ExtractFilePath(ParamStr(0))),
    TPluginMainForm);
  TPluginBootstrap.Shutdown;
end.

Critical: The host .dproj must enable "Build with runtime packages" (<DCC_UsePackage>) and include rtl;fmx;FMXPluginFramework. Without runtime packages, the EXE gets its own copy of TServiceRegistry and plugins register in a separate instance. See API reference and Delphi-Specific Notes.

Examples

Demo Shows
BasicApp Full plugin host via TPluginBootstrap. 5 plugin types.
EventBrokerDemo Publish/Subscribe: 4 plugins communicate via topics.
ShortcutDemo Context-aware keybindings per plugin.
CustomServiceDemo Plugin-to-plugin communication via custom interfaces.
SignedPlugins Authenticode signature validation via OnValidateModule.
HashValidation SHA256 hash validation via manifest.
SecureBootstrap Thin bootstrapper with mutual validation.

Requirements

  • Delphi 11.3+ (RAD Studio) -- developed with Delphi 13, tested with Delphi 11.3 for backwards compatibility

Platform Support

Platform Status
Windows (x86/x64) Tested, primary target
Linux (x64) Tested
macOS (x64/ARM) Theoretically supported by FMX + BPL, not tested

FMX and Delphi runtime packages are cross-platform by design. The loader builds platform-specific filenames automatically (Name.bpl on Windows, bplName.dylib on macOS, bplName.so on Linux). The security helpers (TSecurityValidator) use Windows Authenticode and are no-ops on other platforms -- use the hash-based validation (HashValidation) for cross-platform module verification.

Security

BPL plugins are native code that runs directly in your process -- there is no sandbox. For production use:

  • Only load plugins from trusted sources. An untrusted BPL has full access to your application's memory and OS APIs.
  • Validate before loading. Use OnValidateModule with Authenticode signatures (SignedPlugins), SHA256 hashes (HashValidation), or both (SecureBootstrap).
  • Same Delphi version. Framework and all plugins must be compiled with the same Delphi version and runtime packages. Mismatched BPL ABIs cause crashes.
  • The helpers are starting points. TSecurityValidator and TManifestValidator demonstrate the patterns. For production, extend them (e.g. sign the manifest itself, pin certificate thumbprints, add version checks).

Design Philosophy

Interface-based, not TObject-based. All contracts are Delphi interfaces with GUIDs -- type-safe queries, automatic lifetime management, clean separation. Headless core -- the host owns its UI completely. Safe shutdown -- ClearAll releases all references while BPLs are still loaded, preventing Access Violations. Thread-safe -- all registries use TMonitor, callbacks execute outside locks. See the shutdown sequence for details.

Documentation

  • API Reference -- Complete interface, class, and type documentation
  • Examples/ -- Each demo has its own README with practical code

Acknowledgments

Architecture and documentation developed with AI assistance (Claude, Gemini).

License

MIT -- see LICENSE

About

Headless, BPL-based plugin framework for Delphi FMX. Lifecycle, services, events, keybindings, logging - zero UI opinions.

Topics

Resources

License

Stars

Watchers

Forks

Contributors

Languages