diff --git a/android/src/main/java/io/invertase/firebase/links/RNFirebaseLinks.java b/android/src/main/java/io/invertase/firebase/links/RNFirebaseLinks.java index 746dcf9b..9c308168 100644 --- a/android/src/main/java/io/invertase/firebase/links/RNFirebaseLinks.java +++ b/android/src/main/java/io/invertase/firebase/links/RNFirebaseLinks.java @@ -6,8 +6,6 @@ import android.net.Uri; import android.support.annotation.NonNull; import android.util.Log; -import java.util.Map; - import com.facebook.react.bridge.ActivityEventListener; import com.facebook.react.bridge.LifecycleEventListener; import com.facebook.react.bridge.Promise; @@ -16,7 +14,6 @@ import com.facebook.react.bridge.ReactContextBaseJavaModule; import com.facebook.react.bridge.ReactMethod; import com.facebook.react.bridge.ReadableMap; -import com.facebook.react.bridge.WritableMap; import com.google.firebase.appinvite.FirebaseAppInvite; import com.google.firebase.dynamiclinks.DynamicLink; import com.google.firebase.dynamiclinks.FirebaseDynamicLinks; @@ -47,15 +44,12 @@ public class RNFirebaseLinks extends ReactContextBaseJavaModule implements Activ } @ReactMethod - public void createDynamicLink(final ReadableMap parameters, final Promise promise) { + public void createDynamicLink(final ReadableMap linkData, final Promise promise) { try { - Map metaData = Utils.recursivelyDeconstructReadableMap(parameters); - - DynamicLink.Builder builder = getDynamicLinkBuilderFromMap(metaData); - Uri link = builder.buildDynamicLink().getUri(); - - Log.d(TAG, "created dynamic link: " + link.toString()); - promise.resolve(link.toString()); + DynamicLink.Builder builder = getDynamicLinkBuilder(linkData); + String link = builder.buildDynamicLink().getUri().toString(); + Log.d(TAG, "created dynamic link: " + link); + promise.resolve(link); } catch (Exception ex) { Log.e(TAG, "create dynamic link failure " + ex.getMessage()); promise.reject("links/failure", ex.getMessage(), ex); @@ -63,26 +57,31 @@ public class RNFirebaseLinks extends ReactContextBaseJavaModule implements Activ } @ReactMethod - public void createShortDynamicLink(final ReadableMap parameters, final Promise promise) { + public void createShortDynamicLink(final ReadableMap linkData, final String type, final Promise promise) { try { - Map metaData = Utils.recursivelyDeconstructReadableMap(parameters); + DynamicLink.Builder builder = getDynamicLinkBuilder(linkData); + Task shortLinkTask; + if ("SHORT".equals(type)) { + shortLinkTask = builder.buildShortDynamicLink(ShortDynamicLink.Suffix.SHORT); + } else if ("UNGUESSABLE".equals(type)) { + shortLinkTask = builder.buildShortDynamicLink(ShortDynamicLink.Suffix.UNGUESSABLE); + } else { + shortLinkTask = builder.buildShortDynamicLink(); + } - DynamicLink.Builder builder = getDynamicLinkBuilderFromMap(metaData); - - Task shortLinkTask = getShortDynamicLinkTask(builder, metaData) - .addOnCompleteListener(new OnCompleteListener() { + shortLinkTask.addOnCompleteListener(new OnCompleteListener() { @Override public void onComplete(@NonNull Task task) { - if (task.isSuccessful()) { - Uri shortLink = task.getResult().getShortLink(); - Log.d(TAG, "created short dynamic link: " + shortLink.toString()); - promise.resolve(shortLink.toString()); - } else { - Log.e(TAG, "create short dynamic link failure " + task.getException().getMessage()); - promise.reject("links/failure", task.getException().getMessage(), task.getException()); - } - } - }); + if (task.isSuccessful()) { + String shortLink = task.getResult().getShortLink().toString(); + Log.d(TAG, "created short dynamic link: " + shortLink); + promise.resolve(shortLink); + } else { + Log.e(TAG, "create short dynamic link failure " + task.getException().getMessage()); + promise.reject("links/failure", task.getException().getMessage(), task.getException()); + } + } + }); } catch (Exception ex) { Log.e(TAG, "create short dynamic link failure " + ex.getMessage()); promise.reject("links/failure", ex.getMessage(), ex); @@ -178,95 +177,122 @@ public class RNFirebaseLinks extends ReactContextBaseJavaModule implements Activ return FirebaseAppInvite.getInvitation(pendingDynamicLinkData) != null; } - private DynamicLink.Builder getDynamicLinkBuilderFromMap(final Map metaData) { - DynamicLink.Builder parametersBuilder = FirebaseDynamicLinks.getInstance().createDynamicLink(); + private DynamicLink.Builder getDynamicLinkBuilder(final ReadableMap linkData) { + DynamicLink.Builder builder = FirebaseDynamicLinks.getInstance().createDynamicLink(); try { - parametersBuilder.setLink(Uri.parse((String) metaData.get("link"))); - parametersBuilder.setDynamicLinkDomain((String) metaData.get("dynamicLinkDomain")); - setAndroidParameters(metaData, parametersBuilder); - setIosParameters(metaData, parametersBuilder); - setSocialMetaTagParameters(metaData, parametersBuilder); + builder.setLink(Uri.parse(linkData.getString("link"))); + builder.setDynamicLinkDomain(linkData.getString("dynamicLinkDomain")); + setAnalyticsParameters(linkData.getMap("analytics"), builder); + setAndroidParameters(linkData.getMap("android"), builder); + setIosParameters(linkData.getMap("ios"), builder); + setITunesParameters(linkData.getMap("itunes"), builder); + setNavigationParameters(linkData.getMap("navigation"), builder); + setSocialParameters(linkData.getMap("social"), builder); } catch (Exception e) { Log.e(TAG, "error while building parameters " + e.getMessage()); throw e; } - return parametersBuilder; + return builder; } - private Task getShortDynamicLinkTask(final DynamicLink.Builder builder, final Map metaData) { - Map suffix = (Map) metaData.get("suffix"); - if (suffix != null) { - String option = (String) suffix.get("option"); - if ("SHORT".equals(option)) { - return builder.buildShortDynamicLink(ShortDynamicLink.Suffix.SHORT); - } else if ("UNGUESSABLE".equals(option)) { - return builder.buildShortDynamicLink(ShortDynamicLink.Suffix.UNGUESSABLE); - } + private void setAnalyticsParameters(final ReadableMap analyticsData, final DynamicLink.Builder builder) { + DynamicLink.GoogleAnalyticsParameters.Builder analyticsParameters = new DynamicLink.GoogleAnalyticsParameters.Builder(); + + if (analyticsData.hasKey("campaign")) { + analyticsParameters.setCampaign(analyticsData.getString("campaign")); } - return builder.buildShortDynamicLink(); + if (analyticsData.hasKey("content")) { + analyticsParameters.setContent(analyticsData.getString("content")); + } + if (analyticsData.hasKey("medium")) { + analyticsParameters.setMedium(analyticsData.getString("medium")); + } + if (analyticsData.hasKey("source")) { + analyticsParameters.setSource(analyticsData.getString("source")); + } + if (analyticsData.hasKey("term")) { + analyticsParameters.setTerm(analyticsData.getString("term")); + } + builder.setGoogleAnalyticsParameters(analyticsParameters.build()); } + private void setAndroidParameters(final ReadableMap androidData, final DynamicLink.Builder builder) { + if (androidData.hasKey("packageName")) { + DynamicLink.AndroidParameters.Builder androidParameters = new DynamicLink.AndroidParameters.Builder(androidData.getString("packageName")); - private void setAndroidParameters(final Map metaData, final DynamicLink.Builder parametersBuilder) { - Map androidParameters = (Map) metaData.get("androidInfo"); - if (androidParameters != null) { - DynamicLink.AndroidParameters.Builder androidParametersBuilder = - new DynamicLink.AndroidParameters.Builder((String) androidParameters.get("androidPackageName")); - - if (androidParameters.containsKey("androidFallbackLink")) { - androidParametersBuilder.setFallbackUrl(Uri.parse((String) androidParameters.get("androidFallbackLink"))); + if (androidData.hasKey("fallbackUrl")) { + androidParameters.setFallbackUrl(Uri.parse(androidData.getString("fallbackUrl"))); } - if (androidParameters.containsKey("androidMinPackageVersionCode")) { - androidParametersBuilder.setMinimumVersion(Integer.parseInt((String) androidParameters.get("androidMinPackageVersionCode"))); + if (androidData.hasKey("minimumVersion")) { + androidParameters.setMinimumVersion(Integer.parseInt(androidData.getString("minimumVersion"))); } - parametersBuilder.setAndroidParameters(androidParametersBuilder.build()); + builder.setAndroidParameters(androidParameters.build()); } } - private void setIosParameters(final Map metaData, final DynamicLink.Builder parametersBuilder) { - Map iosParameters = (Map) metaData.get("iosInfo"); - if (iosParameters != null) { - DynamicLink.IosParameters.Builder iosParametersBuilder = - new DynamicLink.IosParameters.Builder((String) iosParameters.get("iosBundleId")); + private void setIosParameters(final ReadableMap iosData, final DynamicLink.Builder builder) { + if (iosData.hasKey("bundleId")) { + DynamicLink.IosParameters.Builder iosParameters = + new DynamicLink.IosParameters.Builder(iosData.getString("bundleId")); - if (iosParameters.containsKey("iosAppStoreId")) { - iosParametersBuilder.setAppStoreId((String) iosParameters.get("iosAppStoreId")); + if (iosData.hasKey("appStoreId")) { + iosParameters.setAppStoreId(iosData.getString("appStoreId")); } - if (iosParameters.containsKey("iosCustomScheme")) { - iosParametersBuilder.setCustomScheme((String) iosParameters.get("iosCustomScheme")); + if (iosData.hasKey("customScheme")) { + iosParameters.setCustomScheme(iosData.getString("customScheme")); } - if (iosParameters.containsKey("iosFallbackLink")) { - iosParametersBuilder.setFallbackUrl(Uri.parse((String) iosParameters.get("iosFallbackLink"))); + if (iosData.hasKey("fallbackUrl")) { + iosParameters.setFallbackUrl(Uri.parse(iosData.getString("fallbackUrl"))); } - if (iosParameters.containsKey("iosIpadBundleId")) { - iosParametersBuilder.setIpadBundleId((String) iosParameters.get("iosIpadBundleId")); + if (iosData.hasKey("iPadBundleId")) { + iosParameters.setIpadBundleId(iosData.getString("iPadBundleId")); } - if (iosParameters.containsKey("iosIpadFallbackLink")) { - iosParametersBuilder.setIpadFallbackUrl(Uri.parse((String) iosParameters.get("iosIpadFallbackLink"))); + if (iosData.hasKey("iPadFallbackUrl")) { + iosParameters.setIpadFallbackUrl(Uri.parse(iosData.getString("iPadFallbackUrl"))); } - if (iosParameters.containsKey("iosMinPackageVersionCode")) { - iosParametersBuilder.setMinimumVersion((String) iosParameters.get("iosMinPackageVersionCode")); + if (iosData.hasKey("minimumVersion")) { + iosParameters.setMinimumVersion(iosData.getString("minimumVersion")); } - parametersBuilder.setIosParameters(iosParametersBuilder.build()); + builder.setIosParameters(iosParameters.build()); } } - private void setSocialMetaTagParameters(final Map metaData, final DynamicLink.Builder parametersBuilder) { - Map socialMetaTagParameters = (Map) metaData.get("socialMetaTagInfo"); - if (socialMetaTagParameters != null) { - DynamicLink.SocialMetaTagParameters.Builder socialMetaTagParametersBuilder = - new DynamicLink.SocialMetaTagParameters.Builder(); + private void setITunesParameters(final ReadableMap itunesData, final DynamicLink.Builder builder) { + DynamicLink.ItunesConnectAnalyticsParameters.Builder itunesParameters = new DynamicLink.ItunesConnectAnalyticsParameters.Builder(); - if (socialMetaTagParameters.containsKey("socialDescription")) { - socialMetaTagParametersBuilder.setDescription((String) socialMetaTagParameters.get("socialDescription")); - } - if (socialMetaTagParameters.containsKey("socialImageLink")) { - socialMetaTagParametersBuilder.setImageUrl(Uri.parse((String) socialMetaTagParameters.get("socialImageLink"))); - } - if (socialMetaTagParameters.containsKey("socialTitle")) { - socialMetaTagParametersBuilder.setTitle((String) socialMetaTagParameters.get("socialTitle")); - } - parametersBuilder.setSocialMetaTagParameters(socialMetaTagParametersBuilder.build()); + if (itunesData.hasKey("affiliateToken")) { + itunesParameters.setAffiliateToken(itunesData.getString("affiliateToken")); } + if (itunesData.hasKey("campaignToken")) { + itunesParameters.setCampaignToken(itunesData.getString("campaignToken")); + } + if (itunesData.hasKey("providerToken")) { + itunesParameters.setProviderToken(itunesData.getString("providerToken")); + } + builder.setItunesConnectAnalyticsParameters(itunesParameters.build()); + } + + private void setNavigationParameters(final ReadableMap navigationData, final DynamicLink.Builder builder) { + DynamicLink.NavigationInfoParameters.Builder navigationParameters = new DynamicLink.NavigationInfoParameters.Builder(); + + if (navigationData.hasKey("forcedRedirectEnabled")) { + navigationParameters.setForcedRedirectEnabled(navigationData.getBoolean("forcedRedirectEnabled")); + } + builder.setNavigationInfoParameters(navigationParameters.build()); + } + + private void setSocialParameters(final ReadableMap socialData, final DynamicLink.Builder builder) { + DynamicLink.SocialMetaTagParameters.Builder socialParameters = new DynamicLink.SocialMetaTagParameters.Builder(); + + if (socialData.hasKey("descriptionText")) { + socialParameters.setDescription(socialData.getString("descriptionText")); + } + if (socialData.hasKey("imageUrl")) { + socialParameters.setImageUrl(Uri.parse(socialData.getString("imageUrl"))); + } + if (socialData.hasKey("title")) { + socialParameters.setTitle(socialData.getString("title")); + } + builder.setSocialMetaTagParameters(socialParameters.build()); } } diff --git a/ios/RNFirebase/links/RNFirebaseLinks.m b/ios/RNFirebase/links/RNFirebaseLinks.m index 6c4d2f81..63ce16c8 100644 --- a/ios/RNFirebase/links/RNFirebaseLinks.m +++ b/ios/RNFirebase/links/RNFirebaseLinks.m @@ -71,16 +71,18 @@ continueUserActivity:(NSUserActivity *)userActivity } // ** Start React Module methods ** -RCT_EXPORT_METHOD(createDynamicLink: (NSDictionary *) metadata resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) { +RCT_EXPORT_METHOD(createDynamicLink:(NSDictionary *)linkData + resolver:(RCTPromiseResolveBlock)resolve + rejecter:(RCTPromiseRejectBlock)reject) { @try { - FIRDynamicLinkComponents *components = [self getDynamicLinkComponentsFromMetadata:metadata]; + FIRDynamicLinkComponents *dynamicLink = [self buildDynamicLink:linkData]; - if (components == nil) { + if (dynamicLink == nil) { reject(@"links/failure", @"Failed to create Dynamic Link", nil); } else { - NSURL *longLink = components.url; - NSLog(@"created long dynamic link: %@", longLink.absoluteString); - resolve(longLink.absoluteString); + NSString *longLink = dynamicLink.url.absoluteString; + NSLog(@"created long dynamic link: %@", longLink); + resolve(longLink); } } @catch(NSException * e) { @@ -89,21 +91,29 @@ RCT_EXPORT_METHOD(createDynamicLink: (NSDictionary *) metadata resolver:(RCTProm } } -RCT_EXPORT_METHOD(createShortDynamicLink: (NSDictionary *) metadata resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) { +RCT_EXPORT_METHOD(createShortDynamicLink:(NSDictionary *)linkData + type:(NSString *)type + resolver:(RCTPromiseResolveBlock)resolve + rejecter:(RCTPromiseRejectBlock)reject) { @try { - FIRDynamicLinkComponents *components = [self getDynamicLinkComponentsFromMetadata:metadata]; - [self setSuffixParameters:metadata components:components]; - [components shortenWithCompletion:^(NSURL *_Nullable shortURL, - NSArray *_Nullable warnings, - NSError *_Nullable error) { + FIRDynamicLinkComponents *components = [self buildDynamicLink:linkData]; + if (type) { + FIRDynamicLinkComponentsOptions *options = [FIRDynamicLinkComponentsOptions options]; + if ([type isEqual: @"SHORT"]) { + options.pathLength = FIRShortDynamicLinkPathLengthShort; + } else if ([type isEqual: @"UNGUESSABLE"]) { + options.pathLength = FIRShortDynamicLinkPathLengthUnguessable; + } + components.options = options; + } + [components shortenWithCompletion:^(NSURL *_Nullable shortURL, NSArray *_Nullable warnings, NSError *_Nullable error) { if (error) { NSLog(@"create short dynamic link failure %@", [error localizedDescription]); reject(@"links/failure", @"Failed to create Short Dynamic Link", error); - } - else { - NSURL *shortLink = shortURL; - NSLog(@"created short dynamic link: %@", shortLink.absoluteString); - resolve(shortLink.absoluteString); + } else { + NSString *shortLink = shortURL.absoluteString; + NSLog(@"created short dynamic link: %@", shortLink); + resolve(shortLink); } }]; } @@ -139,15 +149,17 @@ RCT_EXPORT_METHOD(getInitialLink:(RCTPromiseResolveBlock)resolve rejecter:(RCTPr } // ** Start internals ** -- (FIRDynamicLinkComponents *)getDynamicLinkComponentsFromMetadata:(NSDictionary *)metadata { +- (FIRDynamicLinkComponents *)buildDynamicLink:(NSDictionary *)linkData { @try { - NSURL *link = [NSURL URLWithString:metadata[@"link"]]; - FIRDynamicLinkComponents *components = - [FIRDynamicLinkComponents componentsWithLink:link domain:metadata[@"dynamicLinkDomain"]]; + NSURL *link = [NSURL URLWithString:linkData[@"link"]]; + FIRDynamicLinkComponents *components = [FIRDynamicLinkComponents componentsWithLink:link domain:linkData[@"dynamicLinkDomain"]]; - [self setAndroidParameters:metadata components:components]; - [self setIosParameters:metadata components:components]; - [self setSocialMetaTagParameters:metadata components:components]; + [self setAnalyticsParameters:linkData[@"analytics"] components:components]; + [self setAndroidParameters:linkData[@"android"] components:components]; + [self setIosParameters:linkData[@"ios"] components:components]; + [self setITunesParameters:linkData[@"itunes"] components:components]; + [self setNavigationParameters:linkData[@"navigation"] components:components]; + [self setSocialParameters:linkData[@"social"] components:components]; return components; } @@ -157,82 +169,106 @@ RCT_EXPORT_METHOD(getInitialLink:(RCTPromiseResolveBlock)resolve rejecter:(RCTPr } } -- (void)setAndroidParameters:(NSDictionary *)metadata +- (void)setAnalyticsParameters:(NSDictionary *)analyticsData + components:(FIRDynamicLinkComponents *)components { + FIRDynamicLinkGoogleAnalyticsParameters *analyticsParams = [FIRDynamicLinkGoogleAnalyticsParameters parameters]; + + if (analyticsData[@"campaign"]) { + analyticsParams.campaign = analyticsData[@"campaign"]; + } + if (analyticsData[@"content"]) { + analyticsParams.content = analyticsData[@"content"]; + } + if (analyticsData[@"medium"]) { + analyticsParams.medium = analyticsData[@"medium"]; + } + if (analyticsData[@"source"]) { + analyticsParams.source = analyticsData[@"source"]; + } + if (analyticsData[@"term"]) { + analyticsParams.term = analyticsData[@"term"]; + } + components.analyticsParameters = analyticsParams; +} + +- (void)setAndroidParameters:(NSDictionary *)androidData components:(FIRDynamicLinkComponents *)components { - NSDictionary *androidParametersDict = metadata[@"androidInfo"]; - if (androidParametersDict) { - FIRDynamicLinkAndroidParameters *androidParams = [FIRDynamicLinkAndroidParameters - parametersWithPackageName: androidParametersDict[@"androidPackageName"]]; + if (androidData[@"packageName"]) { + FIRDynamicLinkAndroidParameters *androidParams = [FIRDynamicLinkAndroidParameters parametersWithPackageName: androidData[@"packageName"]]; - if (androidParametersDict[@"androidFallbackLink"]) { - androidParams.fallbackURL = [NSURL URLWithString:androidParametersDict[@"androidFallbackLink"]]; + if (androidData[@"fallbackUrl"]) { + androidParams.fallbackURL = [NSURL URLWithString:androidData[@"fallbackUrl"]]; } - if (androidParametersDict[@"androidMinPackageVersionCode"]) { - androidParams.minimumVersion = [androidParametersDict[@"androidMinPackageVersionCode"] integerValue]; + if (androidData[@"minimumVersion"]) { + androidParams.minimumVersion = [androidData[@"minimumVersion"] integerValue]; } components.androidParameters = androidParams; } } -- (void)setIosParameters:(NSDictionary *)metadata +- (void)setIosParameters:(NSDictionary *)iosData components:(FIRDynamicLinkComponents *)components { - NSDictionary *iosParametersDict = metadata[@"iosInfo"]; - if (iosParametersDict) { - FIRDynamicLinkIOSParameters *iOSParams = [FIRDynamicLinkIOSParameters - parametersWithBundleID:iosParametersDict[@"iosBundleId"]]; - if (iosParametersDict[@"iosAppStoreId"]) { - iOSParams.appStoreID = iosParametersDict[@"iosAppStoreId"]; + if (iosData[@"bundleId"]) { + FIRDynamicLinkIOSParameters *iOSParams = [FIRDynamicLinkIOSParameters parametersWithBundleID:iosData[@"bundleId"]]; + if (iosData[@"appStoreId"]) { + iOSParams.appStoreID = iosData[@"appStoreId"]; } - if (iosParametersDict[@"iosCustomScheme"]) { - iOSParams.customScheme = iosParametersDict[@"iosCustomScheme"]; + if (iosData[@"customScheme"]) { + iOSParams.customScheme = iosData[@"customScheme"]; } - if (iosParametersDict[@"iosFallbackLink"]) { - iOSParams.fallbackURL = [NSURL URLWithString:iosParametersDict[@"iosFallbackLink"]]; + if (iosData[@"fallbackUrl"]) { + iOSParams.fallbackURL = [NSURL URLWithString:iosData[@"fallbackUrl"]]; } - if (iosParametersDict[@"iosIpadBundleId"]) { - iOSParams.iPadBundleID = iosParametersDict[@"iosIpadBundleId"]; + if (iosData[@"iPadBundleId"]) { + iOSParams.iPadBundleID = iosData[@"iPadBundleId"]; } - if (iosParametersDict[@"iosIpadFallbackLink"]) { - iOSParams.iPadFallbackURL = [NSURL URLWithString:iosParametersDict[@"iosIpadFallbackLink"]]; + if (iosData[@"iPadFallbackUrl"]) { + iOSParams.iPadFallbackURL = [NSURL URLWithString:iosData[@"iPadFallbackUrl"]]; } - if (iosParametersDict[@"iosMinPackageVersionCode"]) { - iOSParams.minimumAppVersion = iosParametersDict[@"iosMinPackageVersionCode"]; + if (iosData[@"minimumVersion"]) { + iOSParams.minimumAppVersion = iosData[@"minimumVersion"]; } components.iOSParameters = iOSParams; } } -- (void)setSocialMetaTagParameters:(NSDictionary *)metadata - components:(FIRDynamicLinkComponents *)components { - NSDictionary *socialParamsDict = metadata[@"socialMetaTagInfo"]; - if (socialParamsDict) { - FIRDynamicLinkSocialMetaTagParameters *socialParams = [FIRDynamicLinkSocialMetaTagParameters parameters]; - if (socialParamsDict[@"socialTitle"]) { - socialParams.title = socialParamsDict[@"socialTitle"]; - } - if (socialParamsDict[@"socialDescription"]) { - socialParams.descriptionText = socialParamsDict[@"socialDescription"]; - } - if (socialParamsDict[@"socialImageLink"]) { - socialParams.imageURL = [NSURL URLWithString:socialParamsDict[@"socialImageLink"]]; - } - components.socialMetaTagParameters = socialParams; +- (void)setITunesParameters:(NSDictionary *)itunesData + components:(FIRDynamicLinkComponents *)components { + FIRDynamicLinkItunesConnectAnalyticsParameters *itunesParams = [FIRDynamicLinkItunesConnectAnalyticsParameters parameters]; + if (itunesData[@"affiliateToken"]) { + itunesParams.affiliateToken = itunesData[@"affiliateToken"]; } + if (itunesData[@"campaignToken"]) { + itunesParams.campaignToken = itunesData[@"campaignToken"]; + } + if (itunesData[@"providerToken"]) { + itunesParams.providerToken = itunesData[@"providerToken"]; + } + components.iTunesConnectParameters = itunesParams; } -- (void)setSuffixParameters:(NSDictionary *)metadata - components:(FIRDynamicLinkComponents *)components { - NSDictionary *suffixParametersDict = metadata[@"suffix"]; - if (suffixParametersDict) { - FIRDynamicLinkComponentsOptions *options = [FIRDynamicLinkComponentsOptions options]; - if ([suffixParametersDict[@"option"] isEqual: @"SHORT"]) { - options.pathLength = FIRShortDynamicLinkPathLengthShort; - } - else if ([suffixParametersDict[@"option"] isEqual: @"UNGUESSABLE"]) { - options.pathLength = FIRShortDynamicLinkPathLengthUnguessable; - } - components.options = options; +- (void)setNavigationParameters:(NSDictionary *)navigationData + components:(FIRDynamicLinkComponents *)components { + FIRDynamicLinkNavigationInfoParameters *navigationParams = [FIRDynamicLinkNavigationInfoParameters parameters]; + if (navigationData[@"forcedRedirectEnabled"]) { + navigationParams.forcedRedirectEnabled = navigationData[@"forcedRedirectEnabled"]; } + components.navigationInfoParameters = navigationParams; +} + +- (void)setSocialParameters:(NSDictionary *)socialData + components:(FIRDynamicLinkComponents *)components { + FIRDynamicLinkSocialMetaTagParameters *socialParams = [FIRDynamicLinkSocialMetaTagParameters parameters]; + if (socialData[@"descriptionText"]) { + socialParams.descriptionText = socialData[@"descriptionText"]; + } + if (socialData[@"imageUrl"]) { + socialParams.imageURL = [NSURL URLWithString:socialData[@"imageUrl"]]; + } + if (socialData[@"title"]) { + socialParams.title = socialData[@"title"]; + } + components.socialMetaTagParameters = socialParams; } - (NSArray *)supportedEvents { @@ -249,3 +285,4 @@ RCT_EXPORT_METHOD(getInitialLink:(RCTPromiseResolveBlock)resolve rejecter:(RCTPr @implementation RNFirebaseLinks @end #endif + diff --git a/lib/modules/instanceid/index.js b/lib/modules/instanceid/index.js index 3924a0a9..0cd6528d 100644 --- a/lib/modules/instanceid/index.js +++ b/lib/modules/instanceid/index.js @@ -13,6 +13,7 @@ export const NAMESPACE = 'instanceid'; export default class InstanceId extends ModuleBase { constructor(app: App) { super(app, { + hasShards: false, moduleName: MODULE_NAME, multiApp: false, namespace: NAMESPACE, diff --git a/lib/modules/invites/index.js b/lib/modules/invites/index.js index 099a6ba9..3ba53fae 100644 --- a/lib/modules/invites/index.js +++ b/lib/modules/invites/index.js @@ -23,6 +23,7 @@ export default class Invites extends ModuleBase { constructor(app: App) { super(app, { events: NATIVE_EVENTS, + hasShards: false, moduleName: MODULE_NAME, multiApp: false, namespace: NAMESPACE, diff --git a/lib/modules/links/AnalyticsParameters.js b/lib/modules/links/AnalyticsParameters.js new file mode 100644 index 00000000..36e77209 --- /dev/null +++ b/lib/modules/links/AnalyticsParameters.js @@ -0,0 +1,79 @@ +/** + * @flow + * AnalyticsParameters representation wrapper + */ +import type DynamicLink from './DynamicLink'; +import type { NativeAnalyticsParameters } from './types'; + +export default class AnalyticsParameters { + _campaign: string | void; + _content: string | void; + _link: DynamicLink; + _medium: string | void; + _source: string | void; + _term: string | void; + + constructor(link: DynamicLink) { + this._link = link; + } + + /** + * + * @param campaign + * @returns {DynamicLink} + */ + setCampaign(campaign: string): DynamicLink { + this._campaign = campaign; + return this._link; + } + + /** + * + * @param content + * @returns {DynamicLink} + */ + setContent(content: string): DynamicLink { + this._content = content; + return this._link; + } + + /** + * + * @param medium + * @returns {DynamicLink} + */ + setMedium(medium: string): DynamicLink { + this._medium = medium; + return this._link; + } + + /** + * + * @param source + * @returns {DynamicLink} + */ + setSource(source: string): DynamicLink { + this._source = source; + return this._link; + } + + /** + * + * @param term + * @returns {DynamicLink} + */ + setTerm(term: string): DynamicLink { + this._term = term; + return this._link; + } + + build(): NativeAnalyticsParameters { + return { + campaign: this._campaign, + content: this._content, + medium: this._medium, + source: this._source, + term: this._term, + }; + } +} diff --git a/lib/modules/links/AndroidParameters.js b/lib/modules/links/AndroidParameters.js new file mode 100644 index 00000000..985bfd4b --- /dev/null +++ b/lib/modules/links/AndroidParameters.js @@ -0,0 +1,60 @@ +/** + * @flow + * AndroidParameters representation wrapper + */ +import type DynamicLink from './DynamicLink'; +import type { NativeAndroidParameters } from './types'; + +export default class AndroidParameters { + _fallbackUrl: string | void; + _link: DynamicLink; + _minimumVersion: number | void; + _packageName: string | void; + + constructor(link: DynamicLink) { + this._link = link; + } + + /** + * + * @param fallbackUrl + * @returns {DynamicLink} + */ + setFallbackUrl(fallbackUrl: string): DynamicLink { + this._fallbackUrl = fallbackUrl; + return this._link; + } + + /** + * + * @param minimumVersion + * @returns {DynamicLink} + */ + setMinimumVersion(minimumVersion: number): DynamicLink { + this._minimumVersion = minimumVersion; + return this._link; + } + + /** + * + * @param packageName + * @returns {DynamicLink} + */ + setPackageName(packageName: string): DynamicLink { + this._packageName = packageName; + return this._link; + } + + build(): NativeAndroidParameters { + if ((this._fallbackUrl || this._minimumVersion) && !this._packageName) { + throw new Error( + 'AndroidParameters: Missing required `packageName` property' + ); + } + return { + fallbackUrl: this._fallbackUrl, + minimumVersion: this._minimumVersion, + packageName: this._packageName, + }; + } +} diff --git a/lib/modules/links/DynamicLink.js b/lib/modules/links/DynamicLink.js new file mode 100644 index 00000000..2930a3d0 --- /dev/null +++ b/lib/modules/links/DynamicLink.js @@ -0,0 +1,79 @@ +/** + * @flow + * DynamicLink representation wrapper + */ +import AnalyticsParameters from './AnalyticsParameters'; +import AndroidParameters from './AndroidParameters'; +import IOSParameters from './IOSParameters'; +import ITunesParameters from './ITunesParameters'; +import NavigationParameters from './NavigationParameters'; +import SocialParameters from './SocialParameters'; + +import type { NativeDynamicLink } from './types'; + +export default class DynamicLink { + _analytics: AnalyticsParameters; + _android: AndroidParameters; + _dynamicLinkDomain: string; + _ios: IOSParameters; + _itunes: ITunesParameters; + _link: string; + _navigation: NavigationParameters; + _social: SocialParameters; + + constructor(link: string, dynamicLinkDomain: string) { + this._analytics = new AnalyticsParameters(this); + this._android = new AndroidParameters(this); + this._dynamicLinkDomain = dynamicLinkDomain; + this._ios = new IOSParameters(this); + this._itunes = new ITunesParameters(this); + this._link = link; + this._navigation = new NavigationParameters(this); + this._social = new SocialParameters(this); + } + + get analytics(): AnalyticsParameters { + return this._analytics; + } + + get android(): AndroidParameters { + return this._android; + } + + get ios(): IOSParameters { + return this._ios; + } + + get itunes(): ITunesParameters { + return this._itunes; + } + + get navigation(): NavigationParameters { + return this._navigation; + } + + get social(): SocialParameters { + return this._social; + } + + build(): NativeDynamicLink { + if (!this._link) { + throw new Error('DynamicLink: Missing required `link` property'); + } else if (!this._dynamicLinkDomain) { + throw new Error( + 'DynamicLink: Missing required `dynamicLinkDomain` property' + ); + } + + return { + analytics: this._analytics.build(), + android: this._android.build(), + dynamicLinkDomain: this._dynamicLinkDomain, + ios: this._ios.build(), + itunes: this._itunes.build(), + link: this._link, + navigation: this._navigation.build(), + social: this._social.build(), + }; + } +} diff --git a/lib/modules/links/IOSParameters.js b/lib/modules/links/IOSParameters.js new file mode 100644 index 00000000..1ac46631 --- /dev/null +++ b/lib/modules/links/IOSParameters.js @@ -0,0 +1,114 @@ +/** + * @flow + * IOSParameters representation wrapper + */ +import type DynamicLink from './DynamicLink'; +import type { NativeIOSParameters } from './types'; + +export default class IOSParameters { + _appStoreId: string | void; + _bundleId: string | void; + _customScheme: string | void; + _fallbackUrl: string | void; + _iPadBundleId: string | void; + _iPadFallbackUrl: string | void; + _link: DynamicLink; + _minimumVersion: string | void; + + constructor(link: DynamicLink) { + this._link = link; + } + + /** + * + * @param appStoreId + * @returns {DynamicLink} + */ + setAppStoreId(appStoreId: string): DynamicLink { + this._appStoreId = appStoreId; + return this._link; + } + + /** + * + * @param bundleId + * @returns {DynamicLink} + */ + setBundleId(bundleId: string): DynamicLink { + this._bundleId = bundleId; + return this._link; + } + + /** + * + * @param customScheme + * @returns {DynamicLink} + */ + setCustomScheme(customScheme: string): DynamicLink { + this._customScheme = customScheme; + return this._link; + } + + /** + * + * @param fallbackUrl + * @returns {DynamicLink} + */ + setFallbackUrl(fallbackUrl: string): DynamicLink { + this._fallbackUrl = fallbackUrl; + return this._link; + } + + /** + * + * @param iPadBundleId + * @returns {DynamicLink} + */ + setIPadBundleId(iPadBundleId: string): DynamicLink { + this._iPadBundleId = iPadBundleId; + return this._link; + } + + /** + * + * @param iPadFallbackUrl + * @returns {DynamicLink} + */ + setIPadFallbackUrl(iPadFallbackUrl: string): DynamicLink { + this._iPadFallbackUrl = iPadFallbackUrl; + return this._link; + } + + /** + * + * @param minimumVersion + * @returns {DynamicLink} + */ + setMinimumVersion(minimumVersion: string): DynamicLink { + this._minimumVersion = minimumVersion; + return this._link; + } + + build(): NativeIOSParameters { + if ( + (this._appStoreId || + this._customScheme || + this._fallbackUrl || + this._iPadBundleId || + this._iPadFallbackUrl || + this._minimumVersion) && + !this._bundleId + ) { + throw new Error('IOSParameters: Missing required `bundleId` property'); + } + return { + appStoreId: this._appStoreId, + bundleId: this._bundleId, + customScheme: this._customScheme, + fallbackUrl: this._fallbackUrl, + iPadBundleId: this._iPadBundleId, + iPadFallbackUrl: this._iPadFallbackUrl, + minimumVersion: this._minimumVersion, + }; + } +} diff --git a/lib/modules/links/ITunesParameters.js b/lib/modules/links/ITunesParameters.js new file mode 100644 index 00000000..784a99ff --- /dev/null +++ b/lib/modules/links/ITunesParameters.js @@ -0,0 +1,55 @@ +/** + * @flow + * ITunesParameters representation wrapper + */ +import type DynamicLink from './DynamicLink'; +import type { NativeITunesParameters } from './types'; + +export default class ITunesParameters { + _affiliateToken: string | void; + _campaignToken: string | void; + _link: DynamicLink; + _providerToken: string | void; + + constructor(link: DynamicLink) { + this._link = link; + } + + /** + * + * @param affiliateToken + * @returns {DynamicLink} + */ + setAffiliateToken(affiliateToken: string): DynamicLink { + this._affiliateToken = affiliateToken; + return this._link; + } + + /** + * + * @param campaignToken + * @returns {DynamicLink} + */ + setCampaignToken(campaignToken: string): DynamicLink { + this._campaignToken = campaignToken; + return this._link; + } + + /** + * + * @param providerToken + * @returns {DynamicLink} + */ + setProviderToken(providerToken: string): DynamicLink { + this._providerToken = providerToken; + return this._link; + } + + build(): NativeITunesParameters { + return { + affiliateToken: this._affiliateToken, + campaignToken: this._campaignToken, + providerToken: this._providerToken, + }; + } +} diff --git a/lib/modules/links/NavigationParameters.js b/lib/modules/links/NavigationParameters.js new file mode 100644 index 00000000..dbb408fb --- /dev/null +++ b/lib/modules/links/NavigationParameters.js @@ -0,0 +1,31 @@ +/** + * @flow + * NavigationParameters representation wrapper + */ +import type DynamicLink from './DynamicLink'; +import type { NativeNavigationParameters } from './types'; + +export default class NavigationParameters { + _forcedRedirectEnabled: string | void; + _link: DynamicLink; + + constructor(link: DynamicLink) { + this._link = link; + } + + /** + * + * @param forcedRedirectEnabled + * @returns {DynamicLink} + */ + setForcedRedirectEnabled(forcedRedirectEnabled: string): DynamicLink { + this._forcedRedirectEnabled = forcedRedirectEnabled; + return this._link; + } + + build(): NativeNavigationParameters { + return { + forcedRedirectEnabled: this._forcedRedirectEnabled, + }; + } +} diff --git a/lib/modules/links/SocialParameters.js b/lib/modules/links/SocialParameters.js new file mode 100644 index 00000000..be81386b --- /dev/null +++ b/lib/modules/links/SocialParameters.js @@ -0,0 +1,55 @@ +/** + * @flow + * SocialParameters representation wrapper + */ +import type DynamicLink from './DynamicLink'; +import type { NativeSocialParameters } from './types'; + +export default class SocialParameters { + _descriptionText: string | void; + _imageUrl: string | void; + _link: DynamicLink; + _title: string | void; + + constructor(link: DynamicLink) { + this._link = link; + } + + /** + * + * @param descriptionText + * @returns {DynamicLink} + */ + setDescriptionText(descriptionText: string): DynamicLink { + this._descriptionText = descriptionText; + return this._link; + } + + /** + * + * @param imageUrl + * @returns {DynamicLink} + */ + setImageUrl(imageUrl: string): DynamicLink { + this._imageUrl = imageUrl; + return this._link; + } + + /** + * + * @param title + * @returns {DynamicLink} + */ + setTitle(title: string): DynamicLink { + this._title = title; + return this._link; + } + + build(): NativeSocialParameters { + return { + descriptionText: this._descriptionText, + imageUrl: this._imageUrl, + title: this._title, + }; + } +} diff --git a/lib/modules/links/index.js b/lib/modules/links/index.js index 95fb7566..bb128399 100644 --- a/lib/modules/links/index.js +++ b/lib/modules/links/index.js @@ -2,10 +2,10 @@ * @flow * Dynamic Links representation wrapper */ +import DynamicLink from './DynamicLink'; import { SharedEventEmitter } from '../../utils/events'; import { getLogger } from '../../utils/log'; import ModuleBase from '../../utils/ModuleBase'; -import { areObjectKeysContainedInOther, isObject, isString } from '../../utils'; import { getNativeModule } from '../../utils/native'; import type App from '../core/app'; @@ -15,59 +15,6 @@ const NATIVE_EVENTS = ['links_link_received']; export const MODULE_NAME = 'RNFirebaseLinks'; export const NAMESPACE = 'links'; -function validateParameters(parameters: Object): void { - const suportedParametersObject = { - dynamicLinkDomain: 'string', - link: 'string', - androidInfo: { - androidPackageName: 'string', - androidFallbackLink: 'string', - androidMinPackageVersionCode: 'string', - androidLink: 'string', - }, - iosInfo: { - iosBundleId: 'string', - iosFallbackLink: 'string', - iosCustomScheme: 'string', - iosIpadFallbackLink: 'string', - iosIpadBundleId: 'string', - iosAppStoreId: 'string', - }, - socialMetaTagInfo: { - socialTitle: 'string', - socialDescription: 'string', - socialImageLink: 'string', - }, - suffix: { - option: 'string', - }, - }; - if (!areObjectKeysContainedInOther(parameters, suportedParametersObject)) { - throw new Error('Invalid Parameters.'); - } -} - -function checkForMandatoryParameters(parameters: Object): void { - if (!isString(parameters.dynamicLinkDomain)) { - throw new Error('No dynamicLinkDomain was specified.'); - } - if (!isString(parameters.link)) { - throw new Error('No link was specified.'); - } - if ( - isObject(parameters.androidInfo) && - !isString(parameters.androidInfo.androidPackageName) - ) { - throw new Error('No androidPackageName was specified.'); - } - if ( - isObject(parameters.iosInfo) && - !isString(parameters.iosInfo.iosBundleId) - ) { - throw new Error('No iosBundleId was specified.'); - } -} - /** * @class Links */ @@ -96,11 +43,9 @@ export default class Links extends ModuleBase { * @param parameters * @returns {Promise.} */ - createDynamicLink(parameters: Object = {}): Promise { + createDynamicLink(link: DynamicLink): Promise { try { - checkForMandatoryParameters(parameters); - validateParameters(parameters); - return getNativeModule(this).createDynamicLink(parameters); + return getNativeModule(this).createDynamicLink(link.build()); } catch (error) { return Promise.reject(error); } @@ -111,11 +56,12 @@ export default class Links extends ModuleBase { * @param parameters * @returns {Promise.} */ - createShortDynamicLink(parameters: Object = {}): Promise { + createShortDynamicLink( + link: DynamicLink, + type?: 'SHORT' | 'UNGUESSABLE' + ): Promise { try { - checkForMandatoryParameters(parameters); - validateParameters(parameters); - return getNativeModule(this).createShortDynamicLink(parameters); + return getNativeModule(this).createShortDynamicLink(link.build(), type); } catch (error) { return Promise.reject(error); } diff --git a/lib/modules/links/types.js b/lib/modules/links/types.js new file mode 100644 index 00000000..27c947a4 --- /dev/null +++ b/lib/modules/links/types.js @@ -0,0 +1,53 @@ +/** + * @flow + */ +export type NativeAnalyticsParameters = {| + campaign?: string, + content?: string, + medium?: string, + source?: string, + term?: string, +|}; + +export type NativeAndroidParameters = {| + fallbackUrl?: string, + minimumVersion?: number, + packageName?: string, +|}; + +export type NativeIOSParameters = {| + appStoreId?: string, + bundleId?: string, + customScheme?: string, + fallbackUrl?: string, + iPadBundleId?: string, + iPadFallbackUrl?: string, + minimumVersion?: string, +|}; + +export type NativeITunesParameters = {| + affiliateToken?: string, + campaignToken?: string, + providerToken?: string, +|}; + +export type NativeNavigationParameters = {| + forcedRedirectEnabled?: string, +|}; + +export type NativeSocialParameters = {| + descriptionText?: string, + imageUrl?: string, + title?: string, +|}; + +export type NativeDynamicLink = {| + analytics: NativeAnalyticsParameters, + android: NativeAndroidParameters, + dynamicLinkDomain: string, + ios: NativeIOSParameters, + itunes: NativeITunesParameters, + link: string, + navigation: NativeNavigationParameters, + social: NativeSocialParameters, +|}; diff --git a/lib/modules/notifications/index.js b/lib/modules/notifications/index.js index d29ec73b..504bd9e0 100644 --- a/lib/modules/notifications/index.js +++ b/lib/modules/notifications/index.js @@ -76,6 +76,7 @@ export default class Notifications extends ModuleBase { constructor(app: App) { super(app, { events: NATIVE_EVENTS, + hasShards: false, moduleName: MODULE_NAME, multiApp: false, namespace: NAMESPACE,