diff --git a/packages/dynamic-links/android/src/main/java/io/invertase/firebase/dynamiclinks/ReactNativeFirebaseDynamicLinksModule.java b/packages/dynamic-links/android/src/main/java/io/invertase/firebase/dynamiclinks/ReactNativeFirebaseDynamicLinksModule.java index 7ea87e69169..c08c3cbdf59 100644 --- a/packages/dynamic-links/android/src/main/java/io/invertase/firebase/dynamiclinks/ReactNativeFirebaseDynamicLinksModule.java +++ b/packages/dynamic-links/android/src/main/java/io/invertase/firebase/dynamiclinks/ReactNativeFirebaseDynamicLinksModule.java @@ -20,6 +20,7 @@ import android.app.Activity; import android.content.Intent; import android.net.Uri; +import android.os.Bundle; import android.util.Log; import com.facebook.react.bridge.*; import com.google.android.gms.tasks.Tasks; @@ -41,6 +42,7 @@ public class ReactNativeFirebaseDynamicLinksModule extends ReactNativeFirebaseMo private String initialLinkUrl = null; private int initialLinkMinimumVersion = 0; + private WritableMap initialLinkUtmParameters = new WritableNativeMap(); /** * Ensures calls to getInitialLink only tries to retrieve the link from getDynamicLink once. @@ -164,12 +166,13 @@ public void getInitialLink(Promise promise) { if (pendingDynamicLinkData != null) { initialLinkUrl = pendingDynamicLinkData.getLink().toString(); initialLinkMinimumVersion = pendingDynamicLinkData.getMinimumAppVersion(); + initialLinkUtmParameters = Arguments.makeNativeMap(pendingDynamicLinkData.getUtmParameters()); } // Guard against the scenario where the app was launched using a dynamic link, // then, the app was backgrounded using the Back button, and resumed from the Overview (screen). if (initialLinkUrl != null && !launchedFromHistory) { - promise.resolve(dynamicLinkToWritableMap(initialLinkUrl, initialLinkMinimumVersion)); + promise.resolve(dynamicLinkToWritableMap(initialLinkUrl, initialLinkMinimumVersion, initialLinkUtmParameters)); } else { promise.resolve(null); } @@ -191,7 +194,8 @@ public void resolveLink(String link, Promise promise) { if (linkData != null && linkData.getLink() != null && linkData.getLink().toString() != null) { String linkUrl = linkData.getLink().toString(); int linkMinimumVersion = linkData.getMinimumAppVersion(); - promise.resolve(dynamicLinkToWritableMap(linkUrl, linkMinimumVersion)); + Bundle linkUtmParameters = linkData.getUtmParameters(); + promise.resolve(dynamicLinkToWritableMap(linkUrl, linkMinimumVersion, Arguments.makeNativeMap(linkUtmParameters))); } else { rejectPromiseWithCodeAndMessage(promise, "not-found", "Dynamic link not found"); } @@ -206,7 +210,7 @@ public void resolveLink(String link, Promise promise) { } } - private WritableMap dynamicLinkToWritableMap(String url, int minVersion) { + private WritableMap dynamicLinkToWritableMap(String url, int minVersion, WritableMap utmParameters) { WritableMap writableMap = Arguments.createMap(); writableMap.putString("url", url); @@ -217,6 +221,8 @@ private WritableMap dynamicLinkToWritableMap(String url, int minVersion) { writableMap.putInt("minimumAppVersion", minVersion); } + writableMap.putMap("utmParameters", utmParameters); + return writableMap; } @@ -420,7 +426,7 @@ public void onNewIntent(Intent intent) { if (pendingDynamicLinkData != null) { ReactNativeFirebaseEventEmitter.getSharedInstance().sendEvent(new ReactNativeFirebaseEvent( "dynamic_links_link_received", - dynamicLinkToWritableMap(pendingDynamicLinkData.getLink().toString(), pendingDynamicLinkData.getMinimumAppVersion()) + dynamicLinkToWritableMap(pendingDynamicLinkData.getLink().toString(), pendingDynamicLinkData.getMinimumAppVersion(), Arguments.makeNativeMap(pendingDynamicLinkData.getUtmParameters())) )); } } else { diff --git a/packages/dynamic-links/e2e/dynamicLinks.e2e.js b/packages/dynamic-links/e2e/dynamicLinks.e2e.js index d7dda7cadf8..f1e8c4170ce 100644 --- a/packages/dynamic-links/e2e/dynamicLinks.e2e.js +++ b/packages/dynamic-links/e2e/dynamicLinks.e2e.js @@ -155,6 +155,7 @@ describe('dynamicLinks()', function () { dynamicLink.should.be.an.Object(); dynamicLink.url.should.equal('https://rnfirebase.io'); + dynamicLink.utmParameters.should.eql({}); }); }); @@ -172,6 +173,7 @@ describe('dynamicLinks()', function () { spy.getCall(0).args[0].should.be.an.Object(); spy.getCall(0).args[0].url.should.equal('https://invertase.io/hire-us'); + spy.getCall(0).args[0].utmParameters.should.eql({}); }); }); }); diff --git a/packages/dynamic-links/ios/RNFBDynamicLinks/RNFBDynamicLinksAppDelegateInterceptor.h b/packages/dynamic-links/ios/RNFBDynamicLinks/RNFBDynamicLinksAppDelegateInterceptor.h index df283592367..5eee2980b0a 100644 --- a/packages/dynamic-links/ios/RNFBDynamicLinks/RNFBDynamicLinksAppDelegateInterceptor.h +++ b/packages/dynamic-links/ios/RNFBDynamicLinks/RNFBDynamicLinksAppDelegateInterceptor.h @@ -27,6 +27,7 @@ static NSString *const LINK_RECEIVED_EVENT = @"dynamic_links_link_received"; @interface RNFBDynamicLinksAppDelegateInterceptor : NSObject @property (strong, readwrite) NSString *_Nullable initialLinkUrl; @property (strong, readwrite) NSString *_Nullable initialLinkMinimumAppVersion; +@property (strong, readwrite) NSDictionary *_Nonnull initialLinkUtmParametersDictionary; + (instancetype)sharedInstance; diff --git a/packages/dynamic-links/ios/RNFBDynamicLinks/RNFBDynamicLinksAppDelegateInterceptor.m b/packages/dynamic-links/ios/RNFBDynamicLinks/RNFBDynamicLinksAppDelegateInterceptor.m index e79fde1cdb8..b71bb6899c5 100644 --- a/packages/dynamic-links/ios/RNFBDynamicLinks/RNFBDynamicLinksAppDelegateInterceptor.m +++ b/packages/dynamic-links/ios/RNFBDynamicLinks/RNFBDynamicLinksAppDelegateInterceptor.m @@ -28,6 +28,7 @@ + (instancetype)sharedInstance { sharedInstance = [[RNFBDynamicLinksAppDelegateInterceptor alloc] init]; sharedInstance.initialLinkUrl = nil; sharedInstance.initialLinkMinimumAppVersion = nil; + sharedInstance.initialLinkUtmParametersDictionary = @{}; [GULAppDelegateSwizzler proxyOriginalDelegate]; [GULAppDelegateSwizzler registerAppDelegateInterceptor:sharedInstance]; }); @@ -64,10 +65,12 @@ - (BOOL)application:(UIApplication *)application if (_initialLinkUrl == nil) { _initialLinkUrl = dynamicLink.url.absoluteString; _initialLinkMinimumAppVersion = dynamicLink.minimumAppVersion; + _initialLinkUtmParametersDictionary = dynamicLink.utmParametersDictionary; } [[RNFBRCTEventEmitter shared] sendEventWithName:LINK_RECEIVED_EVENT body:@{ @"url": dynamicLink.url.absoluteString, @"minimumAppVersion": dynamicLink.minimumAppVersion == nil ? [NSNull null] : dynamicLink.minimumAppVersion, + @"utmParameters": dynamicLink.utmParametersDictionary == nil ? @{} : dynamicLink.utmParametersDictionary, }]; } @@ -85,10 +88,12 @@ - (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserAct if (_initialLinkUrl == nil) { _initialLinkUrl = dynamicLink.url.absoluteString; _initialLinkMinimumAppVersion = dynamicLink.minimumAppVersion; + _initialLinkUtmParametersDictionary = dynamicLink.utmParametersDictionary; } [[RNFBRCTEventEmitter shared] sendEventWithName:LINK_RECEIVED_EVENT body:@{ @"url": dynamicLink.url.absoluteString, @"minimumAppVersion": dynamicLink.minimumAppVersion == nil ? [NSNull null] : dynamicLink.minimumAppVersion, + @"utmParameters": dynamicLink.utmParametersDictionary == nil ? @{} : dynamicLink.utmParametersDictionary, }]; } diff --git a/packages/dynamic-links/ios/RNFBDynamicLinks/RNFBDynamicLinksModule.m b/packages/dynamic-links/ios/RNFBDynamicLinks/RNFBDynamicLinksModule.m index 8c5fcc63a53..a979714d735 100644 --- a/packages/dynamic-links/ios/RNFBDynamicLinks/RNFBDynamicLinksModule.m +++ b/packages/dynamic-links/ios/RNFBDynamicLinks/RNFBDynamicLinksModule.m @@ -129,11 +129,13 @@ - (id)init { resolve(@{ @"url": dynamicLink.url.absoluteString, @"minimumAppVersion": dynamicLink.minimumAppVersion == nil ? [NSNull null] : dynamicLink.minimumAppVersion, + @"utmParameters": dynamicLink.utmParametersDictionary == nil ? @{} : dynamicLink.utmParametersDictionary, }); } else if ([RNFBDynamicLinksAppDelegateInterceptor sharedInstance].initialLinkUrl != nil) { resolve(@{ @"url": [RNFBDynamicLinksAppDelegateInterceptor sharedInstance].initialLinkUrl, @"minimumAppVersion": [RNFBDynamicLinksAppDelegateInterceptor sharedInstance].initialLinkMinimumAppVersion == nil ? [NSNull null] : [RNFBDynamicLinksAppDelegateInterceptor sharedInstance].initialLinkMinimumAppVersion, + @"utmParameters": [RNFBDynamicLinksAppDelegateInterceptor sharedInstance].initialLinkUtmParametersDictionary == nil ? @{} : [RNFBDynamicLinksAppDelegateInterceptor sharedInstance].initialLinkUtmParametersDictionary, }); } else { resolve([NSNull null]); @@ -151,11 +153,13 @@ - (id)init { resolve(@{ @"url": dynamicLink.url.absoluteString, @"minimumAppVersion": dynamicLink.minimumAppVersion == nil ? [NSNull null] : dynamicLink.minimumAppVersion, + @"utmParameters": dynamicLink.utmParametersDictionary == nil ? @{} : dynamicLink.utmParametersDictionary, }); } else if (!error && [RNFBDynamicLinksAppDelegateInterceptor sharedInstance].initialLinkUrl != nil) { resolve(@{ @"url": [RNFBDynamicLinksAppDelegateInterceptor sharedInstance].initialLinkUrl, @"minimumAppVersion": [RNFBDynamicLinksAppDelegateInterceptor sharedInstance].initialLinkMinimumAppVersion == nil ? [NSNull null] : [RNFBDynamicLinksAppDelegateInterceptor sharedInstance].initialLinkMinimumAppVersion, + @"utmParameters": [RNFBDynamicLinksAppDelegateInterceptor sharedInstance].initialLinkUtmParametersDictionary == nil ? @{} : [RNFBDynamicLinksAppDelegateInterceptor sharedInstance].initialLinkUtmParametersDictionary, }); } else if (error) { [RNFBSharedUtils rejectPromiseWithUserInfo:reject userInfo:(NSMutableDictionary *) @{ @@ -176,6 +180,7 @@ - (id)init { resolve(@{ @"url": [RNFBDynamicLinksAppDelegateInterceptor sharedInstance].initialLinkUrl, @"minimumAppVersion": [RNFBDynamicLinksAppDelegateInterceptor sharedInstance].initialLinkMinimumAppVersion == nil ? [NSNull null] : [RNFBDynamicLinksAppDelegateInterceptor sharedInstance].initialLinkMinimumAppVersion, + @"utmParameters": [RNFBDynamicLinksAppDelegateInterceptor sharedInstance].initialLinkUtmParametersDictionary == nil ? @{} : [RNFBDynamicLinksAppDelegateInterceptor sharedInstance].initialLinkUtmParametersDictionary, }); } else { resolve([NSNull null]); @@ -192,6 +197,7 @@ - (id)init { resolve(@{ @"url": dynamicLink.url.absoluteString, @"minimumAppVersion": dynamicLink.minimumAppVersion == nil ? [NSNull null] : dynamicLink.minimumAppVersion, + @"utmParameters": dynamicLink.utmParametersDictionary == nil ? @{} : dynamicLink.utmParametersDictionary, }); } else if (!error || (error && [error.localizedDescription containsString:@"dynamicLinks error 404"])) { [RNFBSharedUtils rejectPromiseWithUserInfo:reject userInfo:(NSMutableDictionary *) @{ diff --git a/packages/dynamic-links/lib/index.d.ts b/packages/dynamic-links/lib/index.d.ts index f1c7c8140db..bc80274c8e2 100644 --- a/packages/dynamic-links/lib/index.d.ts +++ b/packages/dynamic-links/lib/index.d.ts @@ -421,6 +421,13 @@ export namespace FirebaseDynamicLinksTypes { * On iOS this returns a string value representing the minimum app version (not the iOS system version). */ minimumAppVersion: number | string | null; + + /** + * The potential UTM parameters linked to this dynamic link + * + * It will only work for short links, not long links + */ + utmParameters: Record; } /**