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