DEV Community

Cover image for React Native — Platform specific code
Nedim Becirovic
Nedim Becirovic

Posted on • Originally published at Medium on

React Native — Platform specific code

With React Native we are writing the code for both, iOS and Android. And it won’t pass long to notice that we need to differ one from another.

Right: Android Emulator Nexus 5 API 23 1080x1920: xxhdpi x86_64

As we can see, our Header component, that has the simple task of displaying text behaves differently on Android and iOS. Clearly, we need to have two different styles for the two. So, how can we accomplish this? Good people from the React Native team have provided us with a quite simple solution. They have offered us a module called Platform.

All we need to do is to import Platform from react-native and we are good to go. The Platform has OS property which tells us either we are running our app on iOS (ios) or Android (android). Furthermore, Platform comes with a method select which given an object with a key of Platform.OS will return the value for the platform we are running our code on.

Enough talk. Let’s see those in action.

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

export const Header = () => (
  <View style={styles.header}>
    <Text style={styles.text}>I am Header</Text>
  </View>
);

const styles = StyleSheet.create({
  header: {
    height: Platform.OS === 'android' ? 76 : 100,
    marginTop: Platform.OS === 'ios' ? 0 : 24,
    ...Platform.select({
      ios: { backgroundColor: '#f00', paddingTop: 24},
      android: { backgroundColor: '#00f'}
    }),
    alignItems: 'center',
    justifyContent: 'center'
  },
  text: {
    color: '#fff',
    fontSize: 24
  }
});

And the result of running such code:

Header after style applied

Let’s break down our code!

height: Platform.OS === 'android' ? 76 : 100,
marginTop: Platform.OS === 'ios' ? 0 : 24,

Nothing fancy here. We have already mentioned that Platform.OS returns ios or android depending on the platform it is running on. Combining that with the ternary operator gave us this nice code which helped us set height/margin of our Header. This code is equivalent to height: 76, marginTop: 24 on Android and height:100, marginTop: 0 on iOS

Moving along we have:

...Platform.select({
 ios: { backgroundColor: '#f00', paddingTop: 24},
 android: { backgroundColor: '#00f'}
 }),

As we mentioned Platform.select will return the value given the key from Platform.OS. So in our case this code becomes ...{ backgroundColor: '#f00', paddingTop: 24} for iOS, and ...{ backgroundColor: '#00f'} for Android.

So to sum it up, or styles are going to look like this:

Android:
const styles = StyleSheet.create({
 header: {
 height: 76,
 marginTop: 24,
 backgroundColor: '#00f',
 alignItems: 'center',
 justifyContent: 'center'
 },
 text: {
 color: '#fff',
 fontSize: 24
 }
});

-----------------------------------

iOS:
const styles = StyleSheet.create({
 header: {
 height: 100,
 marginTop: 0,
 backgroundColor: '#f00', 
 paddingTop: 24,
 alignItems: 'center',
 justifyContent: 'center'
 },
 text: {
 color: '#fff',
 fontSize: 24
 }
});

We have not come to an end with Platform.select. The cool thing about it is that it accepts any value, so you can use this to your advantage to return components for iOS/Android. In our case, we have created BodyAndroid.js, BodyIOS.js, and Body.js. We have replaced default text in App.js with Body component. So, our App.js look like this:

import React from 'react';
import { View} from 'react-native';
import {styles} from "./src/theme/Style";
import { Header } from './src/components/Header';
import { Body } from "./src/components/Body";

export default class App extends React.Component {
  render() {
    return (
      <View style={styles.container}>
        <Header />
        <Body />
      </View>
    );
  }
}

The rest of our code:

BodyAndroid.js
import React from 'react';
import { View, Text} from 'react-native';
import {styles} from "../theme/Style";

export const BodyAndroid = () => (
  <View style={styles.body}>
    <Text style={styles.h1}>This is Android App!</Text>
  </View>
);
--------------------------------
BodyIOS.js
import React from 'react';
import { View, Text} from 'react-native';
import {styles} from "../theme/Style";

export const BodyIOS = () => (
  <View style={styles.body}>
    <Text style={styles.h1}>This is iOS App!</Text>
  </View>
);
--------------------------------
Body.js
import { Platform } from 'react-native';

import { BodyAndroid } from './BodyAndroid';
import { BodyIOS } from './BodyIOS'

export const Body = Platform.select({
  ios: BodyIOS,
  android: BodyAndroid
});

And the result:

As good as this looks I do not consider it the best solution. There is something called Platform-specific extension which I prefer. So in the case of iOS, we want to have .ios. extension, while for Android we will have .android.. This will help React Native determine which component to use for what platform.

Let’s illustrate this with an example.

The code for our Footer is very similar to our Header, therefore, I will not be pasting it here. What is important for us to nice is this simple line import { Footer } from './src/components/Footer';. As we can notice in the components directory we do not have Footer file, but righter Footer.ios and Footer.android. React Native is smart enough to determine which one to use, depending on what platform we are building our app for.

We have seen how we can add our component using the Platform-specific extension and Platform.select method. Was it all that Platform module can do? Well, no. There is one more thing left and you might have guessed it. It is detecting the version of Android/iOS. So let’s modify our Body message by appending to it the version number.

Showing Platform version is as simple as calling Platform.Version. Well… there is a catch. While Android returns the version as an integer, iOS is not so friendly and will give us the version as a string. It should not be difficult to covert it to the integer if we need to compare it (which is the most likely scenario if we need a version number). If we just want to display it we are safe to go with what we get.

To make everything more interesting, React Native comes with build in components and APIs, some of which are Android/iOS specific. To mention few, for Android we have: DatePickerAndroid, ProgressBarAndroid, ViewPagerAndroid; as for iOS we have: AlertIOS, ImagePickerIOS, TabBarIOS. Furthermore, we can write Native modules for our Platform, but that is topic for itself.

Honorary mention goes to component parameters. Some components have Platform specific parameters which we will cover as we mention each component or set of components.

Conclusion

To Platform or not to Platform, that is the difficult question. Usage of the platform-specific code is quite simple when it comes to React Native. As we have seen we have the variety of the choices. Either to create a platform-specific component or to make modification in component by determining OS. So it is all up to us, and our case scenario.

The code used in this article can be found at :

nedimb86/RNPlatform


Top comments (0)