Dynamic Links module of react-native-firebase not working well with Expo

Dynamic Links of Firebase allow developers to send a link to other apps. When the user clicks on the link from the other app, our app opens. Our app receives a link on starting up and we can do pretty much anything based on the link. What is more interesting is that when the app is not installed, Dynamic links prompt the user to install the app. And after the app is installed, the app receives the link and can do something with it.

For a react-native app, we make use of the popular library – react-native-firebase. The latest version of the library is v6 (version 6). It has good documentation on how to set up dynamic links module for a react-native app. However, there is one catch. This library does not work well with Expo apps. In this article, I will explain what does not work and I will provide a work-around on how to fix it.

UPDATE: If you are having trouble with getInitialLink method, I suggest you check my follow-up article on how to fix it.

Working with react-native-firebase

We can create Dynamic links from Firebase console. However, if our app requires dynamic parameters to be part of the link, we can create those links programatically.

const link = await firebase.dynamicLinks().buildLink({
  link: 'https://invertase.io',
  domainUriPrefix: 'https://xyz.page.link',
});

The above code creates a dynamic link. Usually, the link is of default domain ending with page.link. It has a lot of query parameters and does not look good when we share it on iMessage or Whatsapp. To shorten the link, there is another method buildShortLink. This is more of a URL shortener to avoid the URL with long query strings.

const link = await firebase.dynamicLinks().buildShortLink(
 {
   link: 'https://invertase.io',
   domainUriPrefix: 'https://xyz.page.link',
 }
);

The above code produces a simple URL like xyz.page.link/somechars.

After we create the dynamic link, we send the link to another app. And when the user clicks on the link, our app opens. If our app is already open, then the link triggers the onLink event handler.

firebase.dynamicLinks().onLink(() => {
    if (link.url === 'https://invertase.io/offer') 
        return navigateTo('/offers')
});

If the app is closed, then we get the dynamic link using the getInitialLink method.

const initialLink = await firebase.dynamicLinks().getInitialLink();
 
   if (initialLink) {
     if (initialLink.url === 'https://invertase.io/offer') return navigateTo('/offers')
   }

getInitialLink is not working

Within an Expo app, getInitialLink is not working. I tried raising an issue in the react-native-firebase project. They said that it is an Expo problem and that they do not support Expo. After that, I raised an issue in the Expo project. They closed the issue without taking a look at it. It appears there is some firebase support which is going to be introduced with Expo SDK.

Fortunately, there is a work-around. Linking module of react-native has a getInitialURLmethod and that works.

Linking.getInitialURL().then(url => {
  // process this URL
});

However, the URL that the Linking module receives is the shortened URL which we somehow have to interpret. Thankfully, Firebase SDK provides a resolveShortLink method. To make use of Firebase SDK, we have to write a few lines of native code.

Create a new header file (FDLResolver.h) within iOS folder and paste the below code in it.

#import <React/RCTBridgeModule.h>
#import <Firebase/Firebase.h>

@interface FDLResolver : NSObject <RCTBridgeModule>
@end

Create an implementation file (FDLResolver.m) and paste the following code in it. In the code below, we call the resolveShortLinkmethod of Firebase SDK and return the URL embedded within the dynamic link.

#import "FDLResolver.h"
#import <React/RCTLog.h>

@implementation FDLResolver

RCT_EXPORT_MODULE();

RCT_EXPORT_METHOD(resolveShortLink:(NSString *)shortLink :(RCTPromiseResolveBlock)resolve
    :(RCTPromiseRejectBlock)reject)
{
    id completion = ^(NSURL *_Nullable dynamicLink, NSError *_Nullable error) {
      if (!error && dynamicLink) {
        resolve(dynamicLink.absoluteString);
      } else {
          reject(@"Error", @"Error in getting dynamic link", error);
      }
    };

    NSURL *shortLinkURL = [NSURL URLWithString:shortLink];
    [[FIRDynamicLinks dynamicLinks] resolveShortLink:shortLinkURL completion:completion];
}

@end

And finally, we go back to our JavaScript code and parse the URL received from resolveShortLink.

Linking.getInitialURL().then(url => {
  if (url && url.includes('page.link')) {
    const shortLink = url.replace('exps', 'https')
    NativeModules.FDLResolver.resolveShortLink(shortLink)
      .then(link => {
        const linkParts = link.split('?')
        const query = qs.parse(linkParts[1])
        this.parseRouteUrl(query.deep_link_id)
      })
  }
})

We use NativeModules of react-native to get access to the FDLResolver module that we just created. Before passing the short link to the native method, we replace exps with https. And after we receive the URL from the native method, we parse the query string to get the deep_link_id parameter. This query parameter has the embedded link which our app understands.

ForceRedirectEnabled parameter

Dynamic links of Firebase is quite useful. However, testing it is a bit of pain. For example, when we paste the URL on the browser and navigate, it shows an “App preview” page. The App preview page has a “Go To App” button which takes the user to our app. However, if the user clicks the dynamic link URL from another app, the user is directly taken to our app.

To avoid the app preview page, buildShortLinkmethod provides a navigation parameter, forceRedirectEnabled.

firebase
  .dynamicLinks()
  .buildShortLink({
    link: url,
    domainUriPrefix: Config.DEEPLINK_URL,
    ios: {
      bundleId: Config.GOOGLE_BUNDLE_ID,
      appStoreId: Config.APPSTORE_ID,
    },
    navigation: {
      forcedRedirectEnabled: true,
    },
    social: {
      title,
      descriptionText,
      imageUrl,
    },
  })

With forceRedirectEnabled set to true, whenever we paste the dynamic link on the browser and navigate, we are taken directly to the App store instead of App preview page.

In short, don’t paste the dynamic link URL on your browser. Rather share the URL to another app and click it from the other app to test this feature.

Hopefully, you found the article useful. If something is not clear, please comment and I will respond or update the article to make it clearer.

Related Posts

5 thoughts on “Dynamic Links module of react-native-firebase not working well with Expo

Leave a Reply

Your email address will not be published.