How to implement deep linking in flutter, with redirect to app store?

Ayush Shekhar picture Ayush Shekhar · Dec 29, 2018 · Viewed 8.8k times · Source

Is there a way to achieve deep linking in a flutter, so that if a user clicks on a link then they are redirected to a specific part of the app, given that the app is installed, but if it isn't, they are redirected to the respective app store, to install the application and then taken to that specific part?

While searching for a solution I came across this package called uni_links but I am not sure if it can fulfill this requirement.

Answer

Dominique picture Dominique · Jul 11, 2019

You can use Firebase dynamic links for this purpose:

https://firebase.google.com/docs/dynamic-links

There it says:

if a user opens a Dynamic Link on iOS or Android and doesn't have your app installed, the user can be prompted to install it; then, after installation, your app starts and can access the link.

You can find information on how to implement this with Flutter here:

https://pub.dev/packages/firebase_dynamic_links

I have tried it myself with Android and iOS and it worked fine. If the app is not installed, the Google Play store or Apple AppStore is opened. The user can tap "Install" and then "Open". Afterward your app is started and the dynamic link is sent to your app (on iOS via the clipboard) where you can access it as explained on the website above. I.e. right after the start of your app in the first initState method you can call

final PendingDynamicLinkData data = await FirebaseDynamicLinks.instance.retrieveDynamicLink();
final Uri deepLink = data?.link;

to get the deep link. However in my experience on iOS this is too early to retrieve the link. I got "null" when trying it. It seemed to take a moment. I then used a WidgetsBindingObserver and watched in the didChangeAppLifecycleState method for AppLifecycleState.resumed. There I called retrieveDynamicLink. Due to a permission request (if the user allows notifications) the method was called twice. The first time it returned null but when it was called the second time it returned the deep link. So my solution looks like this:

class _MyHomePageState extends State<MyHomePage> with WidgetsBindingObserver {
  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addObserver(this);
  }

  @override
  void dispose() {
    WidgetsBinding.instance.removeObserver(this);
    super.dispose();
  }

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    if (state == AppLifecycleState.resumed) {
      _retrieveDynamicLink();
    }
  }

  /**
   * Laden des Deep Link nach der Installation.
   */
  Future<void> _retrieveDynamicLink() async {
    final PendingDynamicLinkData data = await FirebaseDynamicLinks.instance.retrieveDynamicLink();
    final Uri deepLink = data?.link;

    if (deepLink != null) {
        // Use the deepLink
        // ...
    }
}