How to do it...

  1. Let's start by opening App.js and adding the imports we'll be using: 
import React from 'react';
import { StyleSheet, Text, View, TouchableOpacity, Platform } from 'react-native';
import { Linking } from 'react-native';
import { WebBrowser } from 'expo';
  1. Next, let's add both an App component and a state object. In this app, the state object will house all of the links that we'll be using in this recipe in an array called links. Notice how the url property in each links object has a protocol attached to it (tel, mailto, sms, and so on). These protocols are used by the device to properly handle each link:
export default class App extends React.Component {
state = {
links: [
{
title: 'Call Support',
url: 'tel:+12025550170',
type: 'phone'
},
{
title: 'Email Support',
url: 'mailto:support@email.com',
type: 'email',
},
{
title: 'Text Support',
url: 'sms:+12025550170',
type: 'text message',
},
{
title: 'Join us on Slack',
url: 'slack://channel?team=T5KFMSASF&id=C5K142J57',
type: 'slack deep link',
},
{
title: 'Visit Site (internal)',
url: 'https://google.com',
type: 'internal link'
},
{
title: 'Visit Site (external)',
url: 'https://google.com',
type: 'external link'
}
]
}

}
The phone number used in the Text Support and Call Support buttons is an unused number at the time of writing, as generated by  https://fakenumber.org/. This number is likely to still be unused, but this could possibly change. Feel free to use a different fake number for these links, just make sure to keep the protocol in place.
  1. Next, let's add the render function for our app. The JSX here is simple: we map over the state.links array from the previous step, passing each to our renderButton function defined in the next step:
  render() {
return(
<View style={styles.container}>
<View style={styles.buttonList}>
{this.state.links.map(this.renderButton)}
</View>
</View>
);
}
  1. Let's build out the renderButton method used in the last step. For each link, we create a button with TouchableOpacity and set the onPress property to execute the handleButtonPress and pass it the button property:
  renderButton = (button, index) => {
return(
<TouchableOpacity
key={index}
onPress={() => this.handleButtonPress(button)}
style={styles.button}
>
<Text style={styles.text}>{button.title}</Text>
</TouchableOpacity>
);
}
  1. Next, we can build out the handleButtonPress function. Here, we'll be using the type property that we've added to each object in the links array. If the type is 'internal link', we want to open the URL within our app using the Expo WebBrowser component's openBrowserAsync method, and for everything else, we'll use the React Native Linking component's openURL method. 
    If there's a problem with the openURL call and the URL is using the slack:// protocol, it means the device does not know how to handle the protocol, probably because the slack app isn't installed. We'll handle this problem with the handleMissingApp function, which we'll add in the next step:
  handleButtonPress(button) {
if (button.type === 'internal link') {
WebBrowser.openBrowserAsync(button.url);
} else {
Linking.openURL(button.url).catch(({ message }) => {
if (message.includes('slack://')) {
this.handleMissingApp();
}
});
}
}
  1. Now we can create our handleMissingApp function. Here, we use the React Native helper Platform, which provides information about the platform the app is running on. Platform.OS will always return the operating system, which, on phones, should always resolve to either 'ios' or 'android'. You can read more about the capabilities of Platform in the official documentation at https://facebook.github.io/react-native/docs/platform-specific-code.html.
    If the link to the Slack app does not work as expected, we'll use Linking.openURL again; this time, to open the app in the app store appropriate for the device:
  handleMissingApp() {
if (Platform.OS === 'ios') {
Linking.openURL(`https://itunes.apple.com/us/app/id618783545`);
} else {
Linking.openURL(
`https://play.google.com/store/applications/details?id=com.Slack`
);
}
}
  1. Our app doesn't have any styles yet, so let's add some. Nothing fancy here, just aligning the buttons in the center of the screen, coloring and centering text, and providing padding on each button:
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
justifyContent: 'center',
alignItems: 'center',
},
buttonList: {
flex: 1,
justifyContent: 'center',
},
button: {
margin: 10,
backgroundColor: '#c0392b',
borderRadius: 3,
padding: 10,
paddingRight: 30,
paddingLeft: 30,
},
text: {
color: '#fff',
textAlign: 'center',
},
});

  1. That's all there is to this app. Once we load the app, there should be a column of buttons representing each of our links. The Call Support and Email Support buttons will not work on the iOS simulator. Run this recipe on a real device to see all of the links working properly.: