docs.sheetjs.com/docz/docs/03-demos/17-mobile/05-capacitor.md

495 lines
13 KiB
Markdown
Raw Permalink Normal View History

2023-01-05 23:33:49 +00:00
---
2024-06-03 03:25:20 +00:00
title: Storing Sheets with CapacitorJS
sidebar_label: CapacitorJS
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: 5
sidebar_custom_props:
summary: JS + Web View
---
2023-04-27 09:12:19 +00:00
import current from '/version.js';
2023-05-07 13:58:36 +00:00
import CodeBlock from '@theme/CodeBlock';
2023-04-27 09:12:19 +00:00
2024-06-03 03:25:20 +00:00
[CapacitorJS](https://capacitorjs.com/) is a mobile app runtime for building iOS
and Android apps.
[SheetJS](https://sheetjs.com) is a JavaScript library for reading and writing
data from spreadsheets.
This demo uses CapacitorJS and SheetJS to process data and export spreadsheets.
We'll explore how to load SheetJS in an CapacitorJS app and use APIs and plugins
to extract data from, and write data to, spreadsheet files on the device.
2023-01-05 23:33:49 +00:00
2024-06-03 03:25:20 +00:00
The ["Demo"](#demo) creates an app that looks like the screenshots below:
2023-01-05 23:33:49 +00:00
2023-04-01 20:13:16 +00:00
<table><thead><tr>
<th><a href="#demo">iOS</a></th>
<th><a href="#demo">Android</a></th>
</tr></thead><tbody><tr><td>
2023-01-05 23:33:49 +00:00
2023-04-01 20:13:16 +00:00
![iOS screenshot](pathname:///cap/ios.png)
2023-01-05 23:33:49 +00:00
2023-04-01 20:13:16 +00:00
</td><td>
![Android screenshot](pathname:///cap/and.png)
</td></tr></tbody></table>
2023-01-05 23:33:49 +00:00
2023-12-05 03:46:54 +00:00
:::note Tested Deployments
This demo was tested in the following environments:
2024-06-03 03:25:20 +00:00
**Real Devices**
| OS | Device | CapacitorJS + FS | Date |
|:-----------|:--------------------|:------------------|:-----------|
| Android 30 | NVIDIA Shield | `6.0.0` / `6.0.0` | 2024-06-02 |
| iOS 15.1 | iPad Pro | `6.0.0` / `6.0.0` | 2024-06-02 |
2024-04-30 04:29:40 +00:00
**Simulators**
| OS | Device | CapacitorJS + FS | Dev Platform | Date |
|:-----------|:--------------------|:------------------|:-------------|:-----------|
2024-06-03 03:25:20 +00:00
| Android 34 | Pixel 3a | `6.0.0` / `6.0.0` | `darwin-x64` | 2024-06-02 |
| iOS 17.5 | iPhone 15 Pro Max | `6.0.0` / `6.0.0` | `darwin-x64` | 2024-06-02 |
| Android 34 | Pixel 3a | `6.0.0` / `6.0.0` | `darwin-arm` | 2024-06-02 |
| iOS 17.5 | iPhone 15 Pro Max | `6.0.0` / `6.0.0` | `darwin-arm` | 2024-06-02 |
2024-05-28 05:20:05 +00:00
| Android 34 | Pixel 3a | `6.0.0` / `6.0.0` | `win10-x64` | 2024-05-28 |
2024-04-30 04:29:40 +00:00
2023-12-05 03:46:54 +00:00
:::
:::danger Telemetry
2023-01-05 23:33:49 +00:00
Before starting this demo, manually disable telemetry. On Linux and MacOS:
```bash
npx @capacitor/cli telemetry off
```
To verify telemetry was disabled:
```bash
npx @capacitor/cli telemetry
```
:::
2023-04-01 20:13:16 +00:00
## Integration Details
2023-01-05 23:33:49 +00:00
2024-06-03 03:25:20 +00:00
The [SheetJS NodeJS Module](/docs/getting-started/installation/nodejs) can be
imported from any component or script in the app.
This demo uses [SvelteJS](/docs/demos/frontend/svelte), but the same principles
apply to other frameworks.
2023-01-05 23:33:49 +00:00
#### Reading data
2024-06-03 03:25:20 +00:00
The standard [HTML5 File Input](/docs/demos/local/file#file-api) API works as
expected in CapacitorJS.
Apps will typically include an `input type="file"` element. When the element is
activated, CapacitorJS will show a file picker. After the user selects a file,
the element will receive a `change` event.
The following example parses the selected file using the SheetJS `read`[^1]
method, generates a HTML table from the first sheet using `sheet_to_html`[^2],
and displays the table by setting the `innerHTML` attribute of a `div` element:
2023-01-05 23:33:49 +00:00
2024-06-03 03:25:20 +00:00
```html title="Sample component for data import"
2023-01-05 23:33:49 +00:00
<script>
import { read, utils } from 'xlsx';
let html = "";
/* show file picker, read file, load table */
async function importFile(evt) {
// highlight-start
const f = evt.target.files[0];
const wb = read(await f.arrayBuffer());
// highlight-end
const ws = wb.Sheets[wb.SheetNames[0]]; // get the first worksheet
html = utils.sheet_to_html(ws); // generate HTML and update state
}
</script>
<main>
<!-- highlight-next-line -->
<input type="file" on:change={importFile}/>
<div bind:this={tbl}>{@html html}</div>
</main>
```
#### Writing data
2024-06-03 03:25:20 +00:00
Starting from a SheetJS workbook object[^3], the `write` method with the option
`type: "base64"`[^4] will generate Base64-encoded files.
2023-01-05 23:33:49 +00:00
2024-06-03 03:25:20 +00:00
The `@capacitor/filesystem` plugin can write Base64 strings to the device.
The following example uses the SheetJS `table_to_book` method[^5] to create a
workbook object from a HTML table. The workbook object is exported to the XLSX
format and written to the device.
```html title="Sample component for data export"
2023-01-05 23:33:49 +00:00
<script>
import { Filesystem, Directory } from '@capacitor/filesystem';
2024-06-03 03:25:20 +00:00
import { utils, write } from 'xlsx';
2023-01-05 23:33:49 +00:00
let html = "";
let tbl;
/* get state data and export to XLSX */
async function exportFile() {
2024-06-03 03:25:20 +00:00
/* generate workbook object from HTML table */
2023-01-05 23:33:49 +00:00
const elt = tbl.getElementsByTagName("TABLE")[0];
const wb = utils.table_to_book(elt);
2024-06-03 03:25:20 +00:00
2023-01-05 23:33:49 +00:00
// highlight-start
2024-06-03 03:25:20 +00:00
/* export to XLSX encoded in a Base64 string */
const data = write(wb, { bookType: "xlsx", type: "base64" });
/* attempt to write to the device */
2023-01-05 23:33:49 +00:00
await Filesystem.writeFile({
data,
path: "SheetJSCap.xlsx",
directory: Directory.Documents
2024-06-03 03:25:20 +00:00
});
2023-01-05 23:33:49 +00:00
// highlight-end
}
</script>
<main>
<button on:click={exportFile}>Export XLSX</button>
<div bind:this={tbl}>{@html html}</div>
</main>
```
2024-06-03 03:25:20 +00:00
:::caution pass
`Filesystem.writeFile` cannot overwrite existing files. Production apps should
attempt to delete the file before writing:
```js
/* attempt to delete file first */
try {
await Filesystem.deleteFile({
path: "SheetJSCap.xlsx",
directory: Directory.Documents
});
} catch(e) {}
/* attempt to write to the device */
await Filesystem.writeFile({
data,
path: "SheetJSCap.xlsx",
directory: Directory.Documents
});
```
:::
2023-04-01 20:13:16 +00:00
## Demo
2024-06-03 03:25:20 +00:00
The app in this demo will display data in a table.
When the app is launched, a [test file](https://docs.sheetjs.com/pres.numbers)
will be fetched and processed.
When a document is selected with the file picker, it will be processed and the
table will refresh to show the contents.
"Export XLSX" will attempt to export the table data to `SheetJSCap.xlsx` in the
app Documents folder. An alert will display the location of the file.
2023-04-01 20:13:16 +00:00
### Base Project
2023-01-05 23:33:49 +00:00
2024-06-03 03:25:20 +00:00
0) Follow the official "Environment Setup"[^6] instructions to set up Android
2023-09-05 18:04:23 +00:00
and iOS targets
:::caution pass
iOS development is only supported on macOS.
:::
<details>
<summary><b>Installation Notes</b> (click to show)</summary>
2023-09-05 18:04:23 +00:00
CapacitorJS requires Java 17.
</details>
2023-04-01 20:13:16 +00:00
1) Disable telemetry.
```bash
npx @capacitor/cli telemetry off
```
Verify that telemetry is disabled by running
```bash
npx @capacitor/cli telemetry
```
2023-01-05 23:33:49 +00:00
2023-04-01 20:13:16 +00:00
(it should print `Telemetry is off`)
2023-01-05 23:33:49 +00:00
2023-04-01 20:13:16 +00:00
2) Create a new Svelte project:
2023-01-05 23:33:49 +00:00
```bash
npm create vite@latest sheetjs-cap -- --template svelte
cd sheetjs-cap
```
2023-04-01 20:13:16 +00:00
3) Install dependencies:
2023-01-05 23:33:49 +00:00
2023-05-07 13:58:36 +00:00
<CodeBlock language="bash">{`\
2023-04-27 09:12:19 +00:00
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz
npm i --save @capacitor/core @capacitor/cli @capacitor/filesystem`}
2023-05-07 13:58:36 +00:00
</CodeBlock>
2023-01-05 23:33:49 +00:00
2023-04-01 20:13:16 +00:00
4) Create CapacitorJS structure:
2023-01-05 23:33:49 +00:00
```bash
npx cap init sheetjs-cap com.sheetjs.cap --web-dir=dist
2023-04-01 20:13:16 +00:00
npm run build
```
2024-01-03 06:47:00 +00:00
:::note pass
2023-12-05 03:46:54 +00:00
2024-06-03 03:25:20 +00:00
If prompted to create an Ionic account, type `N` and press <kbd>Enter</kbd>.
2023-12-05 03:46:54 +00:00
:::
2023-04-01 20:13:16 +00:00
5) Download [`src/App.svelte`](pathname:///cap/App.svelte) and replace:
```bash
curl -o src/App.svelte -L https://docs.sheetjs.com/cap/App.svelte
```
2023-09-05 18:04:23 +00:00
### Android
2023-04-01 20:13:16 +00:00
2023-09-05 18:04:23 +00:00
6) Create Android app
2023-04-01 20:13:16 +00:00
```bash
2023-09-05 18:04:23 +00:00
npm i --save @capacitor/android
npx cap add android
2023-01-05 23:33:49 +00:00
```
2023-09-05 18:04:23 +00:00
7) Enable file reading and writing in the Android app.
2023-12-05 03:46:54 +00:00
Add the highlighted lines to `android/app/src/main/AndroidManifest.xml` after
the `Permissions` comment:
2023-09-05 18:04:23 +00:00
```xml title="android/app/src/main/AndroidManifest.xml (add to file)"
<!-- Permissions -->
2023-04-01 20:13:16 +00:00
<!-- highlight-start -->
2023-09-05 18:04:23 +00:00
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
2023-09-11 04:44:15 +00:00
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
2023-04-01 20:13:16 +00:00
<!-- highlight-end -->
2023-01-05 23:33:49 +00:00
2023-09-05 18:04:23 +00:00
<uses-permission android:name="android.permission.INTERNET" />
```
2023-01-05 23:33:49 +00:00
2024-05-28 05:20:05 +00:00
8) Run the app in the simulator:
2023-01-05 23:33:49 +00:00
2023-04-01 20:13:16 +00:00
```bash
npm run build
npx cap sync
2023-09-05 18:04:23 +00:00
npx cap run android
2023-04-01 20:13:16 +00:00
```
2023-01-05 23:33:49 +00:00
2024-05-28 05:20:05 +00:00
The app should look like the screenshot at the top of the page.
2023-01-05 23:33:49 +00:00
2024-05-28 05:20:05 +00:00
9) Test the export functionality.
2023-01-05 23:33:49 +00:00
2024-05-28 05:20:05 +00:00
Touch "Export XLSX" and the emulator will ask for permission. Tap "Allow" and a
popup will be displayed with a path.
2023-04-01 20:13:16 +00:00
2024-05-28 05:20:05 +00:00
Open the "Files" app in the simulator, tap the `≡` icon and tap "Documents". Tap
the "Documents" folder to find `SheetJSCap.xlsx`.
2023-04-01 20:13:16 +00:00
2024-05-28 05:20:05 +00:00
<details open>
<summary><b>Downloading the generated file</b> (click to hide)</summary>
`adb` must be run from the root user:
```bash
adb root
```
The file location can be found by searching for `SheetJSCap.xlsx`:
```bash
adb exec-out find / -name SheetJSCap.xlsx
```
The first line of the output starting with `/` is the desired path:
```text
find: /proc/8533/task/8533/exe: No such file or directory
find: /proc/8533/exe: No such file or directory
// highlight-next-line
/data/media/0/Documents/SheetJSCap.xlsx
/storage/emulated/0/Documents/SheetJSCap.xlsx
```
`adb pull` can download the file:
```bash
adb pull "/data/media/0/Documents/SheetJSCap.xlsx" SheetJSCap.xlsx
```
`SheetJSCap.xlsx` can be opened with a spreadsheet editor such as Excel.
</details>
2023-04-01 20:13:16 +00:00
2024-06-03 03:25:20 +00:00
10) Test the import functionality.
Create a spreadsheet or find an existing file. Click and drag the file into the
Android emulator window. The file will be uploaded to a Downloads folder in the
emulator.
Tap on "Choose File" in the app. In the selector, tap `≡` and select "Downloads"
to find the uploaded file. After selecting the file, the table will refresh.
2023-09-05 18:04:23 +00:00
### iOS
2023-04-01 20:13:16 +00:00
2024-06-03 03:25:20 +00:00
11) Create iOS app
2023-04-01 20:13:16 +00:00
```bash
2023-09-05 18:04:23 +00:00
npm i --save @capacitor/ios
npx cap add ios
2023-01-05 23:33:49 +00:00
```
2024-06-03 03:25:20 +00:00
12) Enable file sharing and make the documents folder visible in the iOS app.
2023-09-05 18:04:23 +00:00
The following lines must be added to `ios/App/App/Info.plist`:
2023-04-01 20:13:16 +00:00
2023-09-05 18:04:23 +00:00
```xml title="ios/App/App/Info.plist (add to file)"
<plist version="1.0">
<dict>
2023-04-01 20:13:16 +00:00
<!-- highlight-start -->
2023-09-05 18:04:23 +00:00
<key>UIFileSharingEnabled</key>
<true/>
<key>LSSupportsOpeningDocumentsInPlace</key>
<true/>
2023-04-01 20:13:16 +00:00
<!-- highlight-end -->
2023-09-05 18:04:23 +00:00
<key>CFBundleDevelopmentRegion</key>
2023-04-01 20:13:16 +00:00
```
2023-09-05 18:04:23 +00:00
(The root element of the document is `plist` and it contains one `dict` child)
2024-06-03 03:25:20 +00:00
13) Run the app in the simulator
2023-01-05 23:33:49 +00:00
```bash
2023-04-01 20:13:16 +00:00
npm run build
npx cap sync
2023-09-05 18:04:23 +00:00
npx cap run ios
2023-01-05 23:33:49 +00:00
```
2023-12-05 03:46:54 +00:00
If prompted to select a target device, select "iPhone 15 Pro Max (simulator)".
2024-06-03 03:25:20 +00:00
The app should look like the screenshot at the top of the page.
2023-04-01 20:13:16 +00:00
2024-06-03 03:25:20 +00:00
14) Test the export functionality.
2023-04-01 20:13:16 +00:00
2023-09-05 18:04:23 +00:00
Touch "Export XLSX" and a popup will be displayed.
2023-04-01 20:13:16 +00:00
2023-09-05 18:04:23 +00:00
To see the generated file, switch to the "Files" app in the simulator and look
for `SheetJSCap.xlsx` in "On My iPhone" > "`sheetjs-cap`"
2023-01-05 23:33:49 +00:00
2024-06-03 03:25:20 +00:00
<details open>
<summary><b>Downloading the generated file</b> (click to hide)</summary>
The app files are available in the filesystem in `~/Library/Developer`. Open a
terminal and run the following command to find the file:
```bash
find ~/Library/Developer -name SheetJSCap.xlsx
```
</details>
15) Test the import functionality.
Create a spreadsheet or find an existing file. Click and drag the file into the
iOS simulator window. The simulator will show a picker for saving the file.
Select the `sheetjs-cap` folder and tap "Save".
Tap on "Choose File" in the app and "Choose File" in the popup. In the picker,
tap "Recents" and select the new file. After selecting the file, the table will refresh.
2023-12-05 03:46:54 +00:00
### Android Device
2024-06-03 03:25:20 +00:00
16) Connect an Android device using a USB cable.
2023-12-05 03:46:54 +00:00
If the device asks to allow USB debugging, tap "Allow".
2024-06-03 03:25:20 +00:00
17) Close any Android / iOS emulators.
2023-12-05 03:46:54 +00:00
2024-06-03 03:25:20 +00:00
18) Build APK and run on device:
2023-12-05 03:46:54 +00:00
```bash
npm run build
npx cap sync
npx cap run android
```
If the Android emulators are closed and an Android device is connected, the last
command will build an APK and install on the device.
2024-06-03 03:25:20 +00:00
:::note pass
In some tests, the last command asked for a target device. Select the Android
device in the list and press <kbd>Enter</kbd>
:::
2023-12-05 03:46:54 +00:00
:::caution pass
For real devices running API level 29 or below, the following line must be added
to the `application` open tag in `android/app/src/main/AndroidManifest.xml`:
```xml title="android/app/src/main/AndroidManifest.xml (add highlighted attribute)"
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
// highlight-next-line
android:requestLegacyExternalStorage="true"
android:theme="@style/AppTheme">
```
:::
### iOS Device
2024-06-03 03:25:20 +00:00
19) Connect an iOS device using a USB cable
20) Close any Android / iOS emulators.
2023-12-05 03:46:54 +00:00
2024-06-03 03:25:20 +00:00
21) Enable developer code signing certificates.
2023-12-05 03:46:54 +00:00
2024-06-03 03:25:20 +00:00
Open `ios/App/App.xcworkspace` in Xcode. Select the "Project Navigator" and
select the "App" project. In the main view, select "Signing & Capabilities".
Under "Signing", select a team in the dropdown menu.
2023-12-05 03:46:54 +00:00
2024-06-03 03:25:20 +00:00
22) Run on device:
2023-12-05 03:46:54 +00:00
```bash
npm run build
npx cap sync
npx cap run ios
```
When prompted to select a target device, select the real device in the list.
2024-06-03 03:25:20 +00:00
[^1]: See [`read` in "Reading Files"](/docs/api/parse-options)
[^2]: See [`sheet_to_html` in "Utilities"](/docs/api/utilities/html#html-table-output)
[^3]: See ["Workbook Object"](/docs/csf/book)
2024-06-04 04:56:22 +00:00
[^4]: See [the "base64" type in "Writing Files"](/docs/api/write-options#output-type)
2024-06-03 03:25:20 +00:00
[^5]: See [`table_to_book` in "HTML" Utilities](/docs/api/utilities/html#create-new-sheet)
[^6]: See ["Environment Setup"](https://capacitorjs.com/docs/getting-started/environment-setup) in the CapacitorJS documentation.