Hello Readers, CoolMonkTechie heartily welcomes you in this article (How To Handle Deep Linking in React Native ?).
In this article, We will learn how to handle deep linking in react native. Mobile apps have a unique vulnerability that is non-existent in the web: Deep Linking. Deep Linking is a technique in which a given URL or resource is used to open a specific page or screen on mobile. So, instead of just launching the app on mobile, a deep link can lead a user to a specific page within the app, providing a better experience. This specific page or screen may reside under a series of hierarchical pages, hence the term “deep” in deep linking.
Deep linking is a way of sending data directly to a native application from an outside source. A deep link looks like app://
where app
is our app scheme and anything following the // could be used internally to handle the request. As a user, we probably have experienced deep linking when opening a link to a product in a browser. If we have the app of that shop installed, it may use a deep link to open the app on that product’s page.
For example, if we were building an e-commerce app, we could use app://products/1
to deep link to our app and open the product detail page for a product with id 1. We can think of these kind of like URLs on the web.
” Deep linking consists of using a uniform resource identifier (URI) that links to a specific location within a mobile app rather than simply launching the app. Deferred deep linking allows users to deep link to content even if the app is not already installed. “
In this article, we will discuss a React Native app that opens a specific page based on the URI provided from an external source.
A famous quote about learning is :
” The beautiful thing about learning is nobody can take it away from you. “
So Let’s begin.
Why Deep Linking?
Deep Link has many use cases where it can come very handy. Think of marketing strategies, referral links, sharing a certain product, etc. The greatest benefit of mobile deep linking is the ability for marketers and app developers to bring users directly into the specific location within their app with a dedicated link. Just as deep links made the web more usable, mobile deep links do the same for mobile apps.
Example
Let’s try to mimic a React Native demo app that opens a specific page based on the URI provided from an external source. To handle deep links, we are going to use an optimum solution provided by the react-navigation
library.
Configure react-navigation in a React Native App
To start, we create a new React Native project by running the following command:
react-native init rnDeepLinkingDemo
cd rnDeepLinkingDemo
To be able to support deep linking via the navigation, we add the required npm dependencies. Once the project directory has been generated from the above command, navigate inside the project folder from our terminal and install the following dependencies.
npm install react-navigation --save
npm install react-native-gesture-handler react-native-safe-area-context @react-native-community/masked-view react-native-screens react-native-reanimated --save
npm install react-navigation-stack --save
The next step is to link all the libraries we just installed. From React Native 0.60 and higher, linking is automatic. So we don’t need to run react-native link
.
On iOS devices, we just have to run the following set of commands.
cd ios
pod install
cd ..
For Android devices, we add the following lines to the android/app/build.gradle
file under the dependencies
section:
implementation 'androidx.appcompat:appcompat:1.1.0-rc01'
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0-alpha02'
Then, open the android/app/src/main/java/com/rndeeplinkdemo/MainActivity.java
file and add the following snippet:
package com.rndeeplinkingdemo;
import com.facebook.react.ReactActivity;
import com.facebook.react.ReactActivityDelegate;
import com.facebook.react.ReactRootView;
import com.swmansion.gesturehandler.react.RNGestureHandlerEnabledRootView;
public class MainActivity extends ReactActivity {
/**
* Returns the name of the main component registered from JavaScript. This is used to schedule
* rendering of the component.
*/
@Override
protected String getMainComponentName() {
return "RNDeepLinkingDemo";
}
protected ReactActivityDelegate createReactActivityDelegate() {
return new ReactActivityDelegate(this, getMainComponentName()) {
@Override
protected ReactRootView createRootView() {
return new RNGestureHandlerEnabledRootView(MainActivity.this);
}
};
}
}
Create a Home & Details Screen
We are going to create all the screens for this example inside the directory src/screens
. To start with the home screen, create a new file Home.js
inside the aforementioned path.
This screen is going to render a list of users from an array of mock data from a placeholder API using a FlatList
component. Each user is going to be wrapped inside a TouchableOpacity
. The reason being, when an end-user presses a username from the list, this is going to contain the logic for navigating from the Home
screen to the Details
screen (which we will add later).
import React, {useState, useEffect} from 'react';
import {View, Text, FlatList, TouchableOpacity} from 'react-native';
function Home({navigation}) {
const [data, setData] = useState([]);
useEffect(() => {
fetch('https://jsonplaceholder.typicode.com/users')
.then((res) => res.json())
.then((res) => {
setData(res);
})
.catch((error) => {
console.log(error);
});
}, []);
const Separator = () => (
<View
style={{
borderBottomColor: '#d3d3d3',
borderBottomWidth: 1,
marginTop: 10,
marginBottom: 10,
}}
/>
);
return (
<View style={{flex: 1}}>
<View style={{paddingHorizontal: 20, paddingVertical: 20}}>
<FlatList
data={data}
keyExtractor={(item) => item.id.toString()}
ItemSeparatorComponent={Separator}
renderItem={({item}) => (
<TouchableOpacity
onPress={() => navigation.navigate('Details', {item})}>
<Text style={{fontSize: 24}}>{item.name}</Text>
</TouchableOpacity>
)}
/>
</View>
</View>
);
}
export default Home;
For the details screen, for now, let us display user list details. We create a new file called Details.js
. To display information for each user when visiting the Details
screen, we have to pass the value of each item using navigation parameters. Next, To fetch the data from the placeholder API on initial render, let us use the useEffect
hook from React. This hook is going to behave like a good old lifecycle method componentDidMount()
. It also allows that if the full item
object is passed or not. If not, just grab the userId
and request the API. Then, define a state variable data
to store the incoming user information. Also, modify the contents of return
in this component screen.
import React, {useState, useEffect} from 'react';
import {View, Text} from 'react-native';
function Details({navigation}) {
const [data, setData] = useState([]);
useEffect(() => {
const item = navigation.getParam('item', {});
if (Object.keys(item).length === 0) {
const userId = navigation.getParam('userId', 1);
fetch(`https://jsonplaceholder.typicode.com/users/${userId}`)
.then((res) => res.json())
.then((res) => {
const data = [];
Object.keys(res).forEach((key) => {
data.push({key, value: `${res[key]}`});
});
setData(data);
});
} else {
const data = [];
Object.keys(item).forEach((key) => {
data.push({key, value: `${item[key]}`});
});
setData(data);
}
}, []);
return (
<View style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}>
{data.map((data) => (
<Text
style={{fontSize: 20}}
key={data.key}>{`${data.key}: ${data.value}`}</Text>
))}
</View>
);
}
export default Details;
Configure Deep Linking in React Navigation
To navigate from Home to Details screen, we need Stack Navigator from react-navigation
. We create a new file called index.js
inside the src/navigation
directory and import the following statements.
import React from 'react'
import { createAppContainer, createSwitchNavigator } from 'react-navigation'
import { createStackNavigator } from 'react-navigation-stack'
import Home from '../screens/Home'
import Details from '../screens/Details'
Create a stack navigator with Home
as the initial screen. To enable deep linking, the current app requires an identifier to recognize the URI path from the external source to the screen of the app. The library react-navigation
provides a path attribute for this. It tells the router relative path to match against the URL. We configure both the routes as follows:
const MainApp = createStackNavigator({
Home: {
screen: Home,
navigationOptions: {
headerTitle: 'Home',
},
path: 'home',
},
Details: {
screen: Details,
navigationOptions: {
headerTitle: 'Details',
},
path: 'details/:userId',
},
});
In the above snippet, the dynamic variable specified by :userId
is passed to details/
. This is going to allow the app to accept a dynamic value such as details/1234
.
Next, we add the configuration to the navigation to extract the path from the incoming URL from the external resource. This is done by uriPrefix
. Add the following code snippet at the end of the file:
export default () => {
const prefix = 'myapp://';
return <AppContainer uriPrefix={prefix} />;
};
The full code of index.js file is as below :
import React from 'react';
import {createAppContainer} from 'react-navigation';
import {createStackNavigator} from 'react-navigation-stack';
import Home from '../screens/Home';
import Details from '../screens/Details';
const MainApp = createStackNavigator({
Home: {
screen: Home,
navigationOptions: {
headerTitle: 'Home',
},
path: 'home',
},
Details: {
screen: Details,
navigationOptions: {
headerTitle: 'Details',
},
path: 'details/:userId',
},
});
const AppContainer = createAppContainer(MainApp);
export default () => {
const prefix = 'myapp://';
return <AppContainer uriPrefix={prefix} />;
};
Import this navigation module inside the App.js
file for it to work:
import React from 'react';
import AppContainer from './src/navigation';
const App = () => {
return <AppContainer />;
};
export default App;
Configure URI Scheme For Native iOS Apps
To make this work, we have to configure the native iOS and Android app to open URLs based on the prefix myapp://
.
For iOS devices, open the ios/rnDeepLinkDemo/AppDelegate.m
file and add the following.
// Add the header at the top of the file:
#import <React/RCTLinkingManager.h>
// Add this above the `@end`:
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url
options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options
{
return [RCTLinkingManager application:app openURL:url options:options];
}
Open ios/rnDeepLinkingDemo.xcodeproj
in the Xcode app and select the app from the left navigation bar.
Open the Info tab.
Next, go to the URL Types.
Click the + button and in identifier as well as URL schemes add myapp
.
Rebuild the React Native binaries by running react-native run-ios
.
For Android users, we have to configure the external linking as well. Open /android/app/src/main/AndroidManifest.xml
and set the value of launchMode
to singleTask
. Also, add a new intent-filter
:
<activity
android:name=".MainActivity"
<!--set the below value-->
android:launchMode="singleTask">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<!--Add the following-->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="myapp" />
</intent-filter>
</activity>
Let’s understand the intent-filter
a little better.
” An
intent filter
is an expression in an app’s manifest file that specifies the type of intents that the component would like to receive.“
Get a closer look on <data>
tag inside <intent-filter>
. There are two properties that we have to care about. Consider scheme
as a type of incoming link and host
as the URL.
” Our Deep Link will look something like this:
myapp://home
.
Testing The App
Before we run the app on our platform of choice, make sure to re-build it using the specific command for the mobile OS as below:
# ios
react-native run-ios
# android
react-native run-android
The Example app output is going to be like below.
To test deep link in iOS, we open a web browser in our iOS simulator device and run the URL myapp://home
. It is going to ask us to whether open the external URI in the app . Next, try entering the URL myapp://details/1
and see what happens.
To test deep link in Android, we make sure our android app is in background and run this command:
adb shell am start -W -a android.intent.action.VIEW -d myapp://home com.rndeeplinkingdemo
adb shell am start -W -a android.intent.action.VIEW -d myapp://details/1 com.rndeeplinkingdemo
If our package has a different name then edit command as follows:
$ adb shell am start -W -a android.intent.action.VIEW -d <URI> <PACKAGE>
If our App opened successfully then our Deep Linking is working as expected.
That’s all about in this article.
Conclusion
In this article, We understood how to handle Deep Linking in React Native. We also discussed about a complete demo of a React Native app that handles deep linking using react-navigation
. Deep linking can bring significant improvements to the user experience of our mobile apps and enable search engines to provide context-sensitive searches and results.
Thanks for reading ! I hope you enjoyed and learned about the Deep Linking Concepts in React Native. Reading is one thing, but the only way to master it is to do it yourself.
Please follow and subscribe us on this blog and and support us in any way possible. Also like and share the article with others for spread valuable knowledge.
You can find Other articles of CoolmonkTechie as below link :
You can also follow official website and tutorials of React Native as below links :
If you have any comments, questions, or think I missed something, feel free to leave them below in the comment box.
Thanks again Reading. HAPPY READING!!???