Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[firebase_dynamic_links] Not working on app start #100

Closed
MaciDE opened this issue Sep 6, 2019 · 45 comments · Fixed by #4354
Closed

[firebase_dynamic_links] Not working on app start #100

MaciDE opened this issue Sep 6, 2019 · 45 comments · Fixed by #4354
Labels
impact: customer A bug with low impact (e.g. affecting only a few customers or has a workaround). (P3) plugin: dynamic_links type: bug Something isn't working

Comments

@MaciDE
Copy link

MaciDE commented Sep 6, 2019

Describe the bug
When opening an iOS App from a dynamic link the initialLink is nil.

To Reproduce
Steps to reproduce the behavior:

  1. Set up firebase dynamic links for a project as described in the readme.
  2. Create a dynamic link (programmatically or via console)
  3. Tap on link in non-browser app

Expected behavior
App should open and getInitialLink() should return the correct dynamic link.

Additional context
From my understanding there is an issue when reacting to the incoming UserActivity. onInitialLink is correctly called but returns way earlier than self.initialLink is set in the completion block from [[FIRDynamicLinks dynamicLinks]handleUniversalLink: completion: ] . Therefore on handling the method call FirebaseDynamicLinks#getInitialLink [self getInitialLink] returns nil and because of self.flutterError also being nil the result returns just with nil.

@MaciDE MaciDE added the type: bug Something isn't working label Sep 6, 2019
@DanielScholte
Copy link

@MaciDE Have you found a way to fix this issue or a workaround?
Currently experiencing this issue myself.

@MaciDE
Copy link
Author

MaciDE commented Sep 27, 2019

@MaciDE Have you found a way to fix this issue or a workaround?
Currently experiencing this issue myself.

Currently, I am calling getInitialLink using a delayed future. It is not working 100%, but at least it is a workaround for now.

PendingDynamicLinkData data;
    
if (Platform.isIOS) {
  await Future.delayed(Duration(seconds: 2), () async {
     data = await FirebaseDynamicLinks.instance.getInitialLink();
  });
} else {
  data = await FirebaseDynamicLinks.instance.getInitialLink();
}

@jherencia
Copy link
Contributor

jherencia commented Oct 3, 2019

I've pushed a PR with the fix, can you try? You just need to point to the PR version.

  firebase_dynamic_links:
    git:
      url: https://github.com/mrmilu/flutterfire.git
      path: packages/firebase_dynamic_links
      ref: firebase_dynamic_links-0.5.0+4

@MaciDE
Copy link
Author

MaciDE commented Oct 3, 2019

I've pushed a PR with the fix, can you try? You just need to point to the PR version?

  firebase_dynamic_links:
    git:
      url: https://github.com/mrmilu/flutterfire.git
      path: packages/firebase_dynamic_links
      ref: firebase_dynamic_links-0.5.0+4

I'll try it next week. So far it looks pretty promising :)

@HofmannZ
Copy link

HofmannZ commented Oct 4, 2019

@jherencia will test the PR tomorrow.

@HofmannZ
Copy link

HofmannZ commented Oct 7, 2019

@jherencia Your PR solves my issues! Been tinkering with this for 3 days straight, thanks so much!

@quetool
Copy link

quetool commented Oct 9, 2019

@jherencia I can confirm your PR fix the problem on iOS when app is in "killed state"

@MaciDE
Copy link
Author

MaciDE commented Oct 9, 2019

@jherencia Yep, seems like your PR fixes the issue. Thank you!

@quetool
Copy link

quetool commented Oct 10, 2019

I just realize it is not working when app is installed for the first time by touching a dynamic link... getInitialLink() is returning always null. Did anyone solve this?

@HofmannZ
Copy link

@quetool did not try it trough the App Store yet

@quetool
Copy link

quetool commented Oct 10, 2019

@HofmannZ doesn't matter app store, you can simulate app installation by running the project without the app installed. The steps are...

  1. Uninstall app
  2. Tap on a dynamic link
  3. Wait for App Store to open
  4. With App Store opened run your project and wait.

Dynamic link should work after installation (like in Android do)

@quetool
Copy link

quetool commented Oct 10, 2019

It seems to be an old iOS issue firebase/firebase-ios-sdk#1244 (comment)

@MaciDE
Copy link
Author

MaciDE commented Oct 11, 2019

@jherencia After extensively testing your PR, I can confirm that your fix is working as expected.

The dynamic link is now working when the (closed) App is opened through a dynamic link without delaying the call of FirebaseDynamicLinks.instance.getInitialLink();.
For me it is also working when the app is installed through a dynamic link. The problem mentioned by @quetool should be a problem with the use of a custom domain as he already found out.

@jherencia
Copy link
Contributor

@MaciDE

Great to hear, thank you!

@quetool
Copy link

quetool commented Oct 11, 2019

@MaciDE yep, the issue I have is when using custom domains... Using default domains like page.link is quite ugly for marketing campaigns... I will try to find a solution...

@jherencia
Copy link
Contributor

I think that in that case (with custom domains) the problem is not related with this library, it's probably related to something wrong in the configuration.

@quetool
Copy link

quetool commented Oct 11, 2019

@jherencia that's right, I checked with original version of the plugin and with your PR, none of them worked out in this case... Seems to be an old firebase issue, maybe some methods are missings in the iOS side of the plugin, don't really know....

@quetool
Copy link

quetool commented Oct 11, 2019

So, I finally find a solution. Pretty dumb indeed... The problem was somehow AppDelegate.m in my project was created (automatically or not, don't really know) with [UIApplicationDelegate application:openURL:options:] function already in it but empty inside...
For some reason this function was "overriding" the one in the plugin so that one in the plugin was never calling...
I addition, I needed to add in [UIApplicationDelegate application:didFinishLaunchingWithOptions:] this calls...

[FIROptions defaultOptions].deepLinkURLScheme = @"my-custom-scheme";
[FIRApp configure];

The first one in order to work with customs schemes, and the second one because for some reason [FIRApp configure] is not being called inside the plugin (don't know if it is a bug or no)...

This is AppDelegate.m now

#include "AppDelegate.h"
#include "GeneratedPluginRegistrant.h"

@import Firebase;
@implementation AppDelegate

- (BOOL)application:(UIApplication *)application
    didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    
    [FIROptions defaultOptions].deepLinkURLScheme = @"my-custom-scheme";
    [FIRApp configure];
    [GeneratedPluginRegistrant registerWithRegistry:self];

    // Override point for customization after application launch.
  return [super application:application didFinishLaunchingWithOptions:launchOptions];
}

//- (BOOL)application:(UIApplication *)application
//            openURL:(NSURL *)url
//            options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
//    // Add any custom logic here.
//    
//    return true;
//}

@end

So now I have Dynamic Links fully functional both on iOS and Android thanks to @jherencia with his PR and some research on my own :P

I hope it helps someone in the future...

@MaciDE
Copy link
Author

MaciDE commented Nov 3, 2019

So what is going on with this issue? Looks like the pr by @jherencia is also in an unsettled state.
Does not really look that great for the open source part of flutter...

jherencia added a commit to mrmilu/flutterfire that referenced this issue Nov 3, 2019
@jherencia
Copy link
Contributor

I've updated the PR, fireabase_dynamic_links 0.5.0+4 was officially published so the new valid version from my repo is:

  firebase_dynamic_links:
    git:
      url: https://github.com/mrmilu/flutterfire.git
      path: packages/firebase_dynamic_links
      ref: firebase_dynamic_links-0.5.0+5

@MaciDE
Copy link
Author

MaciDE commented Nov 4, 2019

@jherencia Looking forward to see your pr getting merged and a new version released. It only takes someone authorized pressing the merge button... :)

@quetool
Copy link

quetool commented Nov 4, 2019

@jherencia what did you do in this PR?

@jherencia
Copy link
Contributor

jherencia commented Nov 4, 2019

@quetool

Nothing, I just applied the changes from master branch so it can be merged. They upgraded the url_launcher version (04b7954) and some change about androidX (31cad01)

@quetool
Copy link

quetool commented Nov 4, 2019

@jherencia thanks!

@shashikantdurge
Copy link

Any updates on this ? It's been a long time

@Dennis-Mwea
Copy link

Any update on this? The delayed init seems not to be working either

@Dennis-Mwea
Copy link

Dennis-Mwea commented Jun 15, 2020

Temporary fix

class _MyAppState extends State<_MyApp> with WidgetsBindingObserver {
 @override
 void initState() {
   WidgetsBinding.instance.addObserver(this);
   super.initState();
   DynamicLinksService.initDynamicLinks(context);
 }

 @override
 void didChangeAppLifecycleState(AppLifecycleState state) {
   if (state == AppLifecycleState.resumed) {
     DynamicLinksService.initDynamicLinks(context);
   }
 }
}

jacek-marchwicki added a commit to jacek-marchwicki/flutterfire that referenced this issue Jun 22, 2020
Description:
Fixing race-condition with getInitialLink and actuall setup
this initial link on iOS devices

Closes: firebase#100
Closes: firebase#1847
Closes: firebase#1861
jacek-marchwicki added a commit to jacek-marchwicki/flutterfire that referenced this issue Jun 22, 2020
Description:
Fixing race-condition with getInitialLink and actuall setup
this initial link on iOS devices

Closes: firebase#100
Closes: firebase#1847
Closes: firebase#1861
@koskimas
Copy link

Doesn't this commit already fix this issue f4289e2?

@degloff
Copy link

degloff commented Oct 8, 2020

It seems this issue is back with firebase_dynamic_links: ^0.6.0+2

Behaviour: The app is properly started by clicking the link, however, FirebaseDynamicLinks.instance.getInitialLink() almost always returns null, but in some cases it works, however not too frequent, probably 1 out of 10 or less.

Conclusion: This indicates that the race condition still prevails and the bug is not properly fixed by the pull request #255.

I tried all the above workarounds, non of it seems to work:

(1) delay FirebaseDynamicLinks.instance.getInitialLink() like this

      PendingDynamicLinkData data;
      if (Platform.isIOS) {
        await Future.delayed(Duration(seconds: 2), () async {
          data = await FirebaseDynamicLinks.instance.getInitialLink();
        });
      } else {
        data = await FirebaseDynamicLinks.instance.getInitialLink();
      }

      final Uri deepLink = data?.link;

     .....

(2) Calling in main after WidgetsFlutterBinding.ensureInitialized() but before calling runApp, awaiting getInitialLink
(3) Calling in a stateful widget and also delaying in didChangeAppLifecycleState as suggested in earlier workaround (2019)

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addObserver(this);
    locator.get<DynamicLinkService>().initDynamicLinks(); // getInitialLink and onLink
  }

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    if (state == AppLifecycleState.resumed) {
      timerLink = new Timer(const Duration(milliseconds: 1000), () async {
          await locator.get<DynamicLinkService>().initDynamicLinks(); // getInitialLink and onLink
        },
      );
    }
  }

I also realised that in a recent commit the order has changed, now the example first calls
onLink to register the handlers and then getInitialLink. This does not make any difference either.

I tested a custom dynamic link and also the Firebase Auth Email link, same behaviour, getInitialLink returns with null.

All tested on physical device. Android works perfectly.

My Flutter version

[✓] Flutter (Channel master, 1.22.0-2.0.pre.93, on Mac OS X 10.15.6 19G2021, locale en-CH)
    • Flutter version 1.22.0-2.0.pre.93 at /Users/dani/development/flutter
    • Framework revision f35a8b7470 (6 weeks ago), 2020-08-26 21:33:03 -0700
    • Engine revision 388193a67b
    • Dart version 2.10.0 (build 2.10.0-62.0.dev)

[✓] Android toolchain - develop for Android devices (Android SDK version 30.0.0)
    • Android SDK at /Users/dani/Library/Android/sdk
    • Platform android-30, build-tools 30.0.0
    • Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6222593)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 12.0.1)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Xcode 12.0.1, Build version 12A7300
    • CocoaPods version 1.9.3

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 4.0)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin version 46.0.2
    • Dart plugin version 193.7361
    • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6222593)

[✓] IntelliJ IDEA Ultimate Edition (version 2019.2.4)
    • IntelliJ at /Applications/IntelliJ IDEA.app
    • Flutter plugin version 38.2.4
    • Dart plugin version 192.7761

[✓] VS Code (version 1.49.2)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.15.0

Happy to do further debugging and diving deeper if someone can give me indications/directions what to do to pinpoint this recurring issue.

@jherencia
Copy link
Contributor

@degloff #100 has not been merged, so it is not part of firebase_dynamic_links: ^0.6.0+2.

@degloff
Copy link

degloff commented Oct 9, 2020

@jherencia from going through the discussion above it looks like that #255 should have fixed it as mentioned by @tapizquent, which seems to be merged back. There is also a note in the release notes. So what is the status?

@degloff
Copy link

degloff commented Oct 9, 2020

I tested Christian's @hffmnn pull request #2580

  firebase_dynamic_links:
    git:
      url: https://github.com/soundreply/flutterfire.git
      path: packages/firebase_dynamic_links
      ref: feature/initial-link-resolving-ios

This seems to fix the issue at least in my setup. As this is a recurring issue open now for a year can someone with the authority press the merge button? Thanks.

@koskimas
Copy link

koskimas commented Oct 9, 2020

@degloff I think there's a common misunderstanding of how the getInitialLink method works and how the initialization should be done. The PR #2580 is a perfect example of this misunderstanding. I'm pretty sure these new reports after the 0.6.0 are mainly caused by this misunderstanding. The 0.6.0 versio has the original bug fixed.

getInitialLink DOES NOT wait for the initial link, and it shouldn't. It only returns the link that may or may not have been received before the onLink listener has been installed.

The initial link may just as well be delivered to the onLink listener. You shouldn't expect to alsways get it from getInitialLink or onLink. It will be delivered by one or the other, but it depends on the timing and pure chance.

So if you first install the onLink listener, and after that call getInitialLink and are prepared to get the link from either, everything works with the current version.

@degloff
Copy link

degloff commented Oct 9, 2020

@koskimas thanks for the reply. I observed exactly that change in the 0.6.0 version and i checked it carefully. I commented already on this in my previous comment.

I also realised that in a recent commit the order has changed, now the example first calls
onLink to register the handlers and then getInitialLink. This does not make any difference either.

But it does NOT solve the problem! Also onLink does not fire.

@koskimas
Copy link

koskimas commented Oct 9, 2020

@degloff

But it does NOT solve the problem! Also onLink does not fire.

Works for me every single time on multiple different devices. I think you'll need to show a reproducible example of the fail for people to take this seriously.

@degloff
Copy link

degloff commented Oct 9, 2020

@koskimas our app startup sequence is quite complex including some more exotic things like WeChat and Line plugin. This may cause a situation that is unique. All I can confirm is that @hffmnn solution works so far always, whereas the suggested approach is only working in less than 10%. Quite a puzzle.

@niwatly
Copy link

niwatly commented Oct 29, 2020

@koskimas Thank you! This comment helps me.

getInitialLink DOES NOT wait for the initial link, and it shouldn't. It only returns the link that may or may not have been received before the onLink listener has been installed.

I had been falling to get initial link,

    _initialLinkCompleter.complete(component.getInitialLink());

    component.onLink(
      onSuccess: (data) async {
        _linkSub.add(data);
      },
      onError: (e) async {
        recordError(e, StackTrace.current);
      },
    );

but solved by swaping onLink and getInitialLink.

    component.onLink(
      onSuccess: (data) async {
        _linkSub.add(data);
      },
      onError: (e) async {
        recordError(e, StackTrace.current);
      },
    );

    _initialLinkCompleter.complete(component.getInitialLink());

@and2long
Copy link

and2long commented Nov 7, 2020

https://pub.dev/packages/firebase_dynamic_links#handle-received-dynamic-links

image

This question has been bothering me all day.
In iOS, I add code in red box, then it worked.

Finally ,my code like this:

  @override
  void initState() {
    super.initState();
    initDynamicLinks();
  }

  void initDynamicLinks() async {
    FirebaseDynamicLinks.instance.onLink(
        onSuccess: (PendingDynamicLinkData dynamicLink) async {
      _checkDynamicLinkParams(dynamicLink);
    }, onError: (OnLinkErrorException e) async {
      Log.d(tag, e.message);
    });
    final PendingDynamicLinkData data =
        await FirebaseDynamicLinks.instance.getInitialLink();
    _checkDynamicLinkParams(data);
  }

  void _checkDynamicLinkParams(PendingDynamicLinkData dynamicLink) {
    // do something...
  }

@russellwheatley
Copy link
Member

I'm going to close this as I believe this comment captures the misconception perfectly. Please do not rely on the getInitialLink API to fire perfectly each time, you have to design your app with the likelihood the onLink listener will receive the link data.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
impact: customer A bug with low impact (e.g. affecting only a few customers or has a workaround). (P3) plugin: dynamic_links type: bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.