Skip to content

[FSSDK-12503] fix: guard detachFromEngine from multi-engine channel teardown#105

Merged
muzahidul-opti merged 1 commit intomasterfrom
fix/FSSDK-12503-detach-engine-guard
Apr 30, 2026
Merged

[FSSDK-12503] fix: guard detachFromEngine from multi-engine channel teardown#105
muzahidul-opti merged 1 commit intomasterfrom
fix/FSSDK-12503-detach-engine-guard

Conversation

@muzahidul-opti
Copy link
Copy Markdown
Contributor

Summary

  • Android: onDetachedFromEngine now checks if the detaching engine's BinaryMessenger matches the one that created the channel — skips cleanup if it doesn't match
  • iOS: detachFromEngine now compares registrar.messenger() against the stored attachedMessenger — skips cleanup if they differ
  • Fixes the case where a secondary Flutter engine (e.g. Firebase background messaging) detaching would destroy the primary engine's MethodChannel, breaking all SDK calls and notification callbacks

Context

The onAttachedToEngine/register fix from #103 correctly guards against channel overwrite on attach (if channel != null { return }). But onDetachedFromEngine/detachFromEngine unconditionally nils the channel — so when the secondary engine detaches, it destroys the primary engine's channel.

Test plan

  • Run multi-engine notification listener integration test on Android emulator
  • Run multi-engine notification listener integration test on iOS simulator
  • Verify decision listener fires after second engine is created
  • Verify track listener fires after second engine is created
  • Verify decision listener works after second engine is destroyed (new test case)

🤖 Generated with Claude Code

…engine (FSSDK-12503)

onDetachedFromEngine/detachFromEngine was unconditionally clearing the
static MethodChannel, even when a secondary engine (e.g. Firebase
background messaging) detached. This destroyed the primary engine's
channel and broke all SDK calls and notification callbacks.

Store the BinaryMessenger that created the channel during attach, and
only clear the channel in detach if the detaching engine's messenger
matches the stored one.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@muzahidul-opti muzahidul-opti changed the title fix: guard detachFromEngine from multi-engine channel teardown (FSSDK-12503) [FSSDK-12503] fix: guard detachFromEngine from multi-engine channel teardown Apr 30, 2026
@raju-opti raju-opti requested a review from Copilot April 30, 2026 12:47
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Guards native plugin teardown so a secondary Flutter engine (e.g., background messaging) detaching doesn’t destroy the primary engine’s MethodChannel and break SDK calls/callbacks.

Changes:

  • iOS: Track the messenger used to create the MethodChannel and skip detachFromEngine cleanup when a different engine is detaching.
  • Android: Track the BinaryMessenger that created the MethodChannel and skip onDetachedFromEngine cleanup when the detaching engine uses a different messenger.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
ios/Classes/SwiftOptimizelyFlutterSdkPlugin.swift Stores the attached messenger and gates channel cleanup in detachFromEngine based on messenger identity.
android/src/main/java/com/optimizely/optimizely_flutter_sdk/OptimizelyFlutterSdkPlugin.java Stores the attached BinaryMessenger and gates channel cleanup in onDetachedFromEngine based on messenger identity.
Comments suppressed due to low confidence (2)

ios/Classes/SwiftOptimizelyFlutterSdkPlugin.swift:56

  • In register(with:), you now store let messenger = registrar.messenger(), but the logger channel setup still calls registrar.messenger() again. Reuse the messenger variable (including for makeBackgroundTaskQueue) so both channels are guaranteed to use the same messenger instance and to avoid redundant lookups.
        let messenger = registrar.messenger()
        attachedMessenger = messenger
        channel = FlutterMethodChannel(name: "optimizely_flutter_sdk", binaryMessenger: messenger)
        let instance = SwiftOptimizelyFlutterSdkPlugin()
        registrar.addMethodCallDelegate(instance, channel: channel)

        // Separate logger channel for outgoing log calls
        let taskQueue = registrar.messenger().makeBackgroundTaskQueue?()
        let loggerChannel = FlutterMethodChannel(name: OptimizelyFlutterLogger.LOGGER_CHANNEL, 
                                                binaryMessenger: registrar.messenger(), 
                                                codec: FlutterStandardMethodCodec.sharedInstance(),
                                                taskQueue: taskQueue)

android/src/main/java/com/optimizely/optimizely_flutter_sdk/OptimizelyFlutterSdkPlugin.java:226

  • onAttachedToEngine stores the engine messenger in attachedMessenger, but the logger channel is still created with a fresh binding.getBinaryMessenger() call. Prefer using attachedMessenger for the logger channel as well to ensure both channels are tied to the same messenger instance and to avoid unnecessary duplicate lookups.
    attachedMessenger = binding.getBinaryMessenger();
    channel = new MethodChannel(attachedMessenger, "optimizely_flutter_sdk");
    channel.setMethodCallHandler(this);
    context = binding.getApplicationContext();

    MethodChannel loggerChannel = new MethodChannel(binding.getBinaryMessenger(), FlutterLogbackAppender.CHANNEL_NAME);
    FlutterLogbackAppender.setChannel(loggerChannel);

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@muzahidul-opti muzahidul-opti merged commit 85e1638 into master Apr 30, 2026
12 of 13 checks passed
@muzahidul-opti muzahidul-opti deleted the fix/FSSDK-12503-detach-engine-guard branch April 30, 2026 12:59
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.

3 participants