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