Skip to content

Commit

Permalink
fix(dynamic-links, android): getInitialLink returned more than once, …
Browse files Browse the repository at this point in the history
…sometimes returned null (#4735)

* fix - initial link when launched from history
* fix - getInitialLink sometimes returns null
* fix - getInitial link guards and add comments
* Apply suggestions from code review

Co-authored-by: Mike Hardy <[email protected]>
  • Loading branch information
sharc7 and mikehardy authored Jan 25, 2021
1 parent 38f3ac1 commit c68a62c
Showing 1 changed file with 57 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,28 @@ public class ReactNativeFirebaseDynamicLinksModule extends ReactNativeFirebaseMo
private static final String SHORT_LINK_TYPE_UNGUESSABLE = "UNGUESSABLE";

private String initialLinkUrl = null;
private boolean gotInitialLink = false;
private int initialLinkMinimumVersion = 0;

/**
* Ensures calls to getInitialLink only tries to retrieve the link from getDynamicLink once.
*/
private boolean gotInitialLink = false;
/**
* Used by getInitialLink to check if the activity has been resumed.
* "host" refers to the host activity, in terms of {@link LifeCycleEventListener#onHostResume()}
*/
private boolean hostResumed = false;
/**
* Used by getInitialLink to check the current activity's intent flags to verify that the app
* hasn't been resumed from the Overview (history) screen.
*/
private boolean launchedFromHistory = false;
/**
* Holds the Promise that was passed to getInitialLink
* if getInitialLink was called before {@link com.facebook.react.common.LifecycleState#RESUMED} Lifecycle state.
*/
private Promise initialPromise = null;

ReactNativeFirebaseDynamicLinksModule(ReactApplicationContext reactContext) {
super(reactContext, TAG);
getReactApplicationContext().addActivityEventListener(this);
Expand Down Expand Up @@ -106,25 +125,38 @@ public void buildShortLink(ReadableMap dynamicLinkMap, String shortLinkType, Pro

@ReactMethod
public void getInitialLink(Promise promise) {
// Check if getDynamicLink() has already completed successfully.
// This ensures the initial link is returned once, if found.
if (gotInitialLink) {
if (initialLinkUrl != null) {
promise.resolve(dynamicLinkToWritableMap(initialLinkUrl, initialLinkMinimumVersion));
} else {
promise.resolve(null);
}
promise.resolve(null);
return;
}

// Check for the case where getInitialLink
// runs before the LifeCycleState is RESUMED (e.g. BEFORE_CREATE or BEFORE_RESUME).
if (!hostResumed) {
// Use initialPromise to store the Promise that was passed and
// run it when LifeCycleState changes to RESUMED in onHostResume.
initialPromise = promise;
return;
}

Activity currentActivity = getCurrentActivity();
// Shouldn't happen anymore, left as a guard.
if (currentActivity == null) {
promise.resolve(null);
return;
}

FirebaseDynamicLinks.getInstance().getDynamicLink(currentActivity.getIntent())
Intent currentIntent = currentActivity.getIntent();
// Verify if the app was resumed from the Overview (history) screen.
launchedFromHistory = (currentIntent != null) && ((currentIntent.getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) != 0);

FirebaseDynamicLinks.getInstance().getDynamicLink(currentIntent)
.addOnCompleteListener(task -> {
if (task.isSuccessful()) {
// Flag that the getDynamicLink() completed successfully,
// preventing future calls to from receiving the link, as if the link had been cleared.
gotInitialLink = true;
PendingDynamicLinkData pendingDynamicLinkData = task.getResult();

Expand All @@ -133,7 +165,9 @@ public void getInitialLink(Promise promise) {
initialLinkMinimumVersion = pendingDynamicLinkData.getMinimumAppVersion();
}

if (initialLinkUrl != null) {
// 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));
} else {
promise.resolve(null);
Expand Down Expand Up @@ -371,6 +405,9 @@ public void onHostDestroy() {
initialLinkUrl = null;
gotInitialLink = false;
initialLinkMinimumVersion = 0;
launchedFromHistory = false;
initialPromise = null;
hostResumed = false;
}

@Override
Expand All @@ -397,9 +434,21 @@ public void onActivityResult(Activity activity, int requestCode, int resultCode,

@Override
public void onHostResume() {
// Flag state is resumed.
hostResumed = true;
// Check if getInitialLink was called before LifeCycleState was RESUMED
// and there's a pending Promise.
if (initialPromise != null) {
// Call getInitialLink getInitialLink with the Promise that was passed in the original call.
getInitialLink(initialPromise);
// Clear the Promise
initialPromise = null;
}
}

@Override
public void onHostPause() {
// Flag state is not resumed.
hostResumed = false;
}
}

1 comment on commit c68a62c

@vercel
Copy link

@vercel vercel bot commented on c68a62c Jan 25, 2021

Choose a reason for hiding this comment

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

Please sign in to comment.