App Shortcuts in React Native : Never let your app shortcuts open any random app 😂

Hey folks,

In this article we will be creating App Shortcuts for React Native apps as shown in the image. We will be creating this using the react-native-app-shortcuts library.

App Shortcuts.jpeg

First things first !!

node --version
 v16.14.1
npm --version
 8.5.0
java --version
 openjdk 11.0.11 2021-04-20

Create a New React Native App using the following commands -

npx react-native init [YOUR_PROJECT_NAME] --version 0.68.2

Note - I am using 0.68 version of React Native. If you have upgraded React Native to the latest version you can create the app using the command ->

npx react-native init [YOUR_PROJECT_NAME]

Let's install the dependencies

We will be installing navigation dependencies to support navigation between multiple screens in our app.

npm install @react-navigation/native @react-navigation/native-stack

npm install react-native-screens react-native-safe-area-context

After the navigation dependencies we will be installing react-native-app-shortcuts library in our app.

npm i react-native-app-shortcuts

Final package.json file should be similar to this ->

package.json

{
  "name": "RNAppShortcuts",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "android": "react-native run-android",
    "ios": "react-native run-ios",
    "start": "react-native start",
    "test": "jest",
    "lint": "eslint ."
  },
  "dependencies": {
    "@react-navigation/native": "^6.0.11",
    "@react-navigation/native-stack": "^6.7.0",
    "react": "17.0.2",
    "react-native": "0.68.2",
    "react-native-app-shortcuts": "^0.2.0",
    "react-native-safe-area-context": "^4.3.1",
    "react-native-screens": "^3.15.0"
  },
  "devDependencies": {
    "@babel/core": "^7.18.10",
    "@babel/runtime": "^7.18.9",
    "@react-native-community/eslint-config": "^3.1.0",
    "babel-jest": "^28.1.3",
    "eslint": "^8.21.0",
    "jest": "^28.1.3",
    "metro-react-native-babel-preset": "^0.72.0",
    "react-test-renderer": "17.0.2"
  },
  "jest": {
    "preset": "react-native"
  }
}

Let's begin the journey of Code ->

  • Remove the template code in App.js and ensure App.js looks like the following -
App.js

import React from 'react';
import {
  StyleSheet,
  Text,
  View,
} from 'react-native';

const App = () => {

  return (
    <View>

    </View>
  );
};

const styles = StyleSheet.create({

});

export default App;
  • Remove the styles constant and imports from 'react-native'
  • We will create a Navigation Container and a Stack Navigator that contains different screens for our app.
  • Import NavigationContainer and createNativeStackNavigator() from 'react-navigation/native' and 'react-navigation/native-stack' respectively.
import {NavigationContainer} from '@react-navigation/native';
import {createNativeStackNavigator} from '@react-navigation/native-stack';
  • Modify the return statement of App.js file. Return aNavigationContainer that encloses our Stack.Navigator inside which all our screens are defined along with their names and components.
return (
    <NavigationContainer>
      <Stack.Navigator>
        <Stack.Screen name="Home" component={HomeComponent} />
        <Stack.Screen name="Notification" component={NotificationComponent} />
        <Stack.Screen name="Chat" component={ChatComponent} />
      </Stack.Navigator>
    </NavigationContainer>
  );
  • Next we will be defining these components namely - HomeComponent, NotificationComponent and ChatComponent.

In the same App.js file create three constants like ->

const NotificationComponent = ({navigation}) => {
  return (
    <>
      <Notification navigation={navigation} />
    </>
  );
};

const ChatComponent = ({navigation}) => {
  return (
    <>
      <Chat navigation={navigation} />
    </>
  );
};

const HomeComponent = ({navigation}) => {
  return (
    <>
      <Home navigation={navigation} />
    </>
  );
};
  • Import the Chat, Home, Notification screens like ->
import Notification from './src/Notification';
import Chat from './src/Chat';
import Home from './src/Home';

At this stage your App.js would look like the following ->

App.js 

import React from 'react';
import {NavigationContainer} from '@react-navigation/native';
import {createNativeStackNavigator} from '@react-navigation/native-stack';
import Notification from './src/Notification';
import Chat from './src/Chat';
import Home from './src/Home';

const Stack = createNativeStackNavigator();

const NotificationComponent = ({navigation}) => {
  return (
    <>
      <Notification navigation={navigation} />
    </>
  );
};

const ChatComponent = ({navigation}) => {
  return (
    <>
      <Chat navigation={navigation} />
    </>
  );
};

const HomeComponent = ({navigation}) => {
  return (
    <>
      <Home navigation={navigation} />
    </>
  );
};

const App = () => {
  return (
    <NavigationContainer>
      <Stack.Navigator>
        <Stack.Screen name="Home" component={HomeComponent} />
        <Stack.Screen name="Notification" component={NotificationComponent} />
        <Stack.Screen name="Chat" component={ChatComponent} />
      </Stack.Navigator>
    </NavigationContainer>
  );
};

export default App;
  • At this stage it might be showing you errors that Home, Notification and Chat screens does not exists and hence they cannot be imported.

  • Let's fix this next.

  • Create a folder src at the level where App.js file is located.

  • Create 3 files inside the src folder namely -> Home.js, Notification.js and Chat.js

  • Also for icons download Notification icon and Chat icon from the respective links as .png images and add in the app project structure at the location

    android/app/src/main/res/drawable
    
  • Your folder structure for adding png files of Icons will be ->

Icon Folder Structure.png

  • Your folder structure should finally look like this ->

Folder Structure.png

Steps for creating screens Home.js, Chat.js and Notification.js

Home.js

Create a functional component named Home.js and export it as default from this file. Make Sure each of the Screen Home.js, Chat.js and Notification.js accepts notification object as props

const Home = ({navigation}) => {
  return (
  );
};

export default Home;

Create a styles constant and create homeStyle.

const styles = StyleSheet.create({
  homeStyle: {
    display: 'flex',
    flex: 1,
    justifyContent: 'center',
    alignSelf: 'center',
  },
});

homeStyle will be assigned to the single view in the Home Screen with the flex value as 1 so that it takes the entire space. justifyContent and alignSelf styles are used to align the Text component inside the View in the centre of the screen.

Inside the return method of Home functional component return View with styles as homeStyle which contains a Text Component as "Home Screen"

return (
    <View style={styles.homeStyle}>
      <Text>{'Home Screen'}</Text>
    </View>
  );

Home.js at this stage will look like ->

Home.js 

import React from 'react';
import {Text, StyleSheet, View} from 'react-native';

const Home = ({navigation}) => {
  return (
    <View style={styles.homeStyle}>
      <Text>{'Home Screen'}</Text>
    </View>
  );
};

const styles = StyleSheet.create({
  homeStyle: {
    display: 'flex',
    flex: 1,
    justifyContent: 'center',
    alignSelf: 'center',
  },
});

export default Home;

Chat.js

Similarly create a screen Chat.js with the following code ->

Chat.js 

import React from 'react';
import {StyleSheet, Text, TouchableOpacity} from 'react-native';

const Chat = ({navigation}) => {
  return (
    <TouchableOpacity
      onPress={() => {
        navigation.navigate('Notification');
      }}
      style={styles.cta1Style}>
      <Text style={styles.ctaTitleStyle}>{'Switch to Notifications'}</Text>
    </TouchableOpacity>
  );
};

const styles = StyleSheet.create({
  cta1Style: {
    backgroundColor: 'red',
    padding: 20,
  },
  ctaTitleStyle: {
    color: 'white',
  },
});

export default Chat;

Notification.js

Similarly create a screen Notification.js with the following code ->

import React from 'react';
import {StyleSheet, Text, TouchableOpacity} from 'react-native';

const Notification = ({navigation}) => {
  return (
    <TouchableOpacity
      onPress={() => {
        navigation.navigate('Chat');
      }}
      style={styles.cta2Style}>
      <Text style={styles.ctaTitleStyle}>{'Switch to Chat'}</Text>
    </TouchableOpacity>
  );
};

const styles = StyleSheet.create({
  cta2Style: {
    backgroundColor: 'blue',
    padding: 20,
  },
  ctaTitleStyle: {
    color: 'white',
  },
});

export default Notification;

And that's done... Now you might not be seeing any error if everything works perfectly...

Let's create the App Shortcuts for our app ->

  • Import RNAppShortcuts from 'react-native-app-shortcuts' in App.js file

  • Inside the App functional component before the return statement create 2 actions using RNAppShortcuts.addShortcut({})

App.js

import React from 'react';
import {NavigationContainer} from '@react-navigation/native';
import {createNativeStackNavigator} from '@react-navigation/native-stack';
import Notification from './src/Notification';
import Chat from './src/Chat';
import Home from './src/Home';
import RNAppShortcuts from 'react-native-app-shortcuts';

const Stack = createNativeStackNavigator();

const NotificationComponent = ({navigation}) => {
  return (
    <>
      <Notification navigation={navigation} />
    </>
  );
};

const ChatComponent = ({navigation}) => {
  return (
    <>
      <Chat navigation={navigation} />
    </>
  );
};

const HomeComponent = ({navigation}) => {
  return (
    <>
      <Home navigation={navigation} />
    </>
  );
};

const App = () => {
  RNAppShortcuts.addShortcut({
    id: '1',
    shortLabel: 'Notify',
    longLabel: 'Open Notifications',
    iconFolderName: 'drawable',
    iconName: 'notification',
  });
  RNAppShortcuts.addShortcut({
    id: '2',
    shortLabel: 'Chat',
    longLabel: 'Open Chats',
    iconFolderName: 'drawable',
    iconName: 'chat',
  });
  return (
    <NavigationContainer>
      <Stack.Navigator>
        <Stack.Screen name="Home" component={HomeComponent} />
        <Stack.Screen name="Notification" component={NotificationComponent} />
        <Stack.Screen name="Chat" component={ChatComponent} />
      </Stack.Navigator>
    </NavigationContainer>
  );
};

export default App;
  • Now we will create handlers which will activate when one of the app shortcut is clicked.

  • In Home.js file import useEffect from React and create a useEffect() equivalent for ComponentWillMount() of class component for Home functional component.

  • Also import RNAppShortcuts from 'react-native-app-shortcuts' for defining app shortcuts handler.

  • This useEffect will be triggered every time this screen loads or mounts. Here we will define our App Shortcuts handler.

  • App Shortcuts handler is created using

    RNAppShortcuts.handleShortcut(id => {});
    

-> At this stage Home.js should look like ->

Home.js 

import React, {useEffect} from 'react';
import {Text, StyleSheet, View} from 'react-native';
import RNAppShortcuts from 'react-native-app-shortcuts';

const Home = ({navigation}) => {
  useEffect(() => {
    RNAppShortcuts.handleShortcut(id => {
      console.log(id);
      if (id === '1') {
        navigation.navigate('Notification');
      } else if (id === '2') {
        navigation.navigate('Chat');
      }
    });
  }, []);

  return (
    <View style={styles.homeStyle}>
      <Text>{'Home Screen'}</Text>
    </View>
  );
};

const styles = StyleSheet.create({
  homeStyle: {
    display: 'flex',
    flex: 1,
    justifyContent: 'center',
    alignSelf: 'center',
  },
});

export default Home;

Important Things to Note -

  • They are multiple libraries in React Native for creating App Shortcuts.
  1. react-native-app-shortcuts

  2. react-native-quick-actions

  3. react-native-actions-shortcuts

  • Shortcuts are added using the following code which accepts parameters like id, shortLabel , longLabel, iconFolderName where the icon image is located, iconName which has some naming rules.
RNAppShortcuts.addShortcut({
    id,
    shortLabel,
    longLabel,
    iconFolderName,
    iconName,
  });
  • Icon Images should be added in native android and iOS folders at right locations.

  • We can add all shortcuts to the app in Splash Screen or we can add app shortcuts based on which part of the app, user has explored.

  • We can remove app shortcuts using RNAppShortcuts.removeShortCut(id)

  • We can remove all app shortcuts using RNAppShortcuts.removeAllShortCuts()
  • Static app shortcuts are shortcuts that are created at the app installation time.

  • react-native-quick-actions library support static app shortcuts for IOS devices.

  • App shortcuts handler can be created using RNAppShortcuts.handleShortcut(id => {});

  • The handler accepts id, using which we can perform different operations on different app shortcut click.

Voohooooooo!! We have complete the project. Cheers !!

Follow me on Twitter for more tech content on ReactNative and Flutter.

Did you find this article valuable?

Support Parjanya Aditya Shukla by becoming a sponsor. Any amount is appreciated!

Â