DEV Community

Suraj Prasad
Suraj Prasad

Posted on

Creating Dynamic Links and Deep Linking URLs in Node.js for React Native

In the mobile app ecosystem, providing a seamless user experience is critical. One way to enhance this is by implementing deep links and dynamic links within your app. Dynamic links allow you to share content and ensure users have a smooth transition whether they have your app installed or not. In this blog, we'll explore how to create dynamic links and deep linking URLs using Node.js for a React Native application.
What Are Dynamic Links and Deep Links?
Deep Links: These are URLs that take users to a specific part of your app. When users click on a deep link, the app opens to the specific content the link is meant to display. If the app is not installed, the link typically opens the web version of the app or a fallback page.
Dynamic Links: These are deep links with added flexibility. They can change their behavior based on different conditions, such as whether the app is installed, the platform (iOS or Android), or even the context in which the link is opened (e.g., marketing campaigns).

Why Use Dynamic Links?
Cross-Platform Compatibility: Dynamic links work on multiple platforms, including iOS, Android, and web.
Deferred Deep Linking: If the app isn't installed, dynamic links can direct users to the app store and then to the specific content once the app is installed.
Enhanced User Experience: They provide a more personalized experience by directing users to the right content within your app.

Prerequisites
Before we dive in, make sure you have the following:
Node.js installed on your machine.
A React Native project setup.
Firebase account (optional, but recommended for generating dynamic links).

Step 1: Setting Up a Node.js Server

We'll start by setting up a Node.js server that will generate dynamic links. You can use Express.js to create a simple server.
First, create a new Node.js project:

mkdir dynamic-links-server
cd dynamic-links-server
npm init -y
npm install express shortid
Enter fullscreen mode Exit fullscreen mode

Step 2: Generating Dynamic Links

const express = require("express");
const shortId = require("shortid")

const { appendSeoDetail } = require("./utils");
const app = express()

const PORT = process.env.PORT || 3000

app.use(express.json())
app.use("/.well-known", express.static('.well-known'))

const urls = {};

app.post("/create-url", (req, res) => {
  try {
    const { title, description, image, newsId } = req.body
    const previewUrl = `https://3a09-2402-4cc0-2501-1f4-71ad-7a58-7a4c-895c.ngrok-free.app/?newsId=${newsId}&title=${encodeURIComponent(title)}&description=${encodeURIComponent(description)}&image=${encodeURIComponent(image)}`
    const id = shortId.generate();
    urls[id] = previewUrl;
    res.send({ url: `https://3a09-2402-4cc0-2501-1f4-71ad-7a58-7a4c-895c.ngrok-free.app/${id}` })
  } catch (error) {
    res.send({ error: "Something went wrong" })
  }
})

app.get('/:id', (req, res) => {
  const id = req.params.id;
  const url = urls[id];

  if (url) {
    res.redirect(url);
  } else {
    res.sendStatus(404);
  }
});

app.get('*', (req, res,) => {
  const { title, description, image } = req.query
  // Define values
  const source = appendSeoDetail({ title, description, image })
  // Return the webpage
  return res.send(source);
});

app.listen(PORT, () => {
  console.log("App is running on ", PORT)
})
Enter fullscreen mode Exit fullscreen mode

Step 3: Creating index html for the social share preview

<!DOCTYPE html>
<html lang="en">
 <head>
  <!-- HTML Meta Tags -->
  <title>{{title}}</title>
  <meta name="description" content="{{description}}" />

  <!-- Facebook Meta Tags -->
  <meta property="og:url" content="https://3a09-2402-4cc0-2501-1f4-71ad-7a58-7a4c-895c.ngrok-free.app/" />
  <meta property="og:type" content="website" />
  <meta property="og:title" content="{{title}}" />
  <meta property="og:description" content="{{description}}" />
  <meta property="og:image" content="{{image}}" />

  <!-- Twitter Meta Tags -->
  <meta name="twitter:card" content="summary_large_image" />
  <meta property="twitter:domain" content="3a09-2402-4cc0-2501-1f4-71ad-7a58-7a4c-895c.ngrok-free.app" />
  <meta property="twitter:url" content="https://3a09-2402-4cc0-2501-1f4-71ad-7a58-7a4c-895c.ngrok-free.app/" />
  <meta name="twitter:title" content="{{title}}" />
  <meta name="twitter:description" content="{{description}}" />
  <meta name="twitter:image" content="{{image}}" />

  <!-- Meta Tags Generated via https://www.opengraph.xyz -->

  <link
   rel="stylesheet"
   href="https://cdn.jsdelivr.net/npm/bootstrap@4.0.0/dist/css/bootstrap.min.css"
   integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm"
   crossorigin="anonymous"
  />

  <script
   src="https://cdnjs.cloudflare.com/ajax/libs/Detect.js/2.2.2/detect.min.js"
   rossorigin="anonymous"
   referrerpolicy="no-referrer"
  ></script>
 </head>

 <body>
  <div class="container pt-3">
   <div class="text-center row justify-content-center">
    <div class="col-10">
     <a href="#">
      <img src="https://www.pouch.news/cropped-pulse%201.png" class="img-fluid" alt="" />
     </a>
    </div>
   </div>
   <div class="centered row mt-3 justify-content-center align-items-center">
    <div class="col-md-3 col-10 text-center">
     <p id="message"></p>
     <p id="redirectMessage text-center d-none d-md-block">Redirecting you to Example app.</p>
    </div>
   </div>
  </div>
 </body>

 <script>
  // Function to check if it's an Android device
  function isAndroid() {
   return navigator.userAgent.match(/Android/i)
  }

  // Function to check if it's an iOS device
  function isiOS() {
   return navigator.userAgent.match(/iPhone|iPad|iPod/i)
  }

  // Function to check if it's a desktop
  function isDesktop() {
   return window.innerWidth > 768 // Adjust the width threshold as needed
  }

  // Function to redirect to a website
  function redirectToWebsite() {
   window.location.href = "https://www.example.com/" // Replace with your desired URL
  }

  // Function to redirect to the Google Play Store
  function redirectToPlayStore() {
   window.location.href =
    "intent://details?id=com.example#Intent;scheme=market;package=com.example;end"
  }

  // Function to redirect to the App Store
  function redirectToAppStore() {
   window.location.href = "itms-apps://itunes.apple.com/app/appid2323" // Replace with your app's App Store URL
  }

  // Check the device type and display the appropriate message
  if (isDesktop()) {
   redirectToWebsite()
  } else if (isAndroid()) {
   document.getElementById("message").textContent =
    "We are redirecting you to the examplemobile app for Android."
   setTimeout(redirectToPlayStore, 3000) // Redirect after 3 seconds
  } else if (isiOS()) {
   document.getElementById("message").textContent = "We are redirecting you to the examplemobile app for iOS."
   setTimeout(redirectToAppStore, 3000) // Redirect after 3 seconds
  }
 </script>
</html>
Enter fullscreen mode Exit fullscreen mode

Step 4: Creating utils for the appending dynamic seo title

const path = require("path")
const fs = require("fs");

function appendSeoDetail({ title, description, image }) {
  const _title = title ?? 'POUCH - Packaging News App';
  const _subtitle = description ?? 'Pouch is a news aggregator application for the Packaging industry that summarises news articles and stories sourced from various third-party links including industry journals, expert blogs, and innovative company releases';
  const _image = image ?? 'https://www.pouch.news/cropped-pulse%201.png';

  // Load HTML template
  const templatePath = path.join(__dirname, '../index.html');

  // Replace handles with content
  var source = fs.readFileSync(templatePath, { encoding: 'utf-8' })
    .replaceAll('{{title}}', _title)
    .replaceAll('{{description}}', _subtitle)
    .replaceAll('{{image}}', _image);

  return source
}

module.exports = { appendSeoDetail }
Enter fullscreen mode Exit fullscreen mode

Step 5: Make a .well-know folder and insert files for

assetlinks.json and apple-app-site-association

{
  "applinks": {
    "details": [
      {
        "appIDs": [
          "EXDFF##.com.example"
        ],
        "paths": [
          "*"
        ]
      }
    ]
  },
  "webcredentials": {
    "apps": [
      "EXDFF##.com.example"
    ]
  }
}
[
  {
    "relation": [
      "delegate_permission/common.handle_all_urls"
    ],
    "target": {
      "namespace": "android_app",
      "package_name": "com.example",
      "sha256_cert_fingerprints": [
        "9B:83:32:66:75:91:03:3B:9C"
       ]
    }
  }
]
Enter fullscreen mode Exit fullscreen mode

Step 7: Integrating Deep Links in React Native

const linking = {
  prefixes: ["example://", "https://3a09-2402-4cc0-2501-1f4-71ad-7a58-7a4c-895c.ngrok-free.app"],
  config,
  async getInitialURL() {
   const url = await Linking.getInitialURL()

   console.log(url, "Dynamic url")

   if (typeof url === "string") {
    return url
   }
js 
  },
 }

<NavigationContainer ref={navigationRef} linking={linking}>

</NavigationContainer>
Enter fullscreen mode Exit fullscreen mode

Deep linking | React Navigation

This guide will describe how to configure your app to handle deep links on various platforms. To handle incoming links, you need to handle 2 scenarios:

favicon reactnavigation.org

Conclusion
By setting up dynamic links and deep linking in your React Native app with a Node.js backend, you can significantly enhance the user experience by providing seamless navigation and personalized content. Dynamic links offer a powerful way to ensure that users get to the right content, whether they have your app installed or not.
This setup is not just limited to Firebase. You can use other services like Branch.io or create a custom solution depending on your needs. The principles, however, remain the same: enabling users to move directly to the content they care about.
Happy coding!

Top comments (0)