From 8bfb4fd571500b5b6342f809da4239d8ef5b3ac5 Mon Sep 17 00:00:00 2001 From: "gwanghee.lee" Date: Thu, 30 Oct 2025 13:34:36 +0900 Subject: [PATCH 1/3] fix: Fix race condition in startSDKwithHandler: capture MethodChannel snapshot to prevent null callback --- .../appsflyersdk/AppsflyerSdkPlugin.java | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/android/src/main/java/com/appsflyer/appsflyersdk/AppsflyerSdkPlugin.java b/android/src/main/java/com/appsflyer/appsflyersdk/AppsflyerSdkPlugin.java index 27c1967..8c8d278 100644 --- a/android/src/main/java/com/appsflyer/appsflyersdk/AppsflyerSdkPlugin.java +++ b/android/src/main/java/com/appsflyer/appsflyersdk/AppsflyerSdkPlugin.java @@ -392,7 +392,8 @@ private void anonymizeUser(MethodCall call, Result result) { result.success(null); // indicate that the method invocation is complete } - private void startSDKwithHandler(MethodCall call, final Result result) { + private void startSDKwithHandler(MethodCall call, final Result result) { + final MethodChannel _channel = mMethodChannel; try { final AppsFlyerLib appsFlyerLib = AppsFlyerLib.getInstance(); @@ -400,8 +401,8 @@ private void startSDKwithHandler(MethodCall call, final Result result) { @Override public void onSuccess() { uiThreadHandler.post(() -> { - if (mMethodChannel != null) { - mMethodChannel.invokeMethod("onSuccess", null); + if (_channel != null) { + _channel.invokeMethod("onSuccess", null); } else { Log.e(AF_PLUGIN_TAG, LogMessages.METHOD_CHANNEL_IS_NULL + " - SDK started successfully but callback `onSuccess` failed"); } @@ -411,11 +412,11 @@ public void onSuccess() { @Override public void onError(final int errorCode, final String errorMessage) { uiThreadHandler.post(() -> { - if (mMethodChannel != null) { + if (_channel != null) { HashMap errorDetails = new HashMap<>(); errorDetails.put("errorCode", errorCode); errorDetails.put("errorMessage", errorMessage); - mMethodChannel.invokeMethod("onError", errorDetails); + _channel.invokeMethod("onError", errorDetails); } else { Log.e(AF_PLUGIN_TAG, LogMessages.METHOD_CHANNEL_IS_NULL + " - SDK failed to start: " + errorMessage); } @@ -738,12 +739,13 @@ public void onResponseError(final String error) { rawResult.success(null); } - private void runOnUIThread(final Object data, final String callbackName, final String status) { + private void runOnUIThread(final Object data, final String callbackName, final String status) { + final MethodChannel _channel = mCallbackChannel; uiThreadHandler.post( new Runnable() { @Override public void run() { - if (mCallbackChannel != null) { + if (_channel != null) { Log.d(AF_PLUGIN_TAG, "Calling invokeMethod with: " + data); JSONObject args = new JSONObject(); try { @@ -766,7 +768,7 @@ public void run() { } catch (JSONException e) { e.printStackTrace(); } - mCallbackChannel.invokeMethod("callListener", args.toString()); + _channel.invokeMethod("callListener", args.toString()); } else { Log.e(AF_PLUGIN_TAG, "CallbackChannel is null, cannot invoke method: " + callbackName); } From e00d346c6a029c786f453adadc9577312e20b936 Mon Sep 17 00:00:00 2001 From: ilous12 Date: Thu, 30 Oct 2025 14:40:36 +0900 Subject: [PATCH 2/3] Update AppsflyerSdkPlugin.java --- .../appsflyersdk/AppsflyerSdkPlugin.java | 92 +++++++++++-------- 1 file changed, 53 insertions(+), 39 deletions(-) diff --git a/android/src/main/java/com/appsflyer/appsflyersdk/AppsflyerSdkPlugin.java b/android/src/main/java/com/appsflyer/appsflyersdk/AppsflyerSdkPlugin.java index 8c8d278..dfc24d8 100644 --- a/android/src/main/java/com/appsflyer/appsflyersdk/AppsflyerSdkPlugin.java +++ b/android/src/main/java/com/appsflyer/appsflyersdk/AppsflyerSdkPlugin.java @@ -173,16 +173,6 @@ public void onMethodCall(MethodCall call, Result result) { } }; - private void onAttachedToEngine(Context applicationContext, BinaryMessenger messenger) { - this.mContext = applicationContext; - this.mEventChannel = new EventChannel(messenger, AF_EVENTS_CHANNEL); - mMethodChannel = new MethodChannel(messenger, AppsFlyerConstants.AF_METHOD_CHANNEL); - mMethodChannel.setMethodCallHandler(this); - mCallbackChannel = new MethodChannel(messenger, AppsFlyerConstants.AF_CALLBACK_CHANNEL); - mCallbackChannel.setMethodCallHandler(callbacksHandler); - } - - private void startListening(Object arguments, Result rawResult) { // Get callback id String callbackName = (String) arguments; @@ -392,37 +382,47 @@ private void anonymizeUser(MethodCall call, Result result) { result.success(null); // indicate that the method invocation is complete } - private void startSDKwithHandler(MethodCall call, final Result result) { + private void startSDKwithHandler(MethodCall call, final Result result) { + Log.d(AF_PLUGIN_TAG, "startSDKwithHandler - " + this + " MethodChannel - " + mMethodChannel); final MethodChannel _channel = mMethodChannel; try { final AppsFlyerLib appsFlyerLib = AppsFlyerLib.getInstance(); + if (appsFlyerLib.isStopped()) { + appsFlyerLib.start(activity, null, new AppsFlyerRequestListener() { + @Override + public void onSuccess() { + uiThreadHandler.post(() -> { + if (_channel != null) { + _channel.invokeMethod("onSuccess", null); + } else { + Log.e(AF_PLUGIN_TAG, LogMessages.METHOD_CHANNEL_IS_NULL + " - SDK started successfully but callback `onSuccess` failed"); + } + }); + } - appsFlyerLib.start(activity, null, new AppsFlyerRequestListener() { - @Override - public void onSuccess() { - uiThreadHandler.post(() -> { - if (_channel != null) { - _channel.invokeMethod("onSuccess", null); - } else { - Log.e(AF_PLUGIN_TAG, LogMessages.METHOD_CHANNEL_IS_NULL + " - SDK started successfully but callback `onSuccess` failed"); - } - }); - } - - @Override - public void onError(final int errorCode, final String errorMessage) { - uiThreadHandler.post(() -> { - if (_channel != null) { - HashMap errorDetails = new HashMap<>(); - errorDetails.put("errorCode", errorCode); - errorDetails.put("errorMessage", errorMessage); - _channel.invokeMethod("onError", errorDetails); - } else { - Log.e(AF_PLUGIN_TAG, LogMessages.METHOD_CHANNEL_IS_NULL + " - SDK failed to start: " + errorMessage); - } - }); - } - }); + @Override + public void onError(final int errorCode, final String errorMessage) { + uiThreadHandler.post(() -> { + if (_channel != null) { + HashMap errorDetails = new HashMap<>(); + errorDetails.put("errorCode", errorCode); + errorDetails.put("errorMessage", errorMessage); + _channel.invokeMethod("onError", errorDetails); + } else { + Log.e(AF_PLUGIN_TAG, LogMessages.METHOD_CHANNEL_IS_NULL + " - SDK failed to start: " + errorMessage); + } + }); + } + }); + } else { + uiThreadHandler.post(() -> { + if (_channel != null) { + _channel.invokeMethod("onSuccess", null); + } else { + Log.e(AF_PLUGIN_TAG, LogMessages.METHOD_CHANNEL_IS_NULL + " - SDK started successfully but callback `onSuccess` failed"); + } + }); + } result.success(null); } catch (Throwable t) { result.error("UNEXPECTED_ERROR", t.getMessage(), null); @@ -739,7 +739,7 @@ public void onResponseError(final String error) { rawResult.success(null); } - private void runOnUIThread(final Object data, final String callbackName, final String status) { + private void runOnUIThread(final Object data, final String callbackName, final String status) { final MethodChannel _channel = mCallbackChannel; uiThreadHandler.post( new Runnable() { @@ -1227,12 +1227,22 @@ private void disableAppSetId(MethodCall call, Result result) { @Override public void onAttachedToEngine(FlutterPluginBinding binding) { - onAttachedToEngine(binding.getApplicationContext(), binding.getBinaryMessenger()); + Log.d(AF_PLUGIN_TAG, "onAttachedToEngine - " + this); + this.mContext = binding.getApplicationContext(); + BinaryMessenger messenger = binding.getBinaryMessenger(); + this.mEventChannel = new EventChannel(messenger, AF_EVENTS_CHANNEL); + mMethodChannel = new MethodChannel(messenger, AppsFlyerConstants.AF_METHOD_CHANNEL); + mMethodChannel.setMethodCallHandler(this); + Log.d(AF_PLUGIN_TAG, "onAttachedToEngine - " + this + " MethodChannel - " + mMethodChannel); + mCallbackChannel = new MethodChannel(messenger, AppsFlyerConstants.AF_CALLBACK_CHANNEL); + mCallbackChannel.setMethodCallHandler(callbacksHandler); + Log.d(AF_PLUGIN_TAG, "onAttachedToEngine - " + this + " mCallbackChannel - " + mCallbackChannel); AppsFlyerPurchaseConnector.INSTANCE.onAttachedToEngine(binding); } @Override public void onDetachedFromEngine(FlutterPluginBinding binding) { + Log.d(AF_PLUGIN_TAG, "onDetachedFromEngine - " + this); mMethodChannel.setMethodCallHandler(null); mMethodChannel = null; mEventChannel.setStreamHandler(null); @@ -1244,6 +1254,7 @@ public void onDetachedFromEngine(FlutterPluginBinding binding) { @Override public void onAttachedToActivity(ActivityPluginBinding binding) { + Log.d(AF_PLUGIN_TAG, "onAttachedToActivity - " + this); activity = binding.getActivity(); mApplication = binding.getActivity().getApplication(); binding.addOnNewIntentListener(onNewIntentListener); @@ -1251,11 +1262,13 @@ public void onAttachedToActivity(ActivityPluginBinding binding) { @Override public void onDetachedFromActivityForConfigChanges() { + Log.d(AF_PLUGIN_TAG, "onDetachedFromActivityForConfigChanges - " + this); this.activity = null; } @Override public void onReattachedToActivityForConfigChanges(ActivityPluginBinding binding) { + Log.d(AF_PLUGIN_TAG, "onReattachedToActivityForConfigChanges - " + this); sendCachedCallbacksToDart(); binding.addOnNewIntentListener(onNewIntentListener); activity = binding.getActivity(); @@ -1263,6 +1276,7 @@ public void onReattachedToActivityForConfigChanges(ActivityPluginBinding binding @Override public void onDetachedFromActivity() { + Log.d(AF_PLUGIN_TAG, "onDetachedFromActivity - " + this); activity = null; saveCallbacks = true; AppsFlyerLib.getInstance().unregisterConversionListener(); From 071541d24ff7913abec4d8b9add1a7d3ad8048de Mon Sep 17 00:00:00 2001 From: ilous12 Date: Thu, 6 Nov 2025 16:16:26 +0900 Subject: [PATCH 3/3] Update AppsflyerSdkPlugin.java --- .../appsflyersdk/AppsflyerSdkPlugin.java | 61 ++++++++----------- 1 file changed, 26 insertions(+), 35 deletions(-) diff --git a/android/src/main/java/com/appsflyer/appsflyersdk/AppsflyerSdkPlugin.java b/android/src/main/java/com/appsflyer/appsflyersdk/AppsflyerSdkPlugin.java index dfc24d8..0861db4 100644 --- a/android/src/main/java/com/appsflyer/appsflyersdk/AppsflyerSdkPlugin.java +++ b/android/src/main/java/com/appsflyer/appsflyersdk/AppsflyerSdkPlugin.java @@ -387,42 +387,33 @@ private void startSDKwithHandler(MethodCall call, final Result result) { final MethodChannel _channel = mMethodChannel; try { final AppsFlyerLib appsFlyerLib = AppsFlyerLib.getInstance(); - if (appsFlyerLib.isStopped()) { - appsFlyerLib.start(activity, null, new AppsFlyerRequestListener() { - @Override - public void onSuccess() { - uiThreadHandler.post(() -> { - if (_channel != null) { - _channel.invokeMethod("onSuccess", null); - } else { - Log.e(AF_PLUGIN_TAG, LogMessages.METHOD_CHANNEL_IS_NULL + " - SDK started successfully but callback `onSuccess` failed"); - } - }); - } + AppsFlyerLib.getInstance().stop(false, mContext); + appsFlyerLib.start(activity, null, new AppsFlyerRequestListener() { + @Override + public void onSuccess() { + uiThreadHandler.post(() -> { + if (_channel != null) { + _channel.invokeMethod("onSuccess", null); + } else { + Log.e(AF_PLUGIN_TAG, LogMessages.METHOD_CHANNEL_IS_NULL + " - SDK started successfully but callback `onSuccess` failed"); + } + }); + } - @Override - public void onError(final int errorCode, final String errorMessage) { - uiThreadHandler.post(() -> { - if (_channel != null) { - HashMap errorDetails = new HashMap<>(); - errorDetails.put("errorCode", errorCode); - errorDetails.put("errorMessage", errorMessage); - _channel.invokeMethod("onError", errorDetails); - } else { - Log.e(AF_PLUGIN_TAG, LogMessages.METHOD_CHANNEL_IS_NULL + " - SDK failed to start: " + errorMessage); - } - }); - } - }); - } else { - uiThreadHandler.post(() -> { - if (_channel != null) { - _channel.invokeMethod("onSuccess", null); - } else { - Log.e(AF_PLUGIN_TAG, LogMessages.METHOD_CHANNEL_IS_NULL + " - SDK started successfully but callback `onSuccess` failed"); - } - }); - } + @Override + public void onError(final int errorCode, final String errorMessage) { + uiThreadHandler.post(() -> { + if (_channel != null) { + HashMap errorDetails = new HashMap<>(); + errorDetails.put("errorCode", errorCode); + errorDetails.put("errorMessage", errorMessage); + _channel.invokeMethod("onError", errorDetails); + } else { + Log.e(AF_PLUGIN_TAG, LogMessages.METHOD_CHANNEL_IS_NULL + " - SDK failed to start: " + errorMessage); + } + }); + } + }); result.success(null); } catch (Throwable t) { result.error("UNEXPECTED_ERROR", t.getMessage(), null);