React Native's web support continues to get better and better, especially if you're using Expo. With Expo it just works out of the box.
But adding another supported platform to your app adds complexity! You've got to make sure things work on each supported platform.
Recently I was building a game with React Native, Match the Pairs, that allows a user to share how many moves it took them to beat the game.
It runs on iOS, Android, and the web. React Native's Share
API works on iOS and Android but not the web so I had to come up with a solution to handle this.
Today we'll cover how to build a function that has differing functionality depending on what platform it runs on.
The shareGame Function
First we'll create the function that will be called when a user presses "Share game" in the app.
type shareGameProps = {
emojis: string[]
moveCount: number
}
export const shareGame = async ({ emojis, moveCount }: shareGameProps) => {}
Example input:
shareGame({
emojis: [
"๐",
"๐ฃ",
"๐ฌ",
"๐",
"๐ค ",
"๐ฆฆ",
"๐ธ",
"๐ฌ",
"๐ค ",
"๐",
"๐ฎ",
"๐ฎ",
"๐ฃ",
"๐",
"๐ฆฆ",
"๐ธ",
],
moveCount: 16,
})
The Share API
First we can take advantage of the Share
API from React Native.
import { Share } from "react-native"
type shareGameProps = {
emojis: string[]
moveCount: number
}
export const shareGame = async ({ emojis, moveCount }: shareGameProps) => {
const message = "This is an example message"
return await Share.share({
message,
})
}
On iOS and Android this works great but the web throws an error that it isn't supported.
Leveraging the Platform API
So, what can we do about this differing API support between platforms?
We can leverage the core Platform
API to change the functionality on a given platform.
import { Share, Platform } from "react-native"
import * as Clipboard from "expo-clipboard"
type shareGameProps = {
emojis: string[]
moveCount: number
}
export const shareGame = async ({ emojis, moveCount }: shareGameProps) => {
const message = "This is an example message"
if (Platform.OS === "web") {
await Clipboard.setStringAsync(message)
alert(`The following message was copied to your clipboard.\n\n${message}`)
return
}
return await Share.share({
message,
})
}
Above you can see that if the platform is "web" we'll copy the message to their clipboard (via expo-clipboard
or react-native-clipboard
).
We're also using alert
to notify the user that we copied the message to the clipboard and what the actual message was. A custom modal would be an even better solution here.
If the platform isn't "web" then we'll continue on to use the Share
API.
Bonus: Building the Share Message
This section isn't really pertinent to the content of this article but I figured I'd add it in. Let's create the actual message.
We want to create the grid of emojis that the user played, like this:
๐ ๐ฃ ๐ฌ ๐
๐ค ๐ฆฆ ๐ธ ๐ฌ
๐ค ๐ ๐ฎ ๐ฎ
๐ฃ ๐ ๐ฆฆ ๐ธ
To do so we'll split our array of emojis into 4 rows of 4 emojis and then join them with a new line character.
import { Share, Platform } from "react-native"
import * as Clipboard from "expo-clipboard"
type shareGameProps = {
emojis: string[]
moveCount: number
}
const buildRow = (emojis: string[], start: number, end: number) =>
emojis.slice(start, end).join(" ")
export const shareGame = async ({ emojis, moveCount }: shareGameProps) => {
const row1 = buildRow(emojis, 0, 4)
const row2 = buildRow(emojis, 4, 8)
const row3 = buildRow(emojis, 8, 12)
const row4 = buildRow(emojis, 12, 16)
const emojiBoard = [row1, row2, row3, row4].join("\n")
const message = `I just beat Match the pairs in ${moveCount} moves!\n${emojiBoard}`
if (Platform.OS === "web") {
await Clipboard.setStringAsync(message)
alert(`The following message was copied to your clipboard. \n\n${message}`)
return
}
return await Share.share({
message,
})
}
And there we have it! A function to share the game result that works across multiple platforms, even when the same APIs aren't supported on each platform.
Top comments (0)