Working with React Navigation V5, Firebase Cloud Messaging, and Firebase Dynamic Links

TribalScale Inc.
TribalScale
Published in
7 min readJun 3, 2021

Part 1: Setting Up React Navigation V5 for Deep Linking

By Daniel Friyia, Agile Software Engineer, TribalScale

Photo by Christina @ wocintechchat.com

Oftentimes in mobile development, clients want users to be able to link to different places in their React Native app. Usually this comes as part of sharing or deep linking from a push notification. Setting up deep linking can be a really daunting task and has a ton of essential steps to ensure it can happen correctly. I thought it would be useful to compile a complete set of instructions for doing deep linking and push notifications, so that other developers could have all the information we need in one place.

Part 1 of this series will take you through the process of setting up deep links with one of the more popular navigation libraries for React Native, namely, React-Navigation. If at any time you get stuck and want to see sample code, please look at the link to the sample project here: https://github.com/friyiajr/DeepLinkProj. That GitHub link contains the complete code for all parts which will hopefully allow you to look at it and get unstuck. Part 2 will cover setting up dynamic links and part 3 will cover setting up dynamic links with Push Notifications.

Creating a New Project

We’ll start by generating a React Native Project from scratch. If you haven’t done this before simply run: `npx react-native init DeepLinkProj — template react-native-template-typescript`. My preference is to use TypeScript, but these instructions will work for vanilla JS if you just remove the type syntax.

Setting up React Navigation

The next thing we want to do is set up React Navigation V5. This article will give my personal quickstart instructions. A more comprehensive guide to everything you can do with setup can be found here: https://reactnavigation.org/docs/getting-started/.

To set up navigation run the following commands:

  1. npm install @react-navigation/native
  2. npm install react-native-reanimated react-native-gesture-handler react-native-screens react-native-safe-area-context @react-native-community/masked-view
  3. npm install @react-navigation/stack
  4. cd ios && npx pod install

Next, import this at the top of your entry file App.tsx:

import 'react-native-gesture-handler';

Finally, wrap our app in the Navigation Controller:

const App: FC = () => {
return (
<NavigationContainer>
......
</NavigationContainer>
);
};

Next, you will want to set up Deep Linking. Like the previous section, I’ll give my quick start instructions here. If you would like additional information please consult the documentation here: https://reactnavigation.org/docs/deep-linking/.

In your iOS AppDelegate.m add the following code:

// Add the header at the top of the file:
#import <React/RCTLinkingManager.h>
// Add this above `@end`:
- (BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options
{
return [RCTLinkingManager application:application openURL:url options:options];
}

This as well:

// Add this above `@end`:
- (BOOL)application:(UIApplication *)application continueUserActivity:(nonnull NSUserActivity *)userActivity
restorationHandler:(nonnull void (^)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler
{
return [RCTLinkingManager application:application
continueUserActivity:userActivity
restorationHandler:restorationHandler];
}

Next, under your XCode info tab add a url scheme for your app. URL schemes are what allow iOS to figure out which app to open based on the deep link you provide. In our case, let’s call it mylinker. The naming here is important because it will always be the prefix of your deep link. For example mylinker://screen3 goes to your app on screen 3. If you change this name later on, you’ll need to change the prefix for all deep links in your app.

You can test your deep link by running this command `npx uri-scheme open mylinker://home — ios`. This command should open the app in the simulator

In Android run this command to set up the deep linking url scheme `npx uri-scheme add mylinker — android`. You can test whether the deep linking worked by running the following command: `npx uri-scheme open mychat://chat/jane — android`

Creating a Schema

Now that we can open the home screen of the app using a deep link, the natural next step is to want to link to other pages in the app. To do this I am going to create three screens: Home Screen, Screen 2 and Screen 3. These screens have nothing complex and only contain their names. We are going to create a schema that can link to screen 2 or 3 depending on the link that is supplied.

First we are going to create a Root Stack containing all the screens we need. It should look something like this:

const App: FC = () => {
const RootStack = createStackNavigator()
return (
<NavigationContainer>
<RootStack.Navigator>
{ROOT_STACK_SCREENS.map((screen: Screen, i: number) => (
<RootStack.Screen
key={i}
name={screen.name}
component={screen.component}
/>
))}
</RootStack.Navigator>
</NavigationContainer>
);
};

Next we will want to create a deep linking schema and set up any supporting methods. I will be covering a simplified configuration in this article. A comprehensive guide to all configurations can be found here: https://reactnavigation.org/docs/deep-linking/.

The first thing we want to do is create an object that will hold all linking options. To do this we will add the prefixes of the different links that can open our app. For simplicity’s sake we will add these to the top of the App.tsx file. For larger apps, on the other hand, it’s best to split this out into another file. These are used to filter for deep links in the app. In our case they would look like this:

const linking: LinkingOptions = {
prefixes: ['mylinker://', 'http://mylinker.com/'],

Next we want to add the getInitialUrl function. This function takes a deep link and returns the deep link path to the schema. The url passed into getInitialUrl is the one that opens the app. In our case it should look like this:

async getInitialURL(): Promise<string> {
// Check if the app was opened by a deep link
const url = await Linking.getInitialURL();
if (url != null) {
return url;
}
// If it was not opened by a deep link, go to the home screen
return 'mylinker://home';
},

The third thing we need to do is set up a subscribe function. The subscribe function listens for urls while the app is active and deep links the user:

// Custom function to subscribe to incoming links
subscribe(listener: (deeplink: string) => void) {
// First, you may want to do the default deep link handling
const onReceiveURL = ({url}: {url: string}) => listener(url);
// Listen to incoming links from deep linking
Linking.addEventListener('url', onReceiveURL);
return () => {
// Clean up the event listeners
Linking.removeEventListener('url', onReceiveURL);
};
},

Lastly we want to add a config. The config states where each link should go to in the app. The key in each case is the string we want to redirect to. The value is the path that redirects there. In our case it should look like this:

config: {
screens: {
[ROOT_SCREEN_NAMES.HOME_SCREEN]: {
path: 'home',
},
[ROOT_SCREEN_NAMES.SCREEN_TWO]: {
path: 'screen2',
},
[ROOT_SCREEN_NAMES.SCREEN_THREE]: {
path: 'screen3',
},
},
},

Finally, in your navigation controller add the linking prop like this:

<NavigationContainer linking={linking}>

Taken together, our App.tsx file should contain all of the following code from this article. If you want to see the full file, please refer to the GitHub link above.

const linking: LinkingOptions = {
prefixes: ['mylinker://', 'http://mylinker.com/'],
async getInitialURL(): Promise<string> {
// Check if the app was opened by a deep link
const url = await Linking.getInitialURL();
const dynamicLinkUrl = await dynamicLinks().getInitialLink();
if (url) {
return url;
}
// If it was not opened by a deep link, go to the home screen
return 'mylinker://home';
},
// Custom function to subscribe to incoming links
subscribe(listener: (deeplink: string) => void) {
// First, you may want to do the default deep link handling
const onReceiveURL = ({url}: {url: string}) => listener(url);
// Listen to incoming links from deep linking
Linking.addEventListener('url', onReceiveURL);
return () => {
Linking.removeEventListener('url', onReceiveURL);
};
},
config: {
screens: {
[ROOT_SCREEN_NAMES.HOME_SCREEN]: {
path: 'home',
},
[ROOT_SCREEN_NAMES.SCREEN_TWO]: {
path: 'screen2',
},
[ROOT_SCREEN_NAMES.SCREEN_THREE]: {
path: 'screen3',
},
},
},
};
const App: FC = () => {
const RootStack = createStackNavigator();
return (
<NavigationContainer linking={linking}>
<RootStack.Navigator>
{ROOT_STACK_SCREENS.map((screen: Screen, i: number) => (
<RootStack.Screen
key={i}
name={screen.name}
component={screen.component}
/>
))}
</RootStack.Navigator>
</NavigationContainer>
);
};

Now we should be able to run the deep linking command earlier and open the app to any of the screens we created. For example if we do this: `npx uri-scheme open mylinker://screen3 — ios` we should end up on screen 3.

This concludes Part 1 of this series, I hope it was helpful. Look forward to Part 2 which will cover setting up dynamic links and part 3 that will cover setting up dynamic links with Push Notifications.

For more information on deep linking with React-Native, click here to speak to one of our experts.

Daniel is an Agile Software Developer specializing in Flutter and React-Native. As much as he likes cross platform he is passionate about all types of mobile development including native iOS and Android and is always looking to advance his skill in the mobile development world.

TribalScale is a global innovation firm that helps enterprises adapt and thrive in the digital era. We transform teams and processes, build best-in-class digital products, and create disruptive startups. Learn more about us on our website. Connect with us on Twitter, LinkedIn & Facebook!

--

--

TribalScale Inc.
TribalScale

A digital innovation firm with a mission to right the future.