Skip to content

Conversation

@pazlavi
Copy link
Collaborator

@pazlavi pazlavi commented Feb 1, 2026

Fix: Plugin Instance Recreation on App Background/Foreground

Summary

This PR fixes an issue where a new AppsflyerSdkPlugin instance was created when the app went to background (via back button) and returned to foreground. This caused loss of plugin state, callbacks, and potential issues with deep linking and conversion data.

Problem

When the Android app goes to background using the back button and returns to foreground, Flutter's engine may be recreated, which causes Flutter to instantiate a new plugin instance. This resulted in:

  • Loss of registered callbacks (GCD, OAOA, UDL)
  • Potential missed deep link callbacks
  • Loss of cached conversion data
  • Multiple plugin instances existing simultaneously

Solution

Implemented a Delegate + Singleton pattern:

  1. AppsflyerSdkPluginDelegate (new) - A lightweight delegate class that Flutter instantiates. It forwards all calls to the singleton implementation.

  2. AppsflyerSdkPlugin (modified) - Now a singleton that holds all plugin state and logic. Ensures the same instance is reused across engine recreations.

  3. PluginLogger (new) - Utility class for controlled debug logging via system property or programmatically.

Changes

New Files

  • AppsflyerSdkPluginDelegate.java - Delegate entry point for Flutter plugin registration
  • PluginLogger.java - Debug logging utility with system property control

Modified Files

  • AppsflyerSdkPlugin.java - Converted to singleton pattern, added extensive debug logging
  • pubspec.yaml - Updated Android pluginClass to AppsflyerSdkPluginDelegate

Architecture

Flutter Engine
      │
      ▼ (creates new instance each time)
┌─────────────────────────────┐
│  AppsflyerSdkPluginDelegate │  ◄── Stateless, lightweight
└─────────────────────────────┘
      │
      ▼ (delegates to singleton)
┌─────────────────────────────┐
│    AppsflyerSdkPlugin       │  ◄── Singleton, holds all state
│    (singleton instance)     │
└─────────────────────────────┘

Debug Logging

Debug logging can be enabled in two ways:

1. Via ADB (requires app restart)

adb shell setprop debug.appsflyer.flutter true

2. Automatically with SDK debug mode

When isDebug: true is passed to initSdk(), plugin logging is automatically enabled.

3. Programmatically

PluginLogger.setDebugLoggingEnabled(true);

Log Output Examples

When enabled, logs show the singleton pattern working:

D/AppsFlyer_FlutterPlugin: Delegate #1 created (Flutter instantiated a new delegate)
D/AppsFlyer_FlutterPlugin: Singleton: Creating new AppsflyerSdkPlugin instance
D/AppsFlyer_FlutterPlugin: Delegate #1 onAttachedToEngine -> delegating to singleton
D/AppsFlyer_FlutterPlugin: Singleton: onAttachedToEngine - setting up channels
...
// App goes to background and returns
D/AppsFlyer_FlutterPlugin: Delegate #2 created (Flutter instantiated a new delegate)
D/AppsFlyer_FlutterPlugin: Singleton: Returning existing AppsflyerSdkPlugin instance
D/AppsFlyer_FlutterPlugin: Delegate #2 onAttachedToEngine -> delegating to singleton

Testing

  1. Initialize SDK with deep link listener
  2. Send app to background using back button
  3. Trigger a deep link
  4. Return to app
  5. Verify deep link callback is received correctly

Checklist

  • Singleton pattern ensures single plugin instance
  • Delegate pattern for clean Flutter integration
  • Callback caching preserved for background scenarios
  • Debug logging controllable via system property
  • Auto-enable logging when SDK debug mode is on
  • No breaking changes to public API

github-actions bot and others added 4 commits December 30, 2025 12:06
* SDK updates deprecate V1 purchase validation, improve iOS error handling (#429)

* SDK updates deprecate V1 purchase validation, improve iOS error handling

SDK Version Updates:
- Update Android SDK from 6.17.4 to 6.17.5
- Update iOS SDK from 6.17.7 to 6.17.8
- Update iOS Purchase Connector from 6.17.7 to 6.17.8
- Bump plugin version to 6.17.8 across all platforms

API Changes:
- Deprecate validateAndLogInAppAndroidPurchase (V1)
- Deprecate validateAndLogInAppIosPurchase (V1)
- Enhance iOS error handling for validateAndLogInAppPurchaseV2 with NSError parsing (code, domain, userInfo)

Documentation Updates:
- Remove "Beta" label from validateAndLogInAppPurchaseV2 API
- Mark V1 purchase validation APIs as Deprecated
- Add comprehensive PlatformException error handling examples
- Add iOS token format explanation for uninstall measurement
- Add cross-platform Firebase Messaging example for uninstall tokens

* lint

* CHANGELOG update

* fix implementation for validateAndLogInAppPurchaseV2

* fix: remove toJSON() causing extra quotes in PR creation

* fix: add .pubignore and handle RC dry-run warnings gracefully

* lint

* chore: prepare RC  (iOS 6.17.8, Android 6.17.5)
Version in pubspec.yaml was incorrectly merged with RC suffix.
This fixes the version to be production-ready.
@pazlavi pazlavi requested a review from Dani-Koza-AF February 1, 2026 14:17
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.

2 participants