Skip to content

[firebase_dynamic_links] [iOS] Deeplinks do not work if they are clicked while the app is killed #9110

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

Closed
tudor07 opened this issue Jul 15, 2022 · 39 comments · Fixed by #9250
Labels
platform: ios Issues / PRs which are specifically for iOS. plugin: dynamic_links resolution: fixed A fix has been merged or is pending merge from a PR. type: bug Something isn't working

Comments

@tudor07
Copy link

tudor07 commented Jul 15, 2022

I have a deeplink that when clicked is supposed to open a specific screen.

On Android all scenarios work perfectly.

On iOS I see the following behaviours:

Working scenario:
If the app was already opened, but was put in background, if I click the deeplink, it works fine, the app is put to foreground and shows my custom screen for the opened deeplink path. These are the steps:

  1. Open my app normally (tap app icon)
  2. Put the app to background (I just dissmiss my app to go to iOS main menu, note: I do not kill my app from memory)
  3. I go and open another app where I have my deeplink (eg. Messages or Mail)
  4. Tap the deeplink
  5. My app is brought to foreground and the correct screen is shown according to the tapped deeplink path

Broken scenario:

  1. Kill my app from memory (from app switcher, swipe up on my app so it's killed)
  2. I go and open another app where I have my deeplink (eg. Messages or Mail)
  3. Tap the deeplink
  4. My app opens on the first default screen, the custom screen for the deeplink is not shown (other way to put it: my handler for the deeplink is not called, onLink/getInitialLink not called)

Minimal code to reproduce:

main.dart
import 'dart:async';

import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

    await Firebase.initializeApp(
      options: FirebaseOptions(
        apiKey: 'apiKey',
        appId: 'appId',
        messagingSenderId: 'messagingSenderId',
        projectId: 'projectId',
        authDomain: 'authDomain',
        databaseURL: 'databaseURL',
        storageBucket: 'storageBucket',
        measurementId: 'measurementId',
        androidClientId: 'androidClientId',
        iosClientId: 'iosClientId',
        iosBundleId: 'iosBundleId',
      ),
  );


  runApp(MyApp());
}
my_app.dart
import 'package:firebase_dynamic_links/firebase_dynamic_links.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

class MyApp extends StatefulWidget {
  MyApp({
    Key key,
  }) : super(key: key);

  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  @override
  void initState() {
    super.initState();

    FirebaseDynamicLinks.instance.onLink.listen(_handleDeepLink);
    _getInitialLink();
  }

  Future<void> _getInitialLink() async {
    final PendingDynamicLinkData data =
        await FirebaseDynamicLinks.instance.getInitialLink();
    _handleDeepLink(data);
  }

  @override
  Widget build(BuildContext context) {
    // return app widgets...
  }

  Future<dynamic> _handleDeepLink(PendingDynamicLinkData linkData) async {
    final Uri deepLink = linkData?.link;
    if (deepLink == null) {
      return;
    }

    if (deepLink.path == '/my/custom/path') {
      Navigator.of(context).pushNamed(MyCustomScreen.routeName);
    }
  }
}
flutter doctor
Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, 2.10.3, on macOS 12.4 21F79 darwin-arm, locale en-RO)
[✓] Android toolchain - develop for Android devices (Android SDK version 31.0.0)
[✓] Xcode - develop for iOS and macOS (Xcode 13.4.1)
[✗] Chrome - develop for the web (Cannot find Chrome executable at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome)
    ! Cannot find Chrome. Try setting CHROME_EXECUTABLE to a Chrome executable.
[✓] Android Studio (version 2021.2)
[✓] Android Studio (version 2021.2)
[✓] IntelliJ IDEA Community Edition (version 2022.1.3)
[✓] IntelliJ IDEA Community Edition (version 2022.1.2)
[✓] IntelliJ IDEA Ultimate Edition (version EAP IC-222.3244.4)
[✓] IntelliJ IDEA Ultimate Edition (version EAP IC-222.3048.13)
[✓] VS Code (version 1.69.0)
[✓] Connected device (1 available)
[✓] HTTP Host Availability

Firebase libs:

firebase_core: 1.19.2
firebase_dynamic_links: 4.3.2
@tudor07 tudor07 added Needs Attention This issue needs maintainer attention. type: bug Something isn't working labels Jul 15, 2022
@darshankawar darshankawar added the triage Issue is currently being triaged. label Jul 15, 2022
@darshankawar
Copy link

Thanks for the detailed report @tudor07

4. (other way to put it: my handler for the deeplink is not called, onLink/getInitialLink not called)

Does this mean getInitialLink() is null and onLink() is not called at all ?

Are you using dart initialization for your project or manual setup using google services file (GoogleService-Info.plist) ?

If the latter, are you using <key>FirebaseDynamicLinksCustomDomains</key> in info.plist file ?

@darshankawar darshankawar added blocked: customer-response Waiting for customer response, e.g. more information was requested. and removed Needs Attention This issue needs maintainer attention. labels Jul 15, 2022
@tudor07
Copy link
Author

tudor07 commented Jul 19, 2022

  1. Yes - getInitialLink is null, onLink not called
  2. Yes - I use Dart initialization (no .plist file)
  3. Yes, I have that entry in the Info.plist file

@google-oss-bot google-oss-bot added Needs Attention This issue needs maintainer attention. and removed blocked: customer-response Waiting for customer response, e.g. more information was requested. labels Jul 19, 2022
@darshankawar
Copy link

Thanks for the update. Can you take a look at this solution and see if it works in your case ?

Also check this comment from team member indicating that initializing with flutterfire configure may not support all firebase products yet, so maybe you can try the same scenario using GoogleService-Info.plist ?

@darshankawar darshankawar added blocked: customer-response Waiting for customer response, e.g. more information was requested. and removed Needs Attention This issue needs maintainer attention. labels Jul 20, 2022
@tudor07
Copy link
Author

tudor07 commented Jul 20, 2022

I already had the Firebase Installations API added to my API key.
Using GoogleService-Info.plist is not an option for my project.

@google-oss-bot google-oss-bot added Needs Attention This issue needs maintainer attention. and removed blocked: customer-response Waiting for customer response, e.g. more information was requested. labels Jul 20, 2022
@darshankawar
Copy link

From your flutter doctor, I see that you are on 2.10.3. Can you possibly upgrade to latest stable and try ?
Also, what iOS version are you seeing this on ? I am trying to know if this is iOS specific or not.

@darshankawar darshankawar added blocked: customer-response Waiting for customer response, e.g. more information was requested. and removed Needs Attention This issue needs maintainer attention. labels Jul 21, 2022
@tudor07
Copy link
Author

tudor07 commented Jul 21, 2022

I'm using iOS 15.5

@google-oss-bot google-oss-bot added Needs Attention This issue needs maintainer attention. and removed blocked: customer-response Waiting for customer response, e.g. more information was requested. labels Jul 21, 2022
@darshankawar
Copy link

@tudor07
From the code sample you shared earlier, specially below section:

Future<void> _getInitialLink() async {
    final PendingDynamicLinkData data =
        await FirebaseDynamicLinks.instance.getInitialLink();
    _handleDeepLink(data);
  }



Future<dynamic> _handleDeepLink(PendingDynamicLinkData linkData) async {
    final Uri deepLink = linkData?.link;
    if (deepLink == null) {
      return;
    }

    if (deepLink.path == '/my/custom/path') {
      Navigator.of(context).pushNamed(MyCustomScreen.routeName);
    }
  }  

Can you try to first check if linkData is null and if not, what it prints and then something like below ?

if (linkData != null) {
  print (`initial link $linkData`);
  }

  final Uri deepLink = linkData?.link;

  if (deepLink != null) {
   // your routing logic here
  }

@darshankawar darshankawar added blocked: customer-response Waiting for customer response, e.g. more information was requested. and removed Needs Attention This issue needs maintainer attention. labels Jul 22, 2022
@matthewfx
Copy link

I have had the same problem. However, once I tested it with a real device instead of the simulator the initial link wasn't null. @darshankawar It would be nice if you could make it work on the simulator too though :)

@tudor07
Copy link
Author

tudor07 commented Jul 27, 2022

@matthewfx I tested on a real device

@google-oss-bot google-oss-bot added Needs Attention This issue needs maintainer attention. and removed blocked: customer-response Waiting for customer response, e.g. more information was requested. labels Jul 27, 2022
@matthewfx
Copy link

@tudor07 uh oh... in that case I wonder why it sometimes works and sometimes doesn't... Quite concerning to be honest :(

@google-oss-bot google-oss-bot added the Needs Attention This issue needs maintainer attention. label Aug 2, 2022
@tudor07
Copy link
Author

tudor07 commented Aug 2, 2022

Screen recording:

RPReplay_Final1659447113.mov

@russellwheatley
Copy link
Member

russellwheatley commented Aug 2, 2022

@tudor07 - did you try this link?

reactnativefirebase.page.link/bFkn

@tudor07
Copy link
Author

tudor07 commented Aug 2, 2022

Yes, same with that one

@russellwheatley
Copy link
Member

@tudor07 You're using this branch #9250?

@russellwheatley
Copy link
Member

Could you also change the default browser as well to chrome and see if that makes a difference.

@darshankawar darshankawar added blocked: customer-response Waiting for customer response, e.g. more information was requested. and removed Needs Attention This issue needs maintainer attention. labels Aug 3, 2022
@tudor07
Copy link
Author

tudor07 commented Aug 3, 2022

I am using @russell/dynamic-9110 branch:

❯ git branch
* @russell/dynamic-9110

I get the same behaviour with Chrome.

Btw, this behaviour is for links generated inside the app, if I use reactnativefirebase.page.link/bFkn specifically I get to invertase.io/helloworld which is a 404 page.

@google-oss-bot google-oss-bot added Needs Attention This issue needs maintainer attention. and removed blocked: customer-response Waiting for customer response, e.g. more information was requested. labels Aug 3, 2022
@russellwheatley
Copy link
Member

If you get the link invertase.io/helloworld then it worked correctly. That is the deeplink:
Screenshot 2022-08-03 at 08 31 15

It is a 404 hence why we use just the path to push you to another screen to show you it works: https://github.com/firebase/flutterfire/blob/master/packages/firebase_dynamic_links/firebase_dynamic_links/example/lib/main.dart#L60

@maciejbrzezinski
Copy link

maciejbrzezinski commented Aug 3, 2022

I'm working on two apps at the moment and I spotted the same problem in one of them :v

That's weird, because scenarios when app is installed from app store or link is clicked when the app is in background works fine. Problem happens only when the app is terminated.

I also compared the two apps configs few times and I couldn't spot anything suspicious. The same plugin versions, the same firebase project, two different custom domains

I performed two tests with usage of app_links package on my apps. Both scenarios were launched by clicking dynamic link from terminated state. There was release mode and this launch option checked in XCode:
Screen Shot 2022-08-03 at 11 03 46 AM

Code that I've used in both apps:

FirebaseDynamicLinks.instance
        .getInitialLink()
        .then((value) => print('getInitialLink: $value'))
        .onError((error, stackTrace) => print(error));

    _appLinks.getInitialAppLink().then((value) {
      print('app link: $value');
      if (value != null) {
        try {
          FirebaseDynamicLinks.instance.getDynamicLink(value).then(
              (dynamicLink) => print('app link as dynamic: $dynamicLink'));
        } catch (e) {
          print(e);
        }
      }
    });

    FirebaseDynamicLinks.instance.onLink
        .listen((event) async => print('onLink: $event'));

And there are results:
Working app:
Screen Shot 2022-08-03 at 10 54 59 AM

Not working. You can see that onLink is not called, but the app_links plugin works fine:
Screen Shot 2022-08-03 at 10 53 57 AM

Any ideas where I can look for the problem cause?

@tudor07
Copy link
Author

tudor07 commented Aug 3, 2022

@russellwheatley shouldn't it open the app? My issue was about opening the app and getting the link that was clicked in Dart

@russellwheatley
Copy link
Member

@tudor07 Yes, it will open your app, and the deep link received is the one I mentioned.

@tudor07
Copy link
Author

tudor07 commented Aug 4, 2022

@russellwheatley that's not what it happens with the example app, so how can I reproduce my issue using it?
In my app, I want my app to open.
In the example app, a webpage is opened even though the app is installed.

@russellwheatley
Copy link
Member

are you running in flutter run --no-pub --release mode? Have you followed every one of these steps exactly?

@krishna700
Copy link

krishna700 commented Aug 6, 2022

I am also facing this issue.
The dynamic link opens the app correctly, but doesn't navigate when app is in terminated state. So initial link is definitely null.

Android is working fine in all states. I have tried this on release builds. I can confirm it doesn't work in IOS terminated state.

This is a very crucial feature as 80% of our customers are in IOS. Please help.

[✓] Flutter (Channel stable, 2.10.5, on macOS 12.4 21F79 darwin-arm, locale en-IN)
[✓] Android toolchain - develop for Android devices (Android SDK version 32.1.0-rc1)
[✓] Xcode - develop for iOS and macOS (Xcode 13.4.1)
[✓] Chrome - develop for the web
[✓] Android Studio (version 2021.1)
[✓] VS Code (version 1.69.2)
[✓] Connected device (1 available)
[✓] HTTP Host Availability

firebase_core: ^1.20.0
firebase_messaging: ^12.0.1
firebase_analytics: ^9.3.0
firebase_crashlytics: ^2.8.6
firebase_dynamic_links: ^4.3.3
firebase_performance: ^0.8.2+1

@ArkadiuszDatka
Copy link

ArkadiuszDatka commented Aug 8, 2022

Similarly for me, it works correctly on android and ios <= 15.5, but it does not work on ios 15.6. @krishna700 if you can verify that you can run on an older ios version.

@russellwheatley
Copy link
Member

@ArkadiuszDatka - My device uses iOS 15.6. It works.

@krishna700
Copy link

krishna700 commented Aug 8, 2022

@ArkadiuszDatka I checked in a device running 15.4.1, it doesn't work in terminated state.

@krishna700
Copy link

@russellwheatley My device uses 15.6, but it doesn't work :(

@ArkadiuszDatka
Copy link

ArkadiuszDatka commented Aug 10, 2022

@krishna700 if you can put 2 seconds delay before FirebaseDynamicLinks.instance.getInitialLink() and check if the link is non-null

@holyboom1
Copy link

holyboom1 commented Aug 12, 2022

i'm found temporary solution this problem...
i'm use library app_links

Future<String?> getInitialLink() async {
final _appLinks = AppLinks();
final PendingDynamicLinkData? linkData = await FirebaseDynamicLinks.instance.getInitialLink();
if (linkData != null) {
return linkData.link.queryParameters[payload];
} else {
final Uri? uri = await _appLinks.getInitialAppLink();
if (uri != null) {
final PendingDynamicLinkData? appLinkData = await FirebaseDynamicLinks.instance.getDynamicLink(uri);
if (appLinkData != null) {
return appLinkData.link.queryParameters[payload];
}}}
return null;
}

and we also can add platform check

@darshankawar darshankawar removed the Needs Attention This issue needs maintainer attention. label Aug 26, 2022
@darshankawar darshankawar added the resolution: fixed A fix has been merged or is pending merge from a PR. label Sep 22, 2022
@firebase firebase locked and limited conversation to collaborators Oct 23, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
platform: ios Issues / PRs which are specifically for iOS. plugin: dynamic_links resolution: fixed A fix has been merged or is pending merge from a PR. type: bug Something isn't working
Projects
None yet
9 participants