From 2130160b49bdf223dea5dc8b20f26dfe9e1eb990 Mon Sep 17 00:00:00 2001 From: muzahidul-opti Date: Thu, 30 Apr 2026 11:12:03 +0600 Subject: [PATCH] fix: guard detachFromEngine to only clear channel owned by detaching 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 --- .../OptimizelyFlutterSdkPlugin.java | 9 ++++++++- ios/Classes/SwiftOptimizelyFlutterSdkPlugin.swift | 11 +++++++++-- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/android/src/main/java/com/optimizely/optimizely_flutter_sdk/OptimizelyFlutterSdkPlugin.java b/android/src/main/java/com/optimizely/optimizely_flutter_sdk/OptimizelyFlutterSdkPlugin.java index 512b1a1..0a5f60a 100644 --- a/android/src/main/java/com/optimizely/optimizely_flutter_sdk/OptimizelyFlutterSdkPlugin.java +++ b/android/src/main/java/com/optimizely/optimizely_flutter_sdk/OptimizelyFlutterSdkPlugin.java @@ -19,6 +19,7 @@ import io.flutter.embedding.engine.plugins.FlutterPlugin; import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding; +import io.flutter.plugin.common.BinaryMessenger; import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.common.MethodChannel.MethodCallHandler; @@ -47,6 +48,7 @@ public class OptimizelyFlutterSdkPlugin extends OptimizelyFlutterClient implements FlutterPlugin, ActivityAware, MethodCallHandler { public static MethodChannel channel; + private static BinaryMessenger attachedMessenger; private Appender flutterLogbackAppender; /** @@ -215,7 +217,8 @@ public void onAttachedToEngine(@NonNull FlutterPluginBinding binding) { if (channel != null) { return; } - channel = new MethodChannel(binding.getBinaryMessenger(), "optimizely_flutter_sdk"); + attachedMessenger = binding.getBinaryMessenger(); + channel = new MethodChannel(attachedMessenger, "optimizely_flutter_sdk"); channel.setMethodCallHandler(this); context = binding.getApplicationContext(); @@ -234,8 +237,12 @@ public void onAttachedToEngine(@NonNull FlutterPluginBinding binding) { @Override public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) { + if (binding.getBinaryMessenger() != attachedMessenger) { + return; + } channel.setMethodCallHandler(null); channel = null; + attachedMessenger = null; // Stop and detach the appender if (flutterLogbackAppender != null) { Logger rootLogger = (Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME); diff --git a/ios/Classes/SwiftOptimizelyFlutterSdkPlugin.swift b/ios/Classes/SwiftOptimizelyFlutterSdkPlugin.swift index 8d17b66..725fd65 100644 --- a/ios/Classes/SwiftOptimizelyFlutterSdkPlugin.swift +++ b/ios/Classes/SwiftOptimizelyFlutterSdkPlugin.swift @@ -30,7 +30,8 @@ public class SwiftOptimizelyFlutterSdkPlugin: NSObject, FlutterPlugin { // to communicate with optimizely flutter sdk static var channel: FlutterMethodChannel! - + private static weak var attachedMessenger: FlutterBinaryMessenger? + // to track each unique userContext var uuid: String { return UUID().uuidString @@ -41,7 +42,9 @@ public class SwiftOptimizelyFlutterSdkPlugin: NSObject, FlutterPlugin { if channel != nil { return } - channel = FlutterMethodChannel(name: "optimizely_flutter_sdk", binaryMessenger: registrar.messenger()) + let messenger = registrar.messenger() + attachedMessenger = messenger + channel = FlutterMethodChannel(name: "optimizely_flutter_sdk", binaryMessenger: messenger) let instance = SwiftOptimizelyFlutterSdkPlugin() registrar.addMethodCallDelegate(instance, channel: channel) @@ -55,8 +58,12 @@ public class SwiftOptimizelyFlutterSdkPlugin: NSObject, FlutterPlugin { } public func detachFromEngine(for registrar: FlutterPluginRegistrar) { + guard registrar.messenger() === Self.attachedMessenger else { + return + } Self.channel?.setMethodCallHandler(nil) Self.channel = nil + Self.attachedMessenger = nil OptimizelyFlutterLogger.clearChannel() }