Skip to content

Conversation

@saseungmin
Copy link
Contributor

@saseungmin saseungmin commented Jun 3, 2025

Add Swift AppDelegate Support for expo

🎯 Overview

This PR extends the plugin to support Swift AppDelegate files for AppsFlyer integration, addressing compatibility with Expo SDK 53+ which now defaults to generating Swift AppDelegate files instead of Objective-C.

📱 Background

✨ Changes

  • ✅ Swift AppDelegate Support: Automatic modification of AppDelegate.swift files
  • ✅ Bridging Header Management: Automatic #import <RNAppsFlyer.h> addition to bridging headers
  • ✅ Backward Compatibility: Existing Objective-C AppDelegate support unchanged

Swift AppDelegate Integration

// AppDelegate.swift
// Automatically adds to openURL method:
AppsFlyerAttribution.shared().handleOpen(url, options: options)

// Automatically adds to continueUserActivity method:
AppsFlyerAttribution.shared().continue(userActivity, restorationHandler: nil)
// {name}-Bridging-Header.h
#import <RNAppsFlyer.h>

Why restorationHandler: nil?

AppsFlyer doesn't actually use the restorationHandler internally. Evidence from AppsFlyer's own implementation:

// From AppsFlyerAttribution.m - receiveBridgeReadyNotification method
// https://github.com/AppsFlyerSDK/appsflyer-react-native-plugin/blob/bb5271cd5da6fa5c7e6d4bbfecfa77f531ea3372/ios/AppsFlyerAttribution.m#L77
- (void)receiveBridgeReadyNotification:(NSNotification *)notification {
    // ... other code ...
    if([self userActivity]) {
        [[AppsFlyerLib shared] continueUserActivity:[self userActivity] restorationHandler:nil];
        //                                                                              ^^^^ nil!
        [self setUserActivity:nil];
    }
}
  • AppsFlyer itself passes nil for delayed universal link processing
  • Actual UI restoration is handled by React Native's RCTLinkingManager, not AppsFlyer

🚨 Error Handling

  • Swift AppDelegate pattern mismatch:
image
  • Missing Bridging Header:
image

🧪 Test

- Add automatic Swift AppDelegate modification for AppsFlyer plugin
- Support Expo SDK 53+ default Swift AppDelegate template
- Add Bridging Header automatic import for Swift projects
- Maintain backward compatibility with Objective-C AppDelegate
@arekkubaczkowski
Copy link

arekkubaczkowski commented Jun 7, 2025

Really appreciate for this one. Just one comment, some time ago when I tried to do it manually in the expo app I was having issues with deeplinks at specific circumstances. Can you please make sure that all possible deeplink paths work properly yet?

AFAIR it was during the cold start where deeplinks weren't catched by SDK.

@saseungmin
Copy link
Contributor Author

saseungmin commented Jun 9, 2025

Really appreciate for this one. Just one comment, some time ago when I tried to do it manually in the expo app I was having issues with deeplinks at specific circumstances. Can you please make sure that all possible deeplink paths work properly yet?
AFAIR it was during the cold start where deeplinks weren't catched by SDK.

@arekkubaczkowski

Thanks for the comment
I tested the cold start scenario you mentioned and it worked fine without any issues. All the deeplinks I'm using are functioning properly as well.

Here are the test cases I covered:

  • IOS (physical device via TestFlight, simulator)
    Cold start (completely closed app): ✅
    Background state: ✅

  • Android (emulator)
    Cold start (completely closed app): ✅
    Background state: ✅

However, since I'm using the free version, I was only able to test with OneLink.

@saseungmin
Copy link
Contributor Author

If deep links are not working properly when the app is running in the background on Android, please add the following code to android/app/src/main/java/com/{appname}/app/MainActivity.kt:

import android.content.Intent

override fun onNewIntent(intent: Intent) {
  super.onNewIntent(intent)
  setIntent(intent)
}

Note: This code differs slightly from the original PR. The original used override fun onNewIntent(intent: Intent?) with a nullable Intent parameter, but this caused compilation errors, so I've updated it to use a non-null Intent parameter.

@arekkubaczkowski
Copy link

If deep links are not working properly when the app is running in the background on Android, please add the following code to android/app/src/main/java/com/{appname}/app/MainActivity.kt:

import android.content.Intent

override fun onNewIntent(intent: Intent) {
  super.onNewIntent(intent)
  setIntent(intent)
}

Note: This code differs slightly from the original PR. The original used override fun onNewIntent(intent: Intent?) with a nullable Intent parameter, but this caused compilation errors, so I've updated it to use a non-null Intent parameter.

I believe it's necessary to add the compatibility for Expo as well. The plugin shouldn't be complex tho

@arekkubaczkowski
Copy link

@saseungmin

#372 (comment)

@jensellfors
Copy link

What's the progress on this, need this to upgrade our app... Not sure if any engineers from AppsFlyer are here?

@arekkubaczkowski
Copy link

What's the progress on this, need this to upgrade our app... Not sure if any engineers from AppsFlyer are here?

I guess not, you can create a local patch using patch-package for now

@huylocit14054
Copy link

This is blocking our app from upgrading to Expo 53. Hope that this issue gets resolved soon.

continue userActivity: NSUserActivity,
restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void
) -> Bool {`;
const RNAPPSFLYER_SWIFT_CONTINUE_USER_ACTIVITY_CODE = 'AppsFlyerAttribution.shared().continue(userActivity, restorationHandler: nil)';

Choose a reason for hiding this comment

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

I saw your comment that restorationHandler is not being used internally. I do think it is better to work with the external Api in case the internal one ever starts using it. You could work around the error you were getting with:

      AppsFlyerAttribution.shared().continue(userActivity) { array in
        restorationHandler(array as? [UIUserActivityRestoring])
      }

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@itsramiel

Thanks for the suggestion! I think keeping restorationHandler: nil is cleaner for now.

  1. Current state: Since AppsFlyer doesn't use restorationHandler internally, we'd be passing unused data through an unnecessary closure.

  2. Type safety concerns: The suggested array as? [UIUserActivityRestoring] casting assumes AppsFlyer will always provide the correct type, but we don't have guarantees about their internal implementation.

  3. Future updates: If AppsFlyer adds functionality that uses restorationHandler, we'll need to update the library anyway, so we can implement it properly at that point.

I think it's better to keep the code simple and explicit rather than adding complexity for future scenarios. When the feature is actually added, we can implement it then.

I'll follow the AppsFlyer maintainer's opinion on this matter for future implementation.
Thanks!

@mapledan
Copy link

mapledan commented Jul 7, 2025

This is blocking our app from upgrading to Expo 53. Hope that this issue gets resolved soon.

We’re encountering the same issue as well. Hopefully, it can be resolved soon.

@arapocket
Copy link

Any news on this?

@arapocket
Copy link

I've reached out to AppsFlyer support and didn't get any definitive update, just that their product team would look into it.

@takuro-kira
Copy link

same, at react native without framework. react-native v0.80.1
hope update document from 2years ago.
https://github.com/AppsFlyerSDK/appsflyer-react-native-plugin/blob/master/Docs/RN_DeepLinkIntegrate.md

@arapocket
Copy link

AppsFlyer got back to me and said that the fix will be prioritized for early August.

@al-af al-af changed the base branch from master to development July 22, 2025 06:30
@al-af al-af merged commit 011ef3a into AppsFlyerSDK:development Jul 22, 2025
al-af added a commit that referenced this pull request Jul 22, 2025
- Add shouldUsePurchaseConnector flag support
- Add automatic Podfile flag injection with conflict detection
- Maintain backward compatibility with manual configurations
- Support both shouldUseStrictMode and shouldUsePurchaseConnector flags

Builds upon Swift AppDelegate support from PR #624
al-af added a commit that referenced this pull request Jul 22, 2025
…lugin

- Add shouldUsePurchaseConnector flag support
- Add automatic Podfile flag injection with conflict detection
- Maintain backward compatibility with manual configurations
- Support both shouldUseStrictMode and shouldUsePurchaseConnector flags

Builds upon Swift AppDelegate support from PR #624
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.

9 participants