1--- 2title: Handle platform differences 3--- 4 5import { SnackInline, Terminal } from '~/ui/components/Snippet'; 6import Video from '~/components/plugins/Video'; 7import { A } from '~/ui/components/Text'; 8import { Step } from '~/ui/components/Step'; 9 10Android, iOS, and the web have different capabilities. In our case, Android and iOS both are able to capture a screenshot with the `react-native-view-shot` library, however web browsers cannot. 11 12In this chapter, let's learn how to make an exception for web browsers to get the same functionality on all platforms. 13 14<Step label="1"> 15 16## Install and import dom-to-image 17 18To capture a screenshot on the web and save it as an image , we'll use a third-party library called [dom-to-image](https://github.com/tsayen/dom-to-image#readme). 19It allows taking a screenshot of any DOM node and turning it into a vector (SVG) or raster (PNG or JPEG) image. 20 21Stop the development server and run the following command to install the library: 22 23<Terminal cmd={['$ npm install dom-to-image']} /> 24 25After installing it, make sure to restart the development server and press <kbd>w</kbd> in the terminal. 26 27To use it, let's import it into **App.js**: 28 29```jsx App.js 30import domtoimage from 'dom-to-image'; 31``` 32 33</Step> 34 35<Step label="2"> 36 37## Add platform-specific code 38 39React Native provides a `Platform` module that gives us access to information about the platform on which the app is currently running. 40You can use it to implement platform-specific behavior. 41 42Import the `Platform` module in **App.js**: 43 44{/* prettier-ignore */} 45```jsx App.js 46import { StyleSheet, View, /* @info Import the Platform module from react-native. */ Platform /* @end */ } from 'react-native'; 47``` 48 49Inside the `onSaveImageAsync()` function in the `<App>` component, we'll use `Platform.OS` to check whether the platform is `'web'`. 50If it is not `'web'`, we'll run the logic added previously to take and save the screenshot. If it is `'web'`, 51we'll use the `domtoimage.toJpeg()` method to convert and capture the current `<View>` as a JPEG image. 52 53<SnackInline 54label="Take a screenshot" 55templateId="tutorial/08-run-on-web/App" 56dependencies={['expo-image-picker', '@expo/vector-icons/FontAwesome', '@expo/vector-icons', 'expo-status-bar', '@expo/vector-icons/MaterialIcons', 'react-native-gesture-handler', 'react-native-reanimated', 'react-native-view-shot', 'expo-media-library', '[email protected]']} 57files={{ 58 'assets/images/background-image.png': 'https://snack-code-uploads.s3.us-west-1.amazonaws.com/~asset/503001f14bb7b8fe48a4e318ad07e910', 59 'assets/images/emoji1.png': 'https://snack-code-uploads.s3.us-west-1.amazonaws.com/~asset/be9751678c0b3f9c6bf55f60de815d30', 60 'assets/images/emoji2.png': 'https://snack-code-uploads.s3.us-west-1.amazonaws.com/~asset/7c0d14b79e134d528c5e0801699d6ccf', 61 'assets/images/emoji3.png': 'https://snack-code-uploads.s3.us-west-1.amazonaws.com/~asset/d713e2de164764c2ab3db0ab4e40c577', 62 'assets/images/emoji4.png': 'https://snack-code-uploads.s3.us-west-1.amazonaws.com/~asset/ac2163b98a973cb50bfb716cc4438f9a', 63 'assets/images/emoji5.png': 'https://snack-code-uploads.s3.us-west-1.amazonaws.com/~asset/9cc0e2ff664bae3af766b9750331c3ad', 64 'assets/images/emoji6.png': 'https://snack-code-uploads.s3.us-west-1.amazonaws.com/~asset/ce614cf0928157b3f7daa3cb8e7bd486', 65 'components/ImageViewer.js': 'tutorial/02-image-picker/ImageViewer.js', 66 'components/Button.js': 'tutorial/03-button-options/Button.js', 67 'components/CircleButton.js': 'tutorial/03-button-options/CircleButton.js', 68 'components/IconButton.js': 'tutorial/03-button-options/IconButton.js', 69 'components/EmojiPicker.js': 'tutorial/04-modal/EmojiPicker.js', 70 'components/EmojiList.js': 'tutorial/05-emoji-list/EmojiList.js', 71 'components/EmojiSticker.js': 'tutorial/06-gestures/CompleteEmojiSticker.js', 72}}> 73 74{/* prettier-ignore */} 75```jsx 76const onSaveImageAsync = async () => { 77 /* @info Add the if condition here to check whether the current platform is web or not. */ if (Platform.OS !== 'web') { /* @end */ 78 try { 79 const localUri = await captureRef(imageRef, { 80 height: 440, 81 quality: 1, 82 }); 83 await MediaLibrary.saveToLibraryAsync(localUri); 84 if (localUri) { 85 alert('Saved!'); 86 } 87 } catch (e) { 88 console.log(e); 89 } 90 } /* @info Add an else condition to run the logic when the current platform is the web. */else { 91 domtoimage 92 .toJpeg(imageRef.current, { 93 quality: 0.95, 94 width: 320, 95 height: 440, 96 }) 97 .then(dataUrl => { 98 let link = document.createElement('a'); 99 link.download = 'sticker-smash.jpeg'; 100 link.href = dataUrl; 101 link.click(); 102 }) 103 .catch(e => { 104 console.log(e); 105 }); 106 } /* @end */ 107}; 108``` 109 110</SnackInline> 111 112On running the app in a web browser, we can now save a screenshot: 113 114<Video file="tutorial/web.mp4" /> 115 116</Step> 117 118## Next steps 119 120The app does everything we set out for it to do, so it's time to shift our focus towards the purely aesthetic. 121In the next chapter, we will [customize the app's status bar, splash screen, and app icon](/tutorial/configuration). 122