Once the project is created lets install react-navigation package to handle our navigation. As we are using version 5.x we have to install it as follows:

npm install @react-navigation/native

npm install react-native-reanimated react-native-gesture-handler react-native-screens react-native-safe-area-context @react-native-community/masked-view

npm install @react-navigation/stack

npx pod-install ios

Add this line at the very top of your entry file (index.js or App.js) to initialise the package:

import 'react-native-gesture-handler';

Now the project is ready to go. if you’re getting any issue installing the package please check react navigation docs. Now we go ahead and create Home.js and Post.js files. Let’s start by our routing at App.js file by creating a simple navigation stack and importing the files we just created.




Setting Up the Base Project

// App.js

import React from 'react';

import { NavigationContainer } from '@react-navigation/native';

import { createStackNavigator } from '@react-navigation/stack';

import Home from './Home';

import Post from './Post';

const Stack = createStackNavigator();

const App = () => {

return (

  <NavigationContainer>

    <Stack.Navigator initialRouteName={'Home'}>

      <Stack.Screen name="Home" component={Home} />

      <Stack.Screen name="Post" component={Post} />

    </Stack.Navigator>

  </NavigationContainer>

 );

};

export default App;




At the Home.js file we're going to create a list of posts in order to navigate inside of each of them. So we have a simple list, each item has a press event where we pass the element itself as parameter to our Post.js file. So, our Home should look like this:

// Home.js

import React, { useEffect } from 'react';

import { View, FlatList, TouchableOpacity, Text, Image, StyleSheet, Linking, Platform } from 'react-native';

const posts = [

{

  id: 1,

  character: "Michael Scott",

  quote: "That's what she said.",

  pic: require("./assets/michael-scott.jpeg")

},

{

  id: 2,

  character: "Dwight Schrute",

  quote: "Any time I'm about to do something, I think to myself 'Would an idiot do that?' and if the answer is yes, I do not do that thing.",

  pic: require("./assets/dwight-schrute.jpg")

 },

 {

  id: 3,

  character: "Andy Bernard",

  quote: "I'm always thinking one step ahead, like a carpenter who makes stairs.",

  pic: require("./assets/andy-bernard.jpg")

 },

 {

  id: 4,

  character: "Kelly Kapoor",

  quote: "I am one of the few people who looks hot eating a cupcake.",

  pic: require("./assets/kelly-kapoor.jpg")

 },

 {

  id: 5,

  character: "Kevin Malone",

  quote: "When I President, they see. They see.",

  pic: require("./assets/kevin-malone.jpg")

 },

 {

  id: 6,

  character: "Angela Martin",

  quote: "I think green is kind of whorish.",

  pic: require("./assets/angela-martin.jpeg")

 }

]

const Home = ({ navigation }) => {

useEffect(() => {

     Linking.getInitialURL().then(url => {

        navigateHandler(url);

     });

     if (Platform.OS === 'ios') {

        Linking.addEventListener('url', handleOpenURL);

     }

     return () => {

        if (Platform.OS === 'ios') {       

          Linking.removeEventListener('url', handleOpenURL);

        }     

     };

  }, [])

const handleOpenURL = (event) => {

     navigateHandler(event.url);

  }

  const navigateHandler = async (url) => {

     if (url) {

        const { navigate } = navigation;

        const route = url.replace(/.*?:\/\//g, '');

        const id = route.match(/\/([^\/]+)\/?$/)[1];

        const post = posts.find(item => item.id === id);

        navigate('Post', { post: post });

     }

  }

const { row, image, title, separator, container } = styles;

  return (

     <View style={container}>

       <FlatList

         data={posts}

         keyExtractor={(item) => item.id.toString()}

         renderItem={({ item }) => (

           <TouchableOpacity onPress={() => navigation.navigate('Post', { post: item })}>

             <View style={row}>

               <Image source={item.pic} style={image} resizeMode="cover" />

               <Text style={title}>{item.character}</Text>

             </View>

           </TouchableOpacity>

          )}

         ItemSeparatorComponent={() => (

            <View style={separator} />

         )}

       />

     </View>

   );

};

export default Home;

Now we're ready to start playing with deep linking.

As you may have noticed, in Home.js file, the section bellow will be responsible to catch the url when our first component is being mounted, then once we got the url all we have to do is to parse it and get the post id.

In this piece of code we catch the url inside useEffect when the component is mounted. If we are on iOS we add the event listener handleOpenURL to catch the event that contains the url and then call the our navigateHandler function and remove it in the arrow function return if the component is about to unmount. On the other hand, if we are on Android we call navigateHandler function immediately through Linking.getInitialURL function, so there we parse the url to extract the id from it and navigate passing it as parameter to the Post component.




Configuring iOS

  1. Editing Info.plist

Now we're gonna open up the .xcworkspace file that lives inside our /ios folder and edit the info.plist file.

By default it comes as a property list so you'll have to create a new property called URL types. We expand it, create an URL identifier and give it the value of the domain for the deep linking, so in this app our url will be something like quoteapp://…

Finally we create another property called URL Schemes, we expand it and for the item 0 we set again our domain name: quoteapp.

2. Editing AppDelegate.m

At the top of the AppDelegate.m we import the following line:

#import <React/RCTLinkingManager.h>

And right after @implementation AppDelegate we add this code:

- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url

 
 

sourceApplication:(NSString *)sourceApplication annotation:(id)annotation

 

{

 

return [RCTLinkingManager application:application openURL:url

 

                    sourceApplication:sourceApplication annotation:annotation];

 

}

 



 

// Only if your app is using [Universal Links](https://developer.apple.com/library/prerelease/ios/documentation/General/Conceptual/AppSearch/UniversalLinks.html).

 

- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity

 

restorationHandler:(void (^)(NSArray * _Nullable))restorationHandler

 

{

 

return [RCTLinkingManager application:application

 

                continueUserActivity:userActivity

 

                  restorationHandler:restorationHandler];

 

}




3. Editing the Info tab

At the top of the project navigator in Xcode, click on the Info tab. You'll find the the section URL Types, so we fill the URL Schemes with your app's domain name.

So there should be it, now we can navigate to the following link. Let's give it a try and open up the navigator adding the following url:

quoteapp://post/1

So this should navigate us to the post with id 1, hence, our first post, that contains our first quote.

Configuring Android

1. Editing AndroidManifest.xml

For Android is a much simpler process. The main configuration we have to do is on AndroidManifest.xml file which you can find in android/app/src/main/AndroidManifest.xml.

So within the activity tag you'll add another <intent-filter> tag block where the <data> tag should contain your domain's name(quoteapp) as scheme and the app's section as post in this case, so we'll be able to use the same domain quoteapp://post we used in iOS.

<intent-filter android:label="filter_react_native">

  <action android:name="android.intent.action.VIEW" />

  <category android:name="android.intent.category.DEFAULT" />

  <category android:name="android.intent.category.BROWSABLE" />

  <data android:scheme="quoteapp" android:host="post" />

</intent-filter>

To test it out you'll have to open the project on Android Studio instead of running it on browser, because it won't work. So, once you have the project open, click on Run -> Edit Configurations and change Launch Option. Set Launch to URL and right below it set the URL as your app domain's name.

Now every time you run your app, Android is going to use that URL to launch the app instead of the default activity. Once the app is open through that URL we are able to catch it in our useEffect hook when component is mounted so you'll be able navigate as we want. So now if you run the app through Android Studio it should be working nicely:

So that's it. With these configurations it should work both in background mode or even if the app is killed.


If you have any questions regarding React Native Development Connect with us today!



Reference: https://medium.com/swlh/creating-deep-links-in-react-native-f6680dd959a9