Skip to content

feat: add registerPlugin so a plugin can be added after the client starts - #522

Open
abelonogov-ld wants to merge 1 commit into
v11from
andrey/register-plugin
Open

feat: add registerPlugin so a plugin can be added after the client starts#522
abelonogov-ld wants to merge 1 commit into
v11from
andrey/register-plugin

Conversation

@abelonogov-ld

@abelonogov-ld abelonogov-ld commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Summary

Plugins could only be supplied through LDConfig, so an integration that learns about a plugin later — or that wants to instrument a client it did not configure — had no way in. This adds LDClient.registerPlugin(_:), matching the method the .NET and Flutter SDKs already expose and the one being added to the Android SDK in launchdarkly/android-client-sdk#393.

  • Hooks became mutable, because registration after start cannot extend a constant array. They now live in a private var behind an NSLock and are replaced rather than mutated in place. Each series reads a snapshot once into a local, so the hooks a series ends with are the hooks it began with — were the array read again mid-series, a hook registered in between would be handed an after stage for a series whose before stage it was never in. The three read sites (evaluateWithHooks, executeBeforeIdentifyHooks, executeAfterTrackHooks) all take that snapshot up front.
  • Hooks go live only once register returns. This matches the Android and .NET ordering, and differs from configuration-time registration where a plugin's hooks are active before register is called. So a plugin's own hooks will not observe evaluations or identify calls its register makes; everything afterwards does run them.
  • EnvironmentMetadata is retained on the instance, so a plugin registered later is handed the same environment description as one configured up front. This also removes the duplicate construction that previously existed in both start and collectHooks.

Registration applies to the one client it is called on, so a multi-environment setup means calling it per environment.

Note that the iOS Plugin protocol has no onPluginsReady, so unlike Android this path is just getHooks then register then activate.

Test plan

Five cases added to LDClientPluginsSpec, all passing on an iPhone 16e simulator alongside the two pre-existing plugin tests (7 total):

  • testRegisterPluginPassesClientAndEnvironmentMetadata
  • testRegisterPluginActivatesBundledHooks
  • testRegisterPluginDoesNotRunTheRegisteringPluginsOwnHooks
  • testRegisterPluginHooksRunAfterConfiguredHooks
  • testRegisterPluginAppliesOnlyToTheClientItIsCalledOn
  • SwiftLint introduces no new violations in the touched files

Note

Overview
Adds LDClient.registerPlugin(_:) so a plugin can be attached after start, not only via LDConfig.plugins. Registration is per client (call it on each environment in a multi-env setup).

Hooks are no longer a constant array: they sit behind an NSLock, and each evaluation/identify/track series snapshots them once so a hook registered mid-series never gets an after without a matching before. register runs before those hooks go live, so a plugin’s own hooks do not observe work done inside register. EnvironmentMetadata is stored on the client so late plugins get the same description as config-time ones.

Reviewed by Cursor Bugbot for commit 5798e94. Bugbot is set up for automated code reviews on this repo. Configure here.

…arts

Plugins could only be supplied through LDConfig, so an integration that
learns about a plugin later — or that wants to instrument a client it did
not configure — had no way in.

Hooks were held in a constant array, which registration after start cannot
extend, so they now live behind a lock and are replaced rather than mutated
in place. Each series reads a snapshot once, so the hooks a series ends with
are the hooks it began with: read again mid-series, a hook registered in
between would be handed an "after" stage for a series whose "before" stage
it was never in.

Hooks go live only once register returns, matching the Android and .NET
ordering, so a plugin's own hooks do not observe its register call.
Retaining EnvironmentMetadata on the instance lets a plugin registered
later be handed the same environment description as one configured up
front, and removes the duplicate construction in start and collectHooks.

Co-authored-by: Cursor <cursoragent@cursor.com>
@abelonogov-ld
abelonogov-ld requested a review from a team as a code owner August 21, 2026 20:31
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