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.
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.
- 100% Headless Core -- The framework
.dpkcontains only logic. No forms, no menus, no UI. - BPL Plugin System -- Plugins are runtime packages (
.bpl/.dylib/.so) loaded dynamically viaLoadPackage. - Self-Registration -- Plugins register in their
initializationsection. No configuration beyondplugins.json. - Shared Singleton -- All BPLs share the same
TServiceRegistryinstance via runtime-package linking. - Optional Helpers -- Ready-made MainForm, Settings UI, Splash, and Bootstrap. Not required.
Host App
|-- links with: rtl, fmx, FMXPluginFramework (runtime packages)
|-- loads plugins at startup via TBPLLoader
+-- Plugin A, Plugin B, ... all share TServiceRegistry
| 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.
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.
| 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. |
- Delphi 11.3+ (RAD Studio) -- developed with Delphi 13, tested with Delphi 11.3 for backwards compatibility
| 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.
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
OnValidateModulewith 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.
TSecurityValidatorandTManifestValidatordemonstrate the patterns. For production, extend them (e.g. sign the manifest itself, pin certificate thumbprints, add version checks).
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.
- API Reference -- Complete interface, class, and type documentation
- Examples/ -- Each demo has its own README with practical code
Architecture and documentation developed with AI assistance (Claude, Gemini).
MIT -- see LICENSE