react-native-firebase icon indicating copy to clipboard operation
react-native-firebase copied to clipboard

[🐛] getInitialLink() returns null if called too soon after launch.

Open janpe opened this issue 4 years ago • 17 comments

Issue

When my iOS app is completely closed and I use a dynamic link to open the app, getInitialLink returns null if I do it too soon. If I wait a bit it will return the link content correctly. I haven't figured out a way to make sure that the method is ready to be called. Currently I am calling it in useEffect and sometimes I get null and sometimes it works as expected, but I can't get it to work reliably without adding a considerable timeout (something like 1000ms) before calling it. So the functionality definitely works so my setup is fine but there just doesn't seem to be a way to reliably know when I can use getInitialLink.

janpe avatar Nov 13 '20 11:11 janpe

This has been noticed before and is an issue. What is causing it? I'm not exactly sure - this is an area where we could really use the community's help If there is any way you could reach in to node_modules and instrument it to log out what the code is attempting to do / data structure contents / assumptions etc and drive this to ground it would really help 🙏

mikehardy avatar Nov 13 '20 13:11 mikehardy

Me too, after update to version 10.0.0. Working on 6.4.0.

EnettyTech avatar Nov 25 '20 05:11 EnettyTech

@bachlongkocanh there were by my count 10 dynamic links releases between 6.4.0 and 10.0.0 and your report does not indicate which platform (ios or android, or both?) so is unfortunately not that informative. You also don't indicate which version of the underlying firebase-ios-sdk / firebase-android-sdk you are using. If you could bisect which version of the package and/or underlying SDK you were using to see when it breaks, that would perhaps isolate exactly which commit or version created the change

https://github.com/invertase/react-native-firebase/blob/master/packages/dynamic-links/CHANGELOG.md

mikehardy avatar Nov 25 '20 13:11 mikehardy

Hello 👋, to help manage issues we automatically close stale issues. This issue has been automatically marked as stale because it has not had activity for quite some time. Has this issue been fixed, or does it still require the community's attention?

This issue will be closed in 15 days if no further activity occurs. Thank you for your contributions.

stale[bot] avatar Dec 25 '20 11:12 stale[bot]

I'm having almost the same issue on iOS 14: the initialLink is null when running the application in release mode is the app is closed and launched by tapping on the dynamic link. I tried several versions of the dynamic links library but it's the same: 10.4.1, 7.5.12, 7.0.0.

florinleu avatar Jan 17 '21 18:01 florinleu

Solved it by adding to AppDelegate.m:

#import <RNFBDynamicLinksAppDelegateInterceptor.h>

  • (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options { return [[RNFBDynamicLinksAppDelegateInterceptor sharedInstance] application:app openURL:url options:options]; }

  • (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler { return [[RNFBDynamicLinksAppDelegateInterceptor sharedInstance] application:application continueUserActivity:userActivity restorationHandler:restorationHandler]; }

florinleu avatar Jan 19 '21 14:01 florinleu

Hello :) I'm facing similar issue as well. Here's the description:

Sometimes const link = await firebase.dynamicLinks().getInitialLink(); returns null, when app is launching from a closed state. But not all the time. It happens randomly. It could be 5 nulls, then 3-4 time with data and then nulls again. It happens ONLY in release mode (debug is working perfectly). Both on iOS and Android platforms, both on simulators and real devices.

Versions:

RN: 0.64.0 @react-native-firebase/app: 8.4.2 @react-native-firebase/dynamic-links: 7.5.3

I've also tried to upgrade to latest, but the issue was there as well.

Also I would like to try the comment above, but when I put #import <RNFBDynamicLinksAppDelegateInterceptor.h> to AppDelegate.m the error Could not build module 'RNFBDynamicLinks' appears.

@mikehardy any suggestions?

One more thing I've noticed. Long Dynamic Links always work. Issue happens only for the short

s-aleinik avatar May 17 '21 22:05 s-aleinik

Hello 👋, to help manage issues we automatically close stale issues. This issue has been automatically marked as stale because it has not had activity for quite some time. Has this issue been fixed, or does it still require the community's attention?

This issue will be closed in 15 days if no further activity occurs. Thank you for your contributions.

stale[bot] avatar Jun 26 '21 02:06 stale[bot]

Not stale, has great info, needs time to investigate, thanks for the patience all involved

mikehardy avatar Jun 26 '21 13:06 mikehardy

Here's a solution that worked for us. It's just a function that tries to get the dynamic link multiple times with a 500ms interval between the calls. It works pretty well.

import dynamicLinks, { FirebaseDynamicLinksTypes } from '@react-native-firebase/dynamic-links';

const getInitialLink = (
  maxAttempts: number,
): Promise<null | FirebaseDynamicLinksTypes.DynamicLink> => new Promise((resolve) => {
  let link: null | FirebaseDynamicLinksTypes.DynamicLink = null;

  const getLink = async (attempt: number = 1) => {
    try {
      link = await dynamicLinks().getInitialLink();
    } catch (e) {
      // Try again
    }

    if (link) {
      resolve(link);
    } else if (attempt <= maxAttempts) {
      setTimeout(() => {
        getLink(attempt + 1);
      }, 500);
    } else {
      resolve(null);
    }
  };

  getLink();
});


// And somewhere in a `useEffect` hook:
getInitialLink(20).then((link) => {
  if (link) {
    // handleDynamicLink(link);
  }
});

danlupascu avatar Jul 28 '21 08:07 danlupascu

It is still actual

"react-native": "0.66.1" "@react-native-firebase/dynamic-links": "14.5.0"

ios: 15.3.1

I`m disagreed with @s-aleinik - a long link also does not work

mtnt avatar Feb 23 '22 21:02 mtnt

This is still happening on iOS release builds and the workaround stated above (delaying retrieval of dynamic links) works for me.

thespacemanatee avatar Mar 23 '22 06:03 thespacemanatee

For anyone else here using Expo with React native. The issue we had was on the frontend with getting the initialUrl. Instead use React Native Linking library. like this: https://reactnative.dev/docs/linking - we added the event listener then like in the docs and everything worked a treat!

kierandesmond avatar Apr 06 '22 15:04 kierandesmond

@kierandesmond Does that solution allow the link to survive the app install process? I could be wrong on this but I'm pretty sure the firebase sdk's have special logic for checking the pasteboard on first run.

austin43 avatar Apr 26 '22 19:04 austin43

Has anyone encountered varying dynamic link behavior between different Android phone models? Looking around I'm seeing many running into getInitialLink() issues on iOS but I've got something different going on.

On iOS and a Google Pixel 4a getInitialLink() works every time. But when installing on my Samsung Galaxy S21 getInitialLink() returns null every other install consistently(first attempt: null, second attempt: correct link, third attempt: null, etc...). This wouldn't be so much of an issue as real users aren't going to be installing the app repeatedly with our QR codes except that it also consistently returns null on the first install after a restart, which makes me worry that it may fail for every user.

Any guesses on what causes the difference between these two devices? It's possible it's a quirk in my dev environment - I do the majority of my development on the Pixel.

erikmillergalow avatar May 27 '22 20:05 erikmillergalow

I am also seeing this exact behaviour as @erikmillergalow with getInitialLink on a Samsung S8 Tablet. if I delay my call to getInitialLink() by, say, 10 milliseconds (via setTimeout) then it works every time. Any ideas?

fowlerp-qlik avatar Jul 26 '22 13:07 fowlerp-qlik

Hello. I had a similar problem on iOS. (although to be precise, it was getInitialLink() always returning null).

"@react-native-firebase/dynamic-links": "15.2.0" "react-native": "0.64.3" iOS: 15.6.1

Finally, I was able to solve it by adding code to AppDelegate.m.

#import <RNFBDynamicLinksAppDelegateInterceptor.h>  // add this line

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
  [RNFBDynamicLinksAppDelegateInterceptor sharedInstance]; // add this line
 //-------
 // other code
 //------- 
}

My solution is to call sharedInstance in didFinishLaunchingWithOptions to explicitly set up method swizzing at app startup. (Not a very smart solution, and sharedInstance will be called several times, but the processing in sharedInstance is guarded by dispatch_once, so there should be no problem if it is called multiple times.)

As far as I have tested, swizzing is enabled by calling the sharedInstance method of the RNFBDynamicLinksAppDelegateInterceptor. Then openURL and continueUserActivity can be processed successfully.

However, in the Release build, openURL is called before sharedInstance, and the URL obtained by getInitialLink() is not saved. Conversely, in the Debug build, sharedInstance is called before openURL, as intended.

Originally, sharedInstance is called in the init method of RNFBDynamicLinksModule.m. I think the problem is caused by the different timing of initialization of native modules by react-native due to release, debugging, and other differences. (I suspect that the difference between Release and Debug that I have experienced is related to downloading the javascript-bundle from the metro server.)

gawa1019 avatar Sep 20 '22 08:09 gawa1019

The workaround here :point_up: of directly instantiating the interceptor, so that it is swizzled properly and then intercepts links correctly - has received some testing and appears to work well, per feedback in #2660 - a related issue.

apparently the swizzling on the dynamic links interceptor does not happen soon enough some times, so it does not intercept the link, but forcing it to init as the workaround does corrects this so there is no longer a race condition

mikehardy avatar Oct 19 '22 15:10 mikehardy

For Expo users, @austin43 has done a fantastic job with PR #6650, just merged, it is releasing now in v16.4.1 here

Docs are updated indicating how to take advantage of it in dynamic links section of rnfirebase.io

Would love to hear at least one confirmation that it works, as we work towards a real solution knowing the workaround truly works for everyone would help focus the effort as it confirms our understanding of the problem

mikehardy avatar Nov 02 '22 15:11 mikehardy

@mikehardy @austin43

Thanks for your help on this workaround.

Unfortunately, no chance on my side with the Expo plugin. I'm on expo SDK 45.

I don't know about the workaround itself, as on my side the issue comes from the plugin which does not apply the workaround to my AppDelegate file.

The header #import <RNFBDynamicLinksAppDelegateInterceptor.h> is correctly added in AppDelegate by the plugin, but the [RNFBDynamicLinksAppDelegateInterceptor sharedInstance]; line is not added.

I suspect a kind of conflict with the @react-native-firebase/app plugin, which add the [FIRApp configure]; first, but I did not confirm this so I'm definitely not sure that this is the reason.

I'll try to dig more when I have time. In the meantime if I can give you any additional info please let me know !

Thanks !

rlemasquerier avatar Nov 08 '22 16:11 rlemasquerier

Hello, @mikehardy

There is a problem with dynamiclinks. Short links works on emulator. However, it doesnt work on real devices. dynamicLinks() .getInitialLink() returns always null. Problem started last week. IOS and Android have same problem.

my dependencies are;

 react-native-firebase/app": "8.2.0",
 react-native-firebase/dynamic-links": "7.3.2",
 react-native: ''0.70.5''

glyhakan avatar Nov 10 '22 10:11 glyhakan

@glyhakan this is called "thread jacking". Your problem is not related in any way to the issue at hand. And your versions are quite out of date, we are on version 16+ here. After this reply to you, I will hide your comment and this comment as off topic. Please do not threadjack.

mikehardy avatar Nov 10 '22 22:11 mikehardy

@rlemasquerier I will be surprised if there is a poor interaction with the app config plugin, as everyone must use the app module here, thus everyone must use the app config plugin if they are on Expo EAS, so a mal-interaction would have shown up immediately as a bug for the developer of the plugin. There could be something about Expo 45 though, perhaps it only works with 46+ ?

mikehardy avatar Nov 10 '22 22:11 mikehardy

Hey @mikehardy, thank you for your answer !

A bit more details about what I found

This is what I found looking a bit closer :

  • If I have both plugins @react-native-firebase/app and @react-native-firebase/dynamic-links used in my expo config, only the first plugin works correctly. So in my scenario, it was only /app
  • If I use one of the 2 plugins, it seems to work as expected

With my understanding of the plugin, the issue could be on this line : https://github.com/invertase/react-native-firebase/blob/9bde409ff45858fb03d512822d3e064f344b57d5/packages/dynamic-links/plugin/src/ios/appDelegate.ts#L45

I'm afraid that since the tag @react-native-firebase/app-didFinishLaunchingWithOptions is the same as the one used by the main @react-native-firebase/app plugin, the expo pre-build step will remove it :
https://github.com/expo/expo/blob/78cca68c09c345e35634d9353cb2a9c4bc854c30/packages/%40expo/config-plugins/build/utils/generateCode.js#L62

TLDR

I have tried this small modification on my project, and it actually fixed my issue : https://github.com/rlemasquerier/react-native-firebase/commit/53c19068dafbecdef476f49f370ef4101a71cad6

It seems to me that this could be a small issue with the plugin.

Still, I agree with you, and I don't know why this did not come up before - so maybe I missed something.

What do you think ? Happy to help if I can provide more details

rlemasquerier avatar Nov 11 '22 16:11 rlemasquerier

@rlemasquerier @mikehardy It's entirely possible I missed this due to my inexperience contributing to native libraries and an over-reliance on the unit tests telling me everything was ok 😅. Probably had some wires crossed as I was testing other workarounds while I was writing this.

@rlemasquerier Could you please create a pull request with your fix?

EDIT

After doing some digging, the issue was that I had another one-off expo workaround in my code, as we're not able to use v16 of rnfb in our app yet due to some use_frameworks conflicts with other libraries, but that's another story.

I cleared out my other workaround, tested with rnfb 16.4.2 locally with your fix in tow, and the plugin now properly injects [RNFBDynamicLinksAppDelegateInterceptor sharedInstance]; 👍.

austin43 avatar Nov 11 '22 19:11 austin43

Great research + great work both of you, thank you.

This is all a bit touchy right now (use_framworks...ugh, this workaround...seriously!?)

...but I do feel like we're almost "stable" here in the sense there will be a reproducible + works well enough to trust solution.

Seems like it just needs a quick PR from @rlemasquerier with that fix you tried and we'll be set? I'd be happy to merge+release it

mikehardy avatar Nov 11 '22 21:11 mikehardy

Thank you @mikehardy @austin43 for confirming this, just opened a PR with the fix, please let me know if anything else needed :)

BTW, nothing to worry about if [RNFBDynamicLinksAppDelegateInterceptor sharedInstance]; is called before [FIRApp configure]; ? It worked as expected on my tests so I guess that's not an issue, but just wanted to let you know that the order of those injected lines depends on the order of the plugins list in expo app.config.js, I'm not sure of the impacts of this 🤔

rlemasquerier avatar Nov 11 '22 23:11 rlemasquerier

@rlemasquerier that's a reasonable concern - about the order of operations. I had not considered it.

I just read the method we are calling and it does not touch anything that is actually firebase-related, it just swizzles itself into the openURL callchain, so I think it's safe for it to be included in / execute in either order - links swizzle first or firapp configure first:

https://github.com/invertase/react-native-firebase/blob/9bde409ff45858fb03d512822d3e064f344b57d5/packages/dynamic-links/ios/RNFBDynamicLinks/RNFBDynamicLinksAppDelegateInterceptor.m#L24-L36

mikehardy avatar Nov 12 '22 00:11 mikehardy

For anyone else following along:

  1. For Expo people, there is a config plugin that should work for everyone as soon as v16.14.4 is out here (should be shortly)
  2. For non-Expo people, there is a workaround - edit your AppDelegate file and add it like this comment above https://github.com/invertase/react-native-firebase/issues/4548#issuecomment-1252028059

We are still unsure why the swizzling is not reliably happening in time for the dynamic links intercepter to get into the callchain of openURL in time, so this is an open issue, but there should be reliable workarounds available for everyone now while we get a real fix evenutally

Thanks!

mikehardy avatar Nov 12 '22 00:11 mikehardy

Hello 👋, to help manage issues we automatically close stale issues.

This issue has been automatically marked as stale because it has not had activity for quite some time.Has this issue been fixed, or does it still require attention?

This issue will be closed in 15 days if no further activity occurs.

Thank you for your contributions.

github-actions[bot] avatar Dec 10 '22 02:12 github-actions[bot]