Bug Description
AppsflyerSdkPlugin.onMethodCall() has a blanket activity == null check at the top (line 210) that rejects all method calls when no Activity is attached:
@Override
public void onMethodCall(MethodCall call, Result result) {
if (activity == null) {
result.error("NO_ACTIVITY", "The current activity is null", null);
return;
}
// ... all methods blocked
}
However, many methods — including initSdk — only need mContext (application context), not activity. For example, initSdk() calls:
instance.init(afDevKey, gcdListener, mContext); // uses mContext, not activity
The only call that actually needs Activity inside initSdk is instance.start(activity), and only when isManualStartMode is false.
Impact
This causes PlatformException(NO_ACTIVITY, The current activity is null, null, null) crashes on Android when:
- App startup before
runApp() — Flutter plugins are initialized during DI setup before the Activity is created. AppsFlyer initSdk is called during this window.
- Background execution — When the app process is started by a Service (e.g., FCM background message handling), there is no Activity at all.
In our production app (Android, Flutter), this is the #1 crash with 26k+ events affecting 13.5k+ users, with 93% occurring during early startup (EARLY signal in Crashlytics).
Expected Behavior
Methods that only require Context should work without an Activity. The activity == null guard should be moved to only the methods that actually need it:
start() / startSDK() / startSDKwithHandler()
performOnDeepLinking() (needs activity.getIntent())
sendPushNotificationData() (needs activity.getIntent())
setPushNotification() (passes activity to SDK)
All other methods (including initSdk with isManualStartMode: true, logEvent, getAppsFlyerUID, setCustomerUserId, etc.) use mContext and should not be blocked.
Suggested Fix
Move the Activity null check from onMethodCall() into only the methods that require it:
@Override
public void onMethodCall(MethodCall call, Result result) {
final String method = call.method;
switch (method) {
case "initSdk":
initSdk(call, result); // uses mContext for init, activity only for start()
break;
case "startSDK":
if (activity == null) {
result.error("NO_ACTIVITY", "The current activity is null", null);
return;
}
startSDK(call, result);
break;
// ... etc
}
}
And inside initSdk, guard only the start() call:
if (!isManualStartMode) {
if (activity != null) {
instance.start(activity);
} else {
Log.w(AF_PLUGIN_TAG, "Activity not available, skipping auto-start. Call startSDK() after Activity is ready.");
}
}
Environment
appsflyer_sdk: 6.17.8
- Flutter: 3.x (stable)
- Android: Reproducible on all versions, especially Android 16
- Crash location:
StandardMethodCodec.decodeEnvelope → PlatformException(NO_ACTIVITY)
Related
The same blanket guard pattern exists in performOnDeepLinking() (line 383-385) but that one legitimately needs Activity. The issue is specifically with the top-level guard blocking methods that don't need it.
Bug Description
AppsflyerSdkPlugin.onMethodCall()has a blanketactivity == nullcheck at the top (line 210) that rejects all method calls when no Activity is attached:However, many methods — including
initSdk— only needmContext(application context), notactivity. For example,initSdk()calls:The only call that actually needs Activity inside
initSdkisinstance.start(activity), and only whenisManualStartModeis false.Impact
This causes
PlatformException(NO_ACTIVITY, The current activity is null, null, null)crashes on Android when:runApp()— Flutter plugins are initialized during DI setup before the Activity is created. AppsFlyerinitSdkis called during this window.In our production app (Android, Flutter), this is the #1 crash with 26k+ events affecting 13.5k+ users, with 93% occurring during early startup (EARLY signal in Crashlytics).
Expected Behavior
Methods that only require
Contextshould work without an Activity. Theactivity == nullguard should be moved to only the methods that actually need it:start()/startSDK()/startSDKwithHandler()performOnDeepLinking()(needsactivity.getIntent())sendPushNotificationData()(needsactivity.getIntent())setPushNotification()(passesactivityto SDK)All other methods (including
initSdkwithisManualStartMode: true,logEvent,getAppsFlyerUID,setCustomerUserId, etc.) usemContextand should not be blocked.Suggested Fix
Move the Activity null check from
onMethodCall()into only the methods that require it:And inside
initSdk, guard only thestart()call:Environment
appsflyer_sdk: 6.17.8StandardMethodCodec.decodeEnvelope→PlatformException(NO_ACTIVITY)Related
The same blanket guard pattern exists in
performOnDeepLinking()(line 383-385) but that one legitimately needs Activity. The issue is specifically with the top-level guard blocking methods that don't need it.