Using the Platform Module in React Native
Tags: reactnative, mobile
Published: 2023-05-03 00:21:41

by [Theodore Kelechukwu Onyejiaku](https://blog.openreplay.com/authors/theodore-kelechukwu-onyejiaku)

<blockquote><em>When creating React Native apps, it may be advantageous to include platform-specific code, and this article will teach you how to use the Platform module and include iOS- or Android-specific code in your cross-platform app.</em></blockquote>


React Native’s Platform module is a module present in React Native. It offers a straightforward method for creating platform-specific code that can only be run on particular operating systems. With the help of this module, we may create code exclusive to iOS or Android, or we can create cross-platform code with platform-specific features.

The great importance of the platform module is that it promotes reusable codes as much as possible, which is the hallmark of react-native. With this module, we don’t have to worry about how to implement different visuals for our Android or iOS applications.

Below are the reasons why and when we would likely use this module.

1. Apply different styles to components depending on the platform.
2. Conditionally render components depending on the platform.
3. Execute different pieces of code depending on the platform.
4. Apply fonts or different font sizes depending on the platform.
5. Use of icons for platform-specific cases.
6. Request permissions to use APIs depending on the platform we want. 
7. Platform-specific animations.
8. Customization f keyboard functions and appearances.
9. Date and time formatting. 
10. Push notification handling and display.

There are just some use cases of the Platform module.

## Getting ready

Start by installing React Native.

```
npx create-expo-app <name_of_app>
```
Here is the link to [React Native website](https://reactnative.dev/).

> NOTE: we should have Node version 16.13.0 || >=18.0.0

Then, install the latest Expo CLI.
```
npm install -g expo-cli
```
This will install the latest [Expo CLI](https://docs.expo.dev/get-started/installation/#expo-cli).

We have to start our application by running the command below:
```
npm start
```

## Styling using the Platform Module
As stated before, we can use the Platform module to style components according to our choice and platform.
Replace the content of `App.js` with the following:
```javascript
// path: ./App.js
import { StatusBar } from "expo-status-bar";
import { Platform, StyleSheet, Text, View } from "react-native";

export default function App() {
  return (
    <View style={styles.container}>
      {Platform.OS === "ios" ? (
        <Text style={styles.text}>
          Styling Specific Platforms using the Platform Module (For iOS).
        </Text>
      ) : (
        <Text style={styles.text}>
          Styling Specific Platforms using the Platform Module (For android)
        </Text>
      )}
      <StatusBar style="auto" />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: Platform.OS === "ios" ? "grey" : "white",
    alignItems: "center",
    justifyContent: Platform.select({
      ios: "center",
      android: "flex-end",
    }),
    padding: 20,
    textAlign: "center",
  },
  text: {
    color: Platform.OS === "android" ? "black" : "white",
    fontSize: 36,
  },
});
```

In the code above, we import the Platform module in the third line. We then used the `Platform.OS` property to specify what should be displayed as texts on the screen, together with their corresponding styles. And lastly, we also used `Platform.OS` and `Platform.select` in our stylesheet. 

Summarily, we specify that for platform ios, we want the `backgroundColor` to be `grey`, the content to flex to the center, aligned to the center of the screen and the text should be `black`. And as for the Android platform, we want the text to be aligned to the `center` but justified to the end of the screen. 


![-](https://blog.openreplay.com/images/using-the-platform-module-in-react-native/images/gVzfg18.jpg)

## Using the Platform Module to select Navigations

Install the react-navigation package.

```
npm install @react-navigation/native
```
 Install dependencies required for our Expo-managed project.
 
 ```
npx expo install react-native-screens react-native-safe-area-context
 ```
 
### Installing Drawer Navigation
Now, we want to specify the type of navigation we want for the Android and iOS platforms. For Android, we want drawer navigation, and for iOS, we want bottom tab navigation.
 
This, of course, can only be possible using the Platform module. So, let us get started.

 For the drawer navigation, we need to install [@react-navigation/drawer.](https://www.npmjs.com/package/@react-navigation/drawer?activeTab=versions) 
 ```
 npm install @react-navigation/drawer
 ```
 And because we are running our project on Expo, we install the following dependencies:
 
 ```
 npx expo install react-native-gesture-handler react-native-reanimated
 ```
 Checkout [react-native-gesture-handler](https://www.npmjs.com/package/react-native-gesture-handler) and [react-native-reanimated](https://www.npmjs.com/package/react-native-reanimated) for more.
 
> NOTE: add this plugins: ['react-native-reanimated/plugin'], to the `babel.config.js` file
 
### Installing Bottom-tab Navigation
We have to install the package below:
```
npm install @react-navigation/bottom-tabs
```

You can learn more about [@react-navigation/bottom-tabs](https://reactnavigation.org/docs/bottom-tab-navigator/).

This is the time to create our screens. Create a folder called `screens`. Inside it, first create the file `Home.js` and add the following piece of code.

```javascript
// path: ./screens/Home.js
import { StyleSheet, Text, View } from 'react-native';

export default function Home() {
  return (
    <View style={styles.container}>
      <Text>This is the Home Screen</Text>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
});
```

### Creating the Screens
After this, create another file called `About.js` and add the same content as `Home.js`; the only difference is the text content.

```javascript
// path: ./screens/About.js
import { StyleSheet, Text, View } from 'react-native';

export default function About() {
  return (
    <View style={styles.container}>
      <Text>This is the About Screen</Text>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
});
```
And finally, for screens, create the screen file `History.js` and add the following content.

```javascript
// path: ./screens/History.js
import { StyleSheet, Text, View } from 'react-native';

export default function History() {
  return (
    <View style={styles.container}>
      <Text>This is the History Screen</Text>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
});
```

Please understand that the `Home.js`, `About.js`, and `History.js` are basically to show a text description of the screens along with their stylesheets.

### Creating the Navigations
For the navigations, we need the folder `navigations`. Now we go ahead and create this folder. Inside it, we need to create two files, `BottomTabNavigation.js` for the iOS display and `DrawerNavigation.js` for the Android display.

The `BottomabNavigation.js` is as follows:


```javascript
// path: ./navigations/BottomabNavigation.j
import { NavigationContainer } from "@react-navigation/native";
import { createBottomTabNavigator } from "@react-navigation/bottom-tabs";
import Home from "../screens/Home";
import About from "../screens/About";
import History from "../screens/History";

const BottomTab = createBottomTabNavigator();

export default function BottomTabNavigation() {
  return (
    <NavigationContainer>
      <BottomTab.Navigator
        useLegacyImplementation={true}
        initialRouteName="Home"
      >
        <BottomTab.Screen name="Home" component={Home} />
        <BottomTab.Screen name="About" component={About} />
        <BottomTab.Screen name="History" component={History} />
      </BottomTab.Navigator>
    </NavigationContainer>
  );
}
```

The code above imports the `NavigationContainer`, our bottom tab navigation container. It also imports the `createBottomTabNavigator()` function, which creates bottom tab navigation for us. We also import the screens we have created previously, and we then specify the name of the screens and their corresponding component screens.

Next, we have to add content to `DrawerNavigation.js`. Add the following content.

```javascript
// path: ./navigations/DrawerNavigation.js
import { NavigationContainer } from "@react-navigation/native";
import { createDrawerNavigator } from '@react-navigation/drawer';

import Home from '../screens/Home';
import About from '../screens/About';
import History from '../screens/History';

const Drawer = createDrawerNavigator();

export default function DrawerNavigation() {
    return (
        <NavigationContainer>
            <Drawer.Navigator useLegacyImplementation={true} initialRouteName="Home">
                <Drawer.Screen name="Home" component={Home} />
                <Drawer.Screen name="About" component={About} />
                <Drawer.Screen name="History" component={History} />
            </Drawer.Navigator>
        </NavigationContainer>
    )
}
```

This is similar to what we did at the `BottomTabNavigation.js`. The only difference is that this time we have to make use of the `createBottomTabNavigator()` function.

Here comes the power of the Platform module. In the `App.js` of our file, add the following:

```javascript
// path: ./App.js
import 'react-native-gesture-handler';
import { Platform } from "react-native"
import DrawerNavigation from "./navigations/DrawerNavigation";
import BottomTabNavigation from "./navigations/BottomTabNavigation";

const App = Platform.select({
  ios: () => <BottomTabNavigation />,
  android: () => <DrawerNavigation />
})
export default App;
```

In the code above, we use the platform module to select which navigation to display. Here is the demo of what our platforms will look like.
 
 
 
 ![-](https://blog.openreplay.com/images/using-the-platform-module-in-react-native/images/kU3kTNf.gif)
 Android display
  
 
![-](https://blog.openreplay.com/images/using-the-platform-module-in-react-native/images/JDlSmeu.gif)
 iOS display

<div style="background-color:#efefef; border-radius:8px; padding:10px; display:block;">
<hr/>
<h3><em>Session Replay for Developers</em></h3> 
<p><em>Uncover frustrations, understand bugs and fix slowdowns like never before with <strong><a href="https://github.com/openreplay/openreplay" target="_blank">OpenReplay</a></strong> — an open-source session replay suite for developers. It can be <strong>self-hosted</strong> in minutes, giving you complete control over your customer data.</em></p>
<img alt="OpenReplay" style="margin-top:5px; margin-bottom:5px;" width="768" height="400" src="https://raw.githubusercontent.com/openreplay/openreplay/main/static/openreplay-git-hero.svg" class="astro-UXNKDZ4E" loading="lazy" decoding="async">
<p><em>Happy debugging! <a href="https://openreplay.com" target="_blank">Try using OpenReplay today.</a></em><p>
<hr/>
</div>

## Using the Platform Module for Native Components that are not common to iOS and Android.

Now that we have looked at how to style for different platforms and select navigations for different platforms using the Platform module. Now we let us use it for Native components that are not common to iOS and Android.

### DateTimePicker

First, we start with the `DateTimePicker`. We have to use the Platform module because the displays for Android and iOS are different. For instance, the one for Android does not appear when the date or time has been selected. For this reason and more, we have to use the Platform module.

Inside our `App.js`, we have to replace the content with the following.

```javascript
// path: ./App.js
import { useState } from "react";
import {
  Platform,
  StyleSheet,
  Text,
  View,
  TouchableOpacity,
} from "react-native";
import DateTimePicker from "@react-native-community/datetimepicker";

export default function App() {
  const [date, setDate] = useState(new Date());
  const [showPicker, setShowPicker] = useState(false);

  const handlePickerChange = (event, selectedDate) => {
    setDate(selectedDate || date);
    hideDateTimePicker();
  };

  const showDateTimePicker = () => {
    setShowPicker(true);
  };

  const hideDateTimePicker = () => {
    setShowPicker(false);
  };

  return (
    <View style={styles.container}>
      {Platform.OS === "ios" ? (
        <DateTimePicker
          testID="dateTimePicker"
          value={date}
          mode="datetime" // for iOS only
          display="default"
          onChange={handlePickerChange}
        />
      ) : (
        <>
          {showPicker && (
            <DateTimePicker
              testID="dateTimePicker"
              value={date}
              mode="date" // for android only
              display="default"
              onChange={handlePickerChange}
            />
          )}
          <TouchableOpacity
            style={styles.androidPicker}
            onPress={showDateTimePicker}
          >
            <Text>{date.toLocaleString()}</Text>
          </TouchableOpacity>
        </>
      )}
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: "#fff",
    alignItems: "center",
    justifyContent: "center",
  },
  androidPicker: {
    backgroundColor: "#f1f1f1",
    padding: 10,
    borderRadius: 5,
  },
});
```

From the code above, from `line 1-10`, we import the `useState`, `Platform`, and `DateTimePicker` modules. With the `useState`, we set states `date` and `showPicker` in `lines 13 and 14`.

In `lines 16-27`, we create the function `handlePickerChange`, which is responsible for setting the date state and hiding the `DateTimePicker` module. We also create the `showDateTimePicker()`, which is responsible for displaying our picker. And lastly, the `hideDateTimePicker()` function hides the picker.

Looking at `lines 30-56`, in `line 32`, we specified the platform and the DateTimePicker to show. The first ternary value is the display for iOS. And we specify that the mode should be `datetime`, which is only specific to iOS. And for the Android display, we ensured it should display when the `showPicker` value is `true`. The reason is just as we stated earlier: the DateTimePicker for Android disappears after the date is set. And lastly, for the Android platform, we added the function `showDateTimePicker()` to `TouchableOpacity` module to show the DateTimePicker when clicked. We also used it to display the value of the date since it does not display by default on Android.

And lastly, we create our styles in `lines 62-74`.

See the demo below. On the left is the Android platform, and on the right is the iOS platform.


![-](https://blog.openreplay.com/images/using-the-platform-module-in-react-native/images/4IvvTPR.gif)


### DrawerLayoutAndroid

The `DrawerLayoutAndroid` does not have an iOS alternative; for this, we will have to install `react-native-drawer-layout.`Check out [react-native-drawer-layout](https://www.npmjs.com/package/react-native-drawer-layout) for more information.

To install this, run the command below:

```
npm install react-native-drawer-layout
```

After that, we will need to install the following: 
```
npx expo install react-native-gesture-handler react-native-reanimated
```

Finally, we add the `react-native-reanimated` plugin to 
our `babel.config.js` file.
```javascript
module.exports = function (api) {
  api.cache(true);
  return {
    presets: ['babel-preset-expo'],
    plugins: ['react-native-reanimated/plugin']
  };
};
```
And we add `import react-native-gesture-handler` at our entry file, which is the `App.js`.

Here is our code: 

```javascript
// path: ./App.js
import "react-native-gesture-handler";
import React, { useRef, useState } from "react";
import {
  Button,
  DrawerLayoutAndroid,
  Text,
  StyleSheet,
  View,
  Platform,
} from "react-native";
import { Drawer } from "react-native-drawer-layout";

const App = () => {
  const [open, setOpen] = React.useState(false);

  // create a navigation view for Android
  const navigationView = () => (
    <View style={styles.container}>
      <Text>I'm the Drawer!</Text>
    </View>
  );

  return (
    <>
      {/* Select for os */}
      {Platform.OS === "ios" ? (
        <Drawer
          open={open}
          onOpen={() => setOpen(true)}
          onClose={() => setOpen(false)}
          renderDrawerContent={() => {
            return (
              <View style={styles.container}>
                <Text>I'm the Drawer!</Text>
              </View>
            );
          }}
        >
          <View style={styles.container}>
            <Text>Swipe from the left (Drawerlayout for iOS)</Text>
          </View>
        </Drawer>
      ) : (
        <DrawerLayoutAndroid
          drawerWidth={300}
          renderNavigationView={navigationView}
        >
          <View style={styles.container}>
            <Text style={styles.paragraph}>
              Swipe from the left (Drawerlayout for Android)
            </Text>
          </View>
        </DrawerLayoutAndroid>
      )}
    </>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: "center",
    justifyContent: "center",
    padding: 16,
  },
  paragraph: {
    padding: 16,
    fontSize: 15,
    textAlign: "center",
  },
});

export default App;
```

* lines 2-12:  we import some modules, among which are the `Drawer`, `DrawerLayoutAndroid`, `Platform` modules, and the `useState` hook.
* line 15: we create a state variable `open` for when our drawer should close or open for the iOS platform.
* lines 18-22: the navigation for Android view is created. This will be displayed when the drawer opens.
* line 27: we used the Platform module to specify the platforms Android and iOS.
* lines 28-38: the Drawer of iOS is created. We specify the `open` state variable, the `onClose()` and `onOpen()` functions. And as well as the `renderDrawerContent()` function, which, as the name implies, renders the view for the iOS drawer.
* lines 45-54: we specify the drawer for Android. We pass the props `drawerWidth`, which specifies the width of our drawer. `renderNavigationView()` function, which displays the navigation view of the drawer when it opens. 
* lines 60-72: we style the components.
* lines 74: we export our app.



Below is the demo of the drawers in the Android and iOS platforms. On the left is Android, and on the right is iOS. 

NOTE: by default, they slide from the left.

![-](https://blog.openreplay.com/images/using-the-platform-module-in-react-native/images/VIIXBDR.gif)

### Switch

One difference when it comes to using `Switch` for Android and iOS is the `ios_backgroundColor` property. It is only specific to iOS. For this reason, the Platform module is required.

```javascript
// path: ./App.js
import React, { useState } from 'react';
import { View, Switch, Platform, StyleSheet } from 'react-native';

export default function App() {
  const [isEnabled, setIsEnabled] = useState(false);

  const toggleSwitch = () => {
    setIsEnabled(previousState => !previousState);
  };

  return (
    <View style={styles.container}>
      {Platform.OS === 'ios' ?
        <Switch
          trackColor={{ false: 'orange', true: 'green' }}
          thumbColor={isEnabled ? '#f5dd4b' : '#f4f3f4'}
          ios_backgroundColor="red" // only available for ios and not for android
          onValueChange={toggleSwitch}
          value={isEnabled}
        />
        :
        <View style={styles.container}>
          <Switch
            trackColor={{ false: 'red', true: 'green' }}
            thumbColor={isEnabled ? '#f5dd4b' : '#f4f3f4'}
            onValueChange={toggleSwitch}
            value={isEnabled}
          />
        </View>
      }
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: "center",
    alignItems: 'center'
  }
})
```

In the code above: 

* lines 1-2: we import the `useState` hook, `Switch`, and `Platform` modules.
* line 7: we create a state variable `isEnabled`, which determines if a switch is enabled or not.
* line 8: `toggleSwitch()` function is created, which will help us toggle the switch back and forth.
* lines 16-22: we specify the value for the `Switch` display for iOS. The props `trackColor` is set to orange when it is false and green when it is true; that is disabled and enabled. We also set the `thumbColor` for when it is enabled and disabled. And the `toggleSwitch()` function is called when we change the value of the switch. And lastly, we pass the value of the switch. Note that we passed the `ios_backgroundColor`, which is only specific to iOS, as red.
* lines 24-31: we specify the same for the Android display just as we did above. The difference is that we did not specify `ios_backgroundColor`, and we made the track color red when it is false; this is to make its background look red.
 

Below is what our code will look like in Android and iOS.

![-](https://blog.openreplay.com/images/using-the-platform-module-in-react-native/images/qpGNCpS.gif)

### StatusBar
The `StatusBar` is responsible for what we see at the top of our screen.
For the `StatusBar` module, we need to specify for Android or iOS when we want to disable or enable `networkActivityIndicatorVisible`, which is specific to iOS. We also need it when we want to specify the value for the `StatusBar` background color, which is specific to Android.


In the `App.js` file, replace the code with this:

```javascript
// path: ./App.js
import React from "react";
import { Platform, StatusBar, View, Text } from "react-native";

export default function App() {
  const isIOS = Platform.OS === "ios";

  return (
    <View style={{ flex: 1 }}>
      {isIOS && (
        <StatusBar
          barStyle="dark-content"
          networkActivityIndicatorVisible={true}
        />
      )}
      {!isIOS && <StatusBar barStyle="light-content" backgroundColor="red" />}
      <View
        style={{
          flex: 1,
          backgroundColor: "#FFFFFF",
          justifyContent: "center",
          alignItems: "center",
        }}
      >
        <Text>This is about Status Bar. Check the top of the screen.</Text>
      </View>
    </View>
  );
}
```

From the code above, we used the `Platform` module to specify `networkActivityIndicatorVisible` to true for the iOS platform and a `backgroundColor` of red for the Android platform. 

See the display below:


![-](https://blog.openreplay.com/images/using-the-platform-module-in-react-native/images/sD4cYJS.jpg)


### Activity Indicator

The activity indicator, as the name suggests, displays an indicator to show an ongoing activity. 

For the `activityIndicator`, when specifying the different platforms, the `size` property differs. The iOS platform uses large or small, but the Android platform uses numbers. See the code below.

```javascript
// path: ./App.js
import { StatusBar } from "expo-status-bar";
import {
  StyleSheet,
  Text,
  View,
  ActivityIndicator,
  Platform,
} from "react-native";

export default function App() {
  return (
    <View style={styles.container}>
      <Text>
        iOS Activity Indicator using size as{" "}
        {Platform.select({
          android: "50",
          ios: "large",
        })}{" "}
      </Text>
      <ActivityIndicator
        size={Platform.OS === "android" ? 50 : "large"}
        animating={true}
        color="blue"
      />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: "#fff",
    alignItems: "center",
    justifyContent: "center",
  },
});
```
In the code above, we used the `Platform.select` to specify the display text for Android and iOS. And with the `Platform.OS`, we specified the size for Android as 50  and for iOS as "large".



Here is a preview of our activity indicator.

![-](https://blog.openreplay.com/images/using-the-platform-module-in-react-native/images/g1lXVAT.gif)


### WebView
Because the WebView is deprecated, we need to install the `react-native-webview` from the react native community. Find out more about [react-native-webview](https://www.npmjs.com/package/react-native-webview). It still has the same props as the latter. 

One of the reasons to use the Platform module here is that there are some props that are platform specific. For instance, the `cacheEnabled` is available on iOS. The `geoLocationEnabled` and `scalesPageToFit` are specific to the Android platform.

Run the command below to install this package:
```
npm i react-native-webview
```


After that is done, replace the content of `App.js` with the code below.

```javascript
// path: ./App.js
import { StyleSheet, Platform } from "react-native";
import { WebView } from "react-native-webview";

export default function App() {
  return Platform.OS === "ios" ? (
    <WebView
      source={{ uri: "https://blog.openreplay.com/" }}
      cacheEnabled={true}
    />
  ) : (
    <WebView
      source={{ uri: "https://blog.openreplay.com/" }}
      geolocationEnabled={true}
      scalesPageToFit={true}
      domStorageEnabled={true}
    />
  );
}
```

In the code above, using the `Platform` module we specified the `cacheEnabled` to true for the iOS platform. And then `geoLocationEnabled` and `scalesPageToFit` for the Android platform and true.

Here is the preview below:

![-](https://blog.openreplay.com/images/using-the-platform-module-in-react-native/images/Tkrwh1N.jpg)


## Conclusion
In this article, we have looked at the Platform module and why it is useful. We also looked at how to use it on different components and modules that are not specific to iOS and Android.