| 
									
										
										
										
											2023-01-05 23:33:49 +00:00
										 |  |  | --- | 
					
						
							|  |  |  | title: React Native | 
					
						
							| 
									
										
										
										
											2023-02-28 11:40:44 +00:00
										 |  |  | pagination_prev: demos/static/index | 
					
						
							| 
									
										
										
										
											2023-01-05 23:33:49 +00:00
										 |  |  | pagination_next: demos/desktop/index | 
					
						
							|  |  |  | sidebar_position: 1 | 
					
						
							|  |  |  | sidebar_custom_props: | 
					
						
							|  |  |  |   summary: React + Native Rendering | 
					
						
							|  |  |  | --- | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-27 09:12:19 +00:00
										 |  |  | import current from '/version.js'; | 
					
						
							| 
									
										
										
										
											2023-01-05 23:33:49 +00:00
										 |  |  | import Tabs from '@theme/Tabs'; | 
					
						
							|  |  |  | import TabItem from '@theme/TabItem'; | 
					
						
							| 
									
										
										
										
											2023-05-01 01:27:02 +00:00
										 |  |  | import CodeBlock from '@theme/CodeBlock'; | 
					
						
							| 
									
										
										
										
											2023-01-05 23:33:49 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | The [NodeJS Module](/docs/getting-started/installation/nodejs) can be imported | 
					
						
							|  |  |  | from the main `App.js` entrypoint or any script in the project. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The "Complete Example" creates an app that looks like the screenshots below: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <table><thead><tr> | 
					
						
							|  |  |  |   <th><a href="#demo">iOS</a></th> | 
					
						
							|  |  |  |   <th><a href="#demo">Android</a></th> | 
					
						
							|  |  |  | </tr></thead><tbody><tr><td> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | </td><td> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | </td></tr></tbody></table> | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-24 08:50:42 +00:00
										 |  |  | ["Fetching Remote Data"](#fetching-remote-data) uses the built-in `fetch` to | 
					
						
							|  |  |  | download and parse remote workbook files. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ["Native Libraries"](#native-libraries) uses native libraries to read and write | 
					
						
							|  |  |  | files in the local device. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | :::caution | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | **Before reading this demo, follow the official React Native CLI Guide!** | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Development Environment Guide: <https://reactnative.dev/docs/environment-setup> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Follow the instructions for iOS (requires macOS) and for Android. They will | 
					
						
							|  |  |  | cover installation and system configuration. You should be able to build and run | 
					
						
							|  |  |  | a sample app in the Android and the iOS (if applicable) simulators. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ::: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ## Fetching Remote Data
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | :::info | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | React Native `0.72.0` will support binary data with `fetch`. For older versions, | 
					
						
							|  |  |  | [a native library](#native-libraries) can provide support. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ::: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | React Native 0.72.0 will support binary data with `fetch`: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							|  |  |  | /* fetch data into an ArrayBuffer */ | 
					
						
							|  |  |  | const ab = await (await fetch("https://sheetjs.com/pres.numbers")).arrayBuffer(); | 
					
						
							|  |  |  | /* parse data */ | 
					
						
							|  |  |  | const wb = XLSX.read(ab); | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ### Fetch Demo
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The following demo uses `react-native-table-component` to display the first | 
					
						
							|  |  |  | worksheet in a simple table. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | :::note | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | This demo was tested on an Intel Mac on 2023 April 24 with RN `0.72.0-rc.1`. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The iOS simulator runs iOS 16.2 on an iPhone SE (3rd generation). | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ::: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 1) Create project: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```bash | 
					
						
							|  |  |  | npx react-native init SheetJSRNFetch --version="0.72.0-rc.1" | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 2) Install shared dependencies: | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-01 01:27:02 +00:00
										 |  |  | <CodeBlock language="bash">{`\ | 
					
						
							| 
									
										
										
										
											2023-04-24 08:50:42 +00:00
										 |  |  | cd SheetJSRNFetch | 
					
						
							|  |  |  | curl -LO https://oss.sheetjs.com/assets/img/logo.png | 
					
						
							| 
									
										
										
										
											2023-05-01 01:27:02 +00:00
										 |  |  | npm i -S https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz | 
					
						
							|  |  |  | npm i -S react-native-table-component@1.2.0 @types/react-native-table-component`} | 
					
						
							|  |  |  | </CodeBlock> | 
					
						
							| 
									
										
										
										
											2023-04-24 08:50:42 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | Refresh iOS project by running `pod install` from the `ios` subfolder: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```bash | 
					
						
							|  |  |  | cd ios; pod install; cd .. | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 3) Download [`App.tsx`](pathname:///reactnative/App.tsx) and replace: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```bash | 
					
						
							|  |  |  | curl -LO https://docs.sheetjs.com/reactnative/App.tsx | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | **iOS Testing** | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Start the iOS emulator: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```bash | 
					
						
							|  |  |  | npx react-native run-ios | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | When opened, the app should look like the "Before" screenshot below.  After | 
					
						
							|  |  |  | tapping "Import data from a spreadsheet", the app should show new data: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <table><thead><tr> | 
					
						
							|  |  |  |   <th>Before</th> | 
					
						
							|  |  |  |   <th>After</th> | 
					
						
							|  |  |  | </tr></thead><tbody><tr><td> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | </td><td> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | </td></tr></tbody></table> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | **Android Testing** | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Start the Android emulator: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```bash | 
					
						
							|  |  |  | npx react-native run-android | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | :::note | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | When this demo was last tested, the simulator failed with the message | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | > Unable to load script.  Make sure you're either Running Metro ...
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The workaround is to launch Metro directly: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```bash | 
					
						
							|  |  |  | npx react-native start | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Press `a` in the terminal window and Metro will try to reload the app. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ::: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | When opened, the app should look like the "Before" screenshot below.  After | 
					
						
							|  |  |  | tapping "Import data from a spreadsheet", the app should show new data: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <table><thead><tr> | 
					
						
							|  |  |  |   <th>Before</th> | 
					
						
							|  |  |  |   <th>After</th> | 
					
						
							|  |  |  | </tr></thead><tbody><tr><td> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | </td><td> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | </td></tr></tbody></table> | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-05 23:33:49 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | ## Native Libraries
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | :::warning | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | React Native does not provide a native file picker or a method for reading and | 
					
						
							|  |  |  | writing data from documents on the devices. A third-party library must be used. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Since React Native internals change between releases, libraries may only work | 
					
						
							|  |  |  | with specific versions of React Native.  Project documentation should be | 
					
						
							|  |  |  | consulted before picking a library. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ::: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The following table lists tested file plugins.  "OS" lists tested platforms | 
					
						
							|  |  |  | ("A" for Android and "I" for iOS).  "Copy" indicates whether an explicit copy | 
					
						
							|  |  |  | is needed (file picker copies to cache directory and file plugin reads cache). | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | | File system Plugin         | File Picker Plugin             |  OS  | Copy | | 
					
						
							|  |  |  | |:---------------------------|:-------------------------------|:----:|:-----| | 
					
						
							|  |  |  | | `react-native-file-access` | `react-native-document-picker` | `AI` |      | | 
					
						
							|  |  |  | | `react-native-blob-util`   | `react-native-document-picker` | `AI` | YES  | | 
					
						
							|  |  |  | | `rn-fetch-blob`            | `react-native-document-picker` | `AI` | YES  | | 
					
						
							|  |  |  | | `react-native-fs`          | `react-native-document-picker` | `AI` | YES  | | 
					
						
							|  |  |  | | `expo-file-system`         | `expo-document-picker`         | ` I` | YES  | | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ### RN File Picker
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The following libraries have been tested: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #### `react-native-document-picker`
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <details open><summary><b>Selecting a file</b> (click to show)</summary> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | When a copy is not needed: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							|  |  |  | import { pickSingle } from 'react-native-document-picker'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const f = await pickSingle({allowMultiSelection: false, mode: "open" }); | 
					
						
							|  |  |  | const path = f.uri; // this path can be read by RN file plugins | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | When a copy is needed: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							|  |  |  | import { pickSingle } from 'react-native-document-picker'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const f = await pickSingle({allowMultiSelection: false, copyTo: "cachesDirectory", mode: "open" }); | 
					
						
							|  |  |  | const path = f.fileCopyUri; // this path can be read by RN file plugins | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | </details> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #### `expo-document-picker`
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <details><summary><b>Selecting a file</b> (click to show)</summary> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | When using `DocumentPicker.getDocumentAsync`, enable `copyToCacheDirectory`: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							|  |  |  | import * as DocumentPicker from 'expo-document-picker'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const result = await DocumentPicker.getDocumentAsync({ | 
					
						
							|  |  |  |   // highlight-next-line | 
					
						
							|  |  |  |   copyToCacheDirectory: true, | 
					
						
							|  |  |  |   type: ['application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'] | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | const path = result.uri; | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | </details> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ### RN File Plugins
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The following libraries have been tested: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #### `react-native-blob-util` and `rn-fetch-blob`
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | :::note Historical Context | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The `react-native-fetch-blob` project was archived in 2019. At the time, there | 
					
						
							|  |  |  | were a number of project forks.  The maintainers blessed the `rn-fetch-blob` | 
					
						
							|  |  |  | fork as the spiritual successor. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | `react-native-blob-util` is an active fork of `rn-fetch-blob` | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-01 01:27:02 +00:00
										 |  |  | When this demo was last tested, `rn-fetch-blob` and `react-native-blob-util` | 
					
						
							|  |  |  | both worked with the tested iOS and Android SDK versions. The APIs are identical | 
					
						
							|  |  |  | for the purposes of working with files. | 
					
						
							| 
									
										
										
										
											2023-01-05 23:33:49 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | ::: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The `ascii` type returns an array of numbers corresponding to the raw bytes. | 
					
						
							|  |  |  | A `Uint8Array` from the data is compatible with the `buffer` type. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <details open><summary><b>Reading and Writing snippets</b> (click to show)</summary> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The snippets use `rn-fetch-blob`.  To use `react-native-blob-util`, change the | 
					
						
							|  |  |  | `import` statements to load the module. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | _Reading Data_ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							|  |  |  | import * as XLSX from "xlsx"; | 
					
						
							|  |  |  | import RNFetchBlob from 'rn-fetch-blob'; // or react-native-blob-util | 
					
						
							|  |  |  | const { readFile } = RNFetchBlob.fs; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const res = await readFile(path, 'ascii'); | 
					
						
							|  |  |  | const wb = XLSX.read(new Uint8Array(res), {type:'buffer'}); | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | :::caution | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | On iOS, the URI from `react-native-document-picker` must be massaged: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							|  |  |  | import { pickSingle } from 'react-native-document-picker'; | 
					
						
							|  |  |  | import RNFetchBlob from 'rn-fetch-blob'; // or react-native-blob-util | 
					
						
							|  |  |  | const { readFile, dirs: { DocumentDir } } = RNFetchBlob.fs; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const f = await pickSingle({ | 
					
						
							|  |  |  | // highlight-start | 
					
						
							|  |  |  |   // Instruct the document picker to copy file to Documents directory | 
					
						
							|  |  |  |   copyTo: "documentDirectory", | 
					
						
							|  |  |  | // highlight-end | 
					
						
							|  |  |  |   allowMultiSelection: false, mode: "open" }); | 
					
						
							|  |  |  | // highlight-start | 
					
						
							|  |  |  | // `f.uri` is the original path and `f.fileCopyUri` is the path to the copy | 
					
						
							|  |  |  | let path = f.fileCopyUri; | 
					
						
							|  |  |  | // iOS workaround | 
					
						
							|  |  |  | if (Platform.OS === 'ios') path = path.replace(/^.*\/Documents\//, DDP + "/"); | 
					
						
							|  |  |  | // highlight-end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const res = await readFile(path, 'ascii'); | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ::: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | _Writing Data_ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							|  |  |  | import * as XLSX from "xlsx"; | 
					
						
							|  |  |  | import RNFetchBlob from 'rn-fetch-blob'; // or react-native-blob-util | 
					
						
							|  |  |  | const { writeFile, readFile, dirs:{ DocumentDir } } = RNFetchBlob.fs; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const wbout = XLSX.write(wb, {type:'buffer', bookType:"xlsx"}); | 
					
						
							|  |  |  | const file = DocumentDir + "/sheetjsw.xlsx"; | 
					
						
							|  |  |  | const res = await writeFile(file, Array.from(wbout), 'ascii'); | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | </details> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #### `react-native-file-access`
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The `base64` encoding returns strings compatible with the `base64` type: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <details open><summary><b>Reading and Writing snippets</b> (click to show)</summary> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | _Reading Data_ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							|  |  |  | import * as XLSX from "xlsx"; | 
					
						
							|  |  |  | import { FileSystem } from "react-native-file-access"; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const b64 = await FileSystem.readFile(path, "base64"); | 
					
						
							|  |  |  | /* b64 is a Base64 string */ | 
					
						
							|  |  |  | const workbook = XLSX.read(b64, {type: "base64"}); | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | _Writing Data_ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							|  |  |  | import * as XLSX from "xlsx"; | 
					
						
							|  |  |  | import { Dirs, FileSystem } from "react-native-file-access"; | 
					
						
							|  |  |  | const DDP = Dirs.DocumentDir + "/"; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const b64 = XLSX.write(workbook, {type:'base64', bookType:"xlsx"}); | 
					
						
							|  |  |  | /* b64 is a Base64 string */ | 
					
						
							|  |  |  | await FileSystem.writeFile(DDP + "sheetjs.xlsx", b64, "base64"); | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | </details> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #### `react-native-fs`
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The `ascii` encoding returns binary strings compatible with the `binary` type: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <details open><summary><b>Reading and Writing snippets</b> (click to show)</summary> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | _Reading Data_ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							|  |  |  | import * as XLSX from "xlsx"; | 
					
						
							|  |  |  | import { readFile } from "react-native-fs"; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const bstr = await readFile(path, "ascii"); | 
					
						
							|  |  |  | /* bstr is a binary string */ | 
					
						
							|  |  |  | const workbook = XLSX.read(bstr, {type: "binary"}); | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | _Writing Data_ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							|  |  |  | import * as XLSX from "xlsx"; | 
					
						
							|  |  |  | import { writeFile, DocumentDirectoryPath } from "react-native-fs"; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const bstr = XLSX.write(workbook, {type:'binary', bookType:"xlsx"}); | 
					
						
							|  |  |  | /* bstr is a binary string */ | 
					
						
							|  |  |  | await writeFile(DocumentDirectoryPath + "/sheetjs.xlsx", bstr, "ascii"); | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | </details> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #### `expo-file-system`
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | :::caution | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Some Expo APIs return URI that cannot be read with `expo-file-system`. This | 
					
						
							|  |  |  | will manifest as an error: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | > Unsupported scheme for location '...'
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The [`expo-document-picker`](#expo-document-picker) snippet makes a local copy. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ::: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The `EncodingType.Base64` encoding is compatible with `base64` type. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <details><summary><b>Reading and Writing snippets</b> (click to show)</summary> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | _Reading Data_ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Calling `FileSystem.readAsStringAsync` with `FileSystem.EncodingType.Base64` | 
					
						
							|  |  |  | encoding returns a promise resolving to a string compatible with `base64` type: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							|  |  |  | import * as XLSX from "xlsx"; | 
					
						
							|  |  |  | import * as FileSystem from 'expo-file-system'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const b64 = await FileSystem.readAsStringAsync(uri, { encoding: FileSystem.EncodingType.Base64 }); | 
					
						
							|  |  |  | const workbook = XLSX.read(b64, { type: "base64" }); | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | _Writing Data_ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The `FileSystem.EncodingType.Base64` encoding accepts Base64 strings: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							|  |  |  | import * as XLSX from "xlsx"; | 
					
						
							|  |  |  | import * as FileSystem from 'expo-file-system'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const b64 = XLSX.write(workbook, {type:'base64', bookType:"xlsx"}); | 
					
						
							|  |  |  | /* b64 is a Base64 string */ | 
					
						
							|  |  |  | await FileSystem.writeAsStringAsync(FileSystem.documentDirectory + "sheetjs.xlsx", b64, { encoding: FileSystem.EncodingType.Base64 }); | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | </details> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ## Demo
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | :::note | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-01 01:27:02 +00:00
										 |  |  | This demo was tested on an Intel Mac on 2023 April 30 with RN `0.72.0-rc.1`. | 
					
						
							| 
									
										
										
										
											2023-01-05 23:33:49 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-01 01:27:02 +00:00
										 |  |  | The iOS simulator runs iOS 16.2 on an iPhone 14. | 
					
						
							| 
									
										
										
										
											2023-01-05 23:33:49 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | The Android simulator runs Android 12 (S) Platform 31 on a Pixel 5. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ::: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | :::warning | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | There are many moving parts and pitfalls with React Native apps. It is strongly | 
					
						
							|  |  |  | recommended to follow the official React Native tutorials for iOS and Android | 
					
						
							|  |  |  | before approaching this demo.  Details like creating an Android Virtual Device | 
					
						
							|  |  |  | are not covered here. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ::: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | This example tries to separate the library-specific functions. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 1) Create project: | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-24 08:50:42 +00:00
										 |  |  | ```bash | 
					
						
							| 
									
										
										
										
											2023-05-01 01:27:02 +00:00
										 |  |  | npx react-native init SheetJSRN --version="0.72.0-rc.1" | 
					
						
							| 
									
										
										
										
											2023-01-05 23:33:49 +00:00
										 |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 2) Install shared dependencies: | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-01 01:27:02 +00:00
										 |  |  | <CodeBlock language="bash">{`\ | 
					
						
							| 
									
										
										
										
											2023-01-05 23:33:49 +00:00
										 |  |  | cd SheetJSRN | 
					
						
							|  |  |  | curl -LO https://oss.sheetjs.com/assets/img/logo.png | 
					
						
							| 
									
										
										
										
											2023-05-01 01:27:02 +00:00
										 |  |  | npm i -S https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz | 
					
						
							|  |  |  | npm i -S react-native-table-component@1.2.0 react-native-document-picker@8.2.0`} | 
					
						
							|  |  |  | </CodeBlock> | 
					
						
							| 
									
										
										
										
											2023-01-05 23:33:49 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | Refresh iOS project by running `pod install` from the `ios` subfolder: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```bash | 
					
						
							|  |  |  | cd ios | 
					
						
							|  |  |  | pod install | 
					
						
							|  |  |  | cd .. | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 3) Download [`index.js`](pathname:///mobile/index.js) and replace: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```bash | 
					
						
							|  |  |  | curl -LO https://docs.sheetjs.com/mobile/index.js | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Start the iOS emulator: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```bash | 
					
						
							|  |  |  | npx react-native run-ios | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | You should see the skeleton app: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 4) Pick a filesystem library for integration: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <Tabs> | 
					
						
							|  |  |  |   <TabItem value="RNBU" label="RNBU"> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Install `react-native-blob-util` dependency: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```bash | 
					
						
							| 
									
										
										
										
											2023-05-01 01:27:02 +00:00
										 |  |  | npm i -S react-native-blob-util@0.17.1 | 
					
						
							| 
									
										
										
										
											2023-01-05 23:33:49 +00:00
										 |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Add the highlighted lines to `index.js`: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```js title="index.js" | 
					
						
							|  |  |  | import { Table, Row, Rows, TableWrapper } from 'react-native-table-component'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // highlight-start | 
					
						
							|  |  |  | import { read, write } from 'xlsx'; | 
					
						
							|  |  |  | import { pickSingle } from 'react-native-document-picker'; | 
					
						
							|  |  |  | import { Platform } from 'react-native'; | 
					
						
							|  |  |  | import RNFetchBlob from 'react-native-blob-util'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | async function pickAndParse() { | 
					
						
							|  |  |  |   /* rn-fetch-blob / react-native-blob-util need a copy */ | 
					
						
							|  |  |  |   const f = await pickSingle({allowMultiSelection: false, copyTo: "documentDirectory", mode: "open" }); | 
					
						
							|  |  |  |   let path = f.fileCopyUri; | 
					
						
							|  |  |  |   if (Platform.OS === 'ios') path = path.replace(/^.*\/Documents\//, RNFetchBlob.fs.dirs.DocumentDir + "/"); | 
					
						
							| 
									
										
										
										
											2023-05-01 01:27:02 +00:00
										 |  |  |   const res = await (await fetch(path)).arrayBuffer(); // RN >= 0.72 | 
					
						
							|  |  |  |   // const res = await RNFetchBlob.fs.readFile(path, 'ascii'); // RN < 0.72 | 
					
						
							| 
									
										
										
										
											2023-01-05 23:33:49 +00:00
										 |  |  |   return read(new Uint8Array(res), {type: 'buffer'}); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | async function writeWorkbook(wb) { | 
					
						
							|  |  |  |   const wbout = write(wb, {type:'buffer', bookType:"xlsx"}); | 
					
						
							|  |  |  |   const file = RNFetchBlob.fs.dirs.DocumentDir + "/sheetjsw.xlsx"; | 
					
						
							|  |  |  |   await RNFetchBlob.fs.writeFile(file, Array.from(wbout), 'ascii'); | 
					
						
							|  |  |  |   return file; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | // highlight-end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const make_width = ws => { | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   </TabItem> | 
					
						
							|  |  |  |   <TabItem value="RNFA" label="RNFA"> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Install `react-native-file-access` dependency: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```bash | 
					
						
							| 
									
										
										
										
											2023-05-01 01:27:02 +00:00
										 |  |  | npm i -S react-native-file-access@2.6.0 | 
					
						
							| 
									
										
										
										
											2023-01-05 23:33:49 +00:00
										 |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Add the highlighted lines to `index.js`: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```js title="index.js" | 
					
						
							|  |  |  | import { Table, Row, Rows, TableWrapper } from 'react-native-table-component'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // highlight-start | 
					
						
							|  |  |  | import { read, write } from 'xlsx'; | 
					
						
							|  |  |  | import { pickSingle } from 'react-native-document-picker'; | 
					
						
							| 
									
										
										
										
											2023-05-01 01:27:02 +00:00
										 |  |  | import { Platform } from 'react-native'; | 
					
						
							| 
									
										
										
										
											2023-01-05 23:33:49 +00:00
										 |  |  | import { Dirs, FileSystem } from 'react-native-file-access'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | async function pickAndParse() { | 
					
						
							| 
									
										
										
										
											2023-05-01 01:27:02 +00:00
										 |  |  |   /* react-native-file-access in RN < 0.72 does not need a copy */ | 
					
						
							|  |  |  |   //const f = await pickSingle({allowMultiSelection: false, mode: "open" }); | 
					
						
							|  |  |  |   //const res = await FileSystem.readFile(f.uri, "base64"); | 
					
						
							|  |  |  |   //return read(res, {type: 'base64'}); | 
					
						
							|  |  |  |   /* react-native-file-access in RN >= 0.72 needs a copy */ | 
					
						
							|  |  |  |   const f = await pickSingle({allowMultiSelection: false, copyTo: "documentDirectory", mode: "open" }); | 
					
						
							|  |  |  |   let path = f.fileCopyUri; | 
					
						
							|  |  |  |   const res = await (await fetch(path)).arrayBuffer(); | 
					
						
							|  |  |  |   return read(new Uint8Array(res), {type: 'buffer'}); | 
					
						
							| 
									
										
										
										
											2023-01-05 23:33:49 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | async function writeWorkbook(wb) { | 
					
						
							|  |  |  |   const wbout = write(wb, {type:'base64', bookType:"xlsx"}); | 
					
						
							|  |  |  |   const file = Dirs.DocumentDir + "/sheetjsw.xlsx"; | 
					
						
							|  |  |  |   await FileSystem.writeFile(file, wbout, "base64"); | 
					
						
							|  |  |  |   return file; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | // highlight-end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const make_width = ws => { | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   </TabItem> | 
					
						
							|  |  |  |   <TabItem value="RNFB" label="RNFB"> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Install `rn-fetch-blob` dependency: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```bash | 
					
						
							| 
									
										
										
										
											2023-05-01 01:27:02 +00:00
										 |  |  | npm i -S rn-fetch-blob@0.12.0 | 
					
						
							| 
									
										
										
										
											2023-01-05 23:33:49 +00:00
										 |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Add the highlighted lines to `index.js`: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```js title="index.js" | 
					
						
							|  |  |  | import { Table, Row, Rows, TableWrapper } from 'react-native-table-component'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // highlight-start | 
					
						
							|  |  |  | import { read, write } from 'xlsx'; | 
					
						
							|  |  |  | import { pickSingle } from 'react-native-document-picker'; | 
					
						
							|  |  |  | import { Platform } from 'react-native'; | 
					
						
							|  |  |  | import RNFetchBlob from 'rn-fetch-blob'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | async function pickAndParse() { | 
					
						
							|  |  |  |   /* rn-fetch-blob / react-native-blob-util need a copy */ | 
					
						
							|  |  |  |   const f = await pickSingle({allowMultiSelection: false, copyTo: "documentDirectory", mode: "open" }); | 
					
						
							|  |  |  |   let path = f.fileCopyUri; | 
					
						
							|  |  |  |   if (Platform.OS === 'ios') path = path.replace(/^.*\/Documents\//, RNFetchBlob.fs.dirs.DocumentDir + "/"); | 
					
						
							| 
									
										
										
										
											2023-05-01 01:27:02 +00:00
										 |  |  |   const res = await (await fetch(path)).arrayBuffer(); // RN >= 0.72 | 
					
						
							|  |  |  |   // const res = await RNFetchBlob.fs.readFile(path, 'ascii'); // RN < 0.72 | 
					
						
							| 
									
										
										
										
											2023-01-05 23:33:49 +00:00
										 |  |  |   return read(new Uint8Array(res), {type: 'buffer'}); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | async function writeWorkbook(wb) { | 
					
						
							|  |  |  |   const wbout = write(wb, {type:'buffer', bookType:"xlsx"}); | 
					
						
							|  |  |  |   const file = RNFetchBlob.fs.dirs.DocumentDir + "/sheetjsw.xlsx"; | 
					
						
							|  |  |  |   await RNFetchBlob.fs.writeFile(file, Array.from(wbout), 'ascii'); | 
					
						
							|  |  |  |   return file; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | // highlight-end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const make_width = ws => { | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   </TabItem> | 
					
						
							|  |  |  |   <TabItem value="RNFS" label="RNFS"> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Install `react-native-fs` dependency: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```bash | 
					
						
							| 
									
										
										
										
											2023-05-01 01:27:02 +00:00
										 |  |  | npm i -S react-native-fs@2.20.0 | 
					
						
							| 
									
										
										
										
											2023-01-05 23:33:49 +00:00
										 |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Add the highlighted lines to `index.js`: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```js title="index.js" | 
					
						
							|  |  |  | import { Table, Row, Rows, TableWrapper } from 'react-native-table-component'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // highlight-start | 
					
						
							|  |  |  | import { read, write } from 'xlsx'; | 
					
						
							|  |  |  | import { pickSingle } from 'react-native-document-picker'; | 
					
						
							|  |  |  | import { writeFile, readFile, DocumentDirectoryPath } from 'react-native-fs'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | async function pickAndParse() { | 
					
						
							|  |  |  |   /* react-native-fs needs a copy */ | 
					
						
							|  |  |  |   const f = await pickSingle({allowMultiSelection: false, copyTo: "cachesDirectory", mode: "open" }); | 
					
						
							|  |  |  |   const bstr = await readFile(f.fileCopyUri, 'ascii'); | 
					
						
							|  |  |  |   return read(bstr, {type:'binary'}); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | async function writeWorkbook(wb) { | 
					
						
							|  |  |  |   const wbout = write(wb, {type:'binary', bookType:"xlsx"}); | 
					
						
							|  |  |  |   const file = DocumentDirectoryPath + "/sheetjsw.xlsx"; | 
					
						
							|  |  |  |   await writeFile(file, wbout, 'ascii'); | 
					
						
							|  |  |  |   return file; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | // highlight-end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const make_width = ws => { | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   </TabItem> | 
					
						
							|  |  |  |   <TabItem value="EXPO" label="EXPO"> | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-01 01:27:02 +00:00
										 |  |  | :::warning | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | At the time of testing, Expo did not support RN 0.72 .  The project should be | 
					
						
							|  |  |  | created with React Native 0.67.2: | 
					
						
							| 
									
										
										
										
											2023-01-05 23:33:49 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-01 01:27:02 +00:00
										 |  |  | ```bash | 
					
						
							|  |  |  | npx react-native init SheetJSRN --version="0.67.2" | 
					
						
							|  |  |  | ``` | 
					
						
							| 
									
										
										
										
											2023-01-05 23:33:49 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | ::: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Install `expo-file-system` and `expo-document-picker` dependencies: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```bash | 
					
						
							|  |  |  | npx install-expo-modules | 
					
						
							|  |  |  | npm i -S expo-file-system expo-document-picker | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Add the highlighted lines to `index.js`: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```js title="index.js" | 
					
						
							|  |  |  | import { Table, Row, Rows, TableWrapper } from 'react-native-table-component'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // highlight-start | 
					
						
							|  |  |  | import { read, write } from 'xlsx'; | 
					
						
							|  |  |  | import { getDocumentAsync } from 'expo-document-picker'; | 
					
						
							|  |  |  | import { documentDirectory, readAsStringAsync, writeAsStringAsync } from 'expo-file-system'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | async function pickAndParse() { | 
					
						
							|  |  |  |   const result = await getDocumentAsync({copyToCacheDirectory: true}); | 
					
						
							|  |  |  |   const path = result.uri; | 
					
						
							|  |  |  |   const res = await readAsStringAsync(path, { encoding: "base64" }); | 
					
						
							|  |  |  |   return read(res, {type: 'base64'}); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | async function writeWorkbook(wb) { | 
					
						
							|  |  |  |   const wbout = write(wb, {type:'base64', bookType:"xlsx"}); | 
					
						
							|  |  |  |   const file = documentDirectory + "sheetjsw.xlsx"; | 
					
						
							|  |  |  |   await writeAsStringAsync(file, wbout, { encoding: "base64" }); | 
					
						
							|  |  |  |   return file; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | // highlight-end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const make_width = ws => { | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   </TabItem> | 
					
						
							|  |  |  | </Tabs> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 5) Refresh the app: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```bash | 
					
						
							|  |  |  | cd ios | 
					
						
							|  |  |  | pod install | 
					
						
							|  |  |  | cd .. | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Once refreshed, the development process must be restarted: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```bash | 
					
						
							|  |  |  | npx react-native run-ios | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | **iOS Testing** | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The app can be tested with the following sequence in the simulator: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - Download <https://sheetjs.com/pres.numbers> | 
					
						
							|  |  |  | - In the simulator, click the Home icon to return to the home screen | 
					
						
							|  |  |  | - Click on the "Files" icon | 
					
						
							|  |  |  | - Click and drag `pres.numbers` from a Finder window into the simulator. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - Make sure "On My iPhone" is highlighted and select "Save" | 
					
						
							|  |  |  | - Click the Home icon again then select the `SheetJSRN` app | 
					
						
							|  |  |  | - Click "Import data" and select `pres`: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Once selected, the screen should refresh with new contents: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - Click "Export data".  You will see a popup with a location: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - Find the file and verify the contents are correct: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```bash | 
					
						
							|  |  |  | find ~/Library/Developer/CoreSimulator -name sheetjsw.xlsx | | 
					
						
							|  |  |  |   while read x; do echo "$x"; npx xlsx-cli "$x"; done | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Once testing is complete, stop the simulator and the development process. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | **Android Testing** | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | There are no Android-specific steps.  Emulator can be started with: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```bash | 
					
						
							|  |  |  | npx react-native run-android | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The app can be tested with the following sequence in the simulator: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - Download <https://sheetjs.com/pres.numbers> | 
					
						
							|  |  |  | - Click and drag `pres.numbers` from a Finder window into the simulator. | 
					
						
							|  |  |  | - Click "Import data" and select `pres.numbers`: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Once selected, the screen should refresh with new contents: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - Click "Export data".  You will see a popup with a location: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - Pull the file from the simulator and verify the contents: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```bash | 
					
						
							|  |  |  | adb exec-out run-as com.sheetjsrn cat files/sheetjsw.xlsx > /tmp/sheetjsw.xlsx | 
					
						
							|  |  |  | npx xlsx-cli /tmp/sheetjsw.xlsx | 
					
						
							|  |  |  | ``` |