docs.sheetjs.com/docz/docs/03-demos/05-mobile/04-ionic.md
2023-09-11 00:44:15 -04:00

12 KiB

title sidebar_label description pagination_prev pagination_next sidebar_position sidebar_custom_props
Data Conduction in Ionic Apps Ionic Build data-intensive mobile apps with Ionic and Cordova. Seamlessly integrate spreadsheets into your app using SheetJS. Let data in your Excel spreadsheets shine. demos/static/index demos/desktop/index 4
summary
Native Components + Web View

import current from '/version.js'; import CodeBlock from '@theme/CodeBlock';

Ionic is a mobile app framework for building iOS and Android apps with the Cordova platform.

SheetJS is a JavaScript library for reading and writing data from spreadsheets.

This demo uses Ionic and SheetJS to process data and generate spreadsheets. We'll explore how to load SheetJS in an Ionic app and use Ionic APIs and plugins to extract data from, and write data to, spreadsheet files on the device.

The "Demo" creates an app that looks like the screenshots below:

iOS Android

iOS screenshot

Android screenshot

:::info pass

This demo covers Ionic apps using the Cordova platform.

The CapacitorJS demo covers CapacitorJS apps.

:::

:::warning Telemetry

Before starting this demo, manually disable telemetry. On Linux and MacOS:

rm -rf ~/.ionic/
mkdir ~/.ionic
cat <<EOF > ~/.ionic/config.json
{
  "version": "6.20.1",
  "telemetry": false,
  "npmClient": "npm"
}
EOF
npx @capacitor/cli telemetry off

To verify telemetry was disabled:

npx @ionic/cli config get -g telemetry
npx @capacitor/cli telemetry

:::

Integration Details

The SheetJS NodeJS Module can be imported from the main entrypoint or any script in the project.

Internal State

The "Angular" demo discusses a number of state representations and preview strategies.

For this demo, the internal state is an "array of arrays"1 (any[][]):

import { Component } from '@angular/core';
type AOA = any[][];

@Component({...})
export class SheetJSTablePage {
  data: AOA = [
    ["S", "h", "e", "e", "t", "J", "S"],
    [  5,   4,   3,   3,   7,   9,   5]
  ];
  // ...
}

Displaying Data

ion-grid2 is a display grid component. The Angular ngFor directive3 simplifies iteration over the array of arrays:

<ion-grid>
  <ion-row *ngFor="let row of data">
    <ion-col *ngFor="let val of row">
      {{val}}
    </ion-col>
  </ion-row>
</ion-grid>

File Operations

@awesome-cordova-plugins/file reads and writes files on devices.

:::info pass

The plugins in the @ionic-native scope have been deprecated. The community modules in the @awesome-cordova-plugins scope should be used.

:::

Reading Files

this.file.readAsArrayBuffer reads file data from a specified URL and resolves to ArrayBuffer objects.

These objects can be parsed with the SheetJS read method4. The SheetJS sheet_to_json method5 with the option header: 1 generates an array of arrays which can be assigned to the page state:

/* read a workbook file */
const ab: ArrayBuffer = await this.file.readAsArrayBuffer(url, filename);
/* parse */
const wb: XLSX.WorkBook = XLSX.read(ab, {type: 'array'});
/* generate an array of arrays from the first worksheet */
const ws: XLSX.WorkSheet = wb.SheetNames[wb.Sheets[0]];
const aoa: AOA = XLSX.utils.sheet_to_json(ws, {header: 1});
/* update state */
this.data = aoa;

Writing Files

this.file.writeFile writes file data stored in Blob objects to the device.

From the array of arrays, the SheetJS aoa_to_sheet method6 generates a worksheet object. The book_new and book_append_sheet helpers7 generate a workbook object. The SheetJS write method8 with the option type: "array" will generate an ArrayBuffer, from which a Blob can be created:

/* generate worksheet */
const ws: XLSX.WorkSheet = XLSX.utils.aoa_to_sheet(this.data);

/* generate workbook and add the worksheet */
const wb: XLSX.WorkBook = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(wb, ws, 'SheetJS');

/* write XLSX to ArrayBuffer */
const ab: ArrayBuffer = XLSX.write(wb, { bookType: 'xlsx', type: 'array' });

/* generate Blob */
let blob = new Blob([ab], {type: 'application/octet-stream'});

/* write Blob to device */
this.file.writeFile(url, filename, blob, {replace: true});

Demo

:::note

The project was last tested in 2023 September 10. ionic info showed:

  • Ionic: @ionic/angular 7.3.3, @ionic/angular-toolkit 9.0.0
  • Cordova: cordova-lib@12.0.1, android 12.0.1, ios 7.0.1

The file integration uses @awesome-cordova-plugins/file version 6.4.0.

The iOS demo was last tested on 2023 September 10 on an emulated iPhone SE (3rd generation) + iOS 16.4

The Android demo was last tested on 2023 September 10 on an emulated Pixel 3 + Android 13 ("Tiramisu") API 33.

:::

The app in this demo will display data in a table.

On load, a test file will be processed.

When a document is selected with the file picker, it will be processed and the table will refresh to show the contents.

"Import Data" will attempt to read SheetJSIonic.xlsx from a known location. An alert will display the expected location.

"Export Data" will attempt to export the table data to SheetJSIonic.xlsx in a known location. After writing, an alert will display the location of the file.

Platform Setup

  1. Disable telemetry as noted in the warning.

  2. Follow the official instructions for iOS and Android development9.

  3. Install required global dependencies:

npm i -g cordova-res @angular/cli native-run @ionic/cli

Base Project

  1. Create a new project:
ionic start SheetJSIonic blank --type angular --cordova --quiet --no-git --no-link --confirm

When asked to select NgModules or Standalone Components, select NgModules

If a prompt asks to confirm Cordova use, enter Yes to continue.

If a prompt asks about creating an Ionic account, enter N to opt out.

  1. Set up Cordova:
cd SheetJSIonic
ionic cordova plugin add cordova-plugin-file
ionic cordova platform add ios --confirm
ionic cordova platform add android --confirm
npm i --save @awesome-cordova-plugins/core @awesome-cordova-plugins/file @ionic/cordova-builders

:::note pass

If cordova-plugin-file is added before the platforms, installation may fail:

CordovaError: Could not load API for ios project

This can be resolved by removing and reinstalling the ios platform:

ionic cordova platform rm ios
ionic cordova platform add ios --confirm

:::

:::caution pass

If the npm i step fails due to rxjs resolution, add the highlighted lines to package.json to force a resolution:

  "private": true,
  // highlight-start
  "overrides": {
    "rxjs": "~7.5.0"
  },
  // highlight-end
  "dependencies": {

Note that the required rxjs version will be displayed in the error log.

After adding the lines, the npm i command will succeed.

:::

  1. Install dependencies:

{\ npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz}

  1. Add @awesome-cordova-plugins/file to the module. Differences highlighted below:
import { AppComponent } from './app.component';
import { AppRoutingModule } from './app-routing.module';

// highlight-next-line
import { File } from '@awesome-cordova-plugins/file/ngx';

@NgModule({
  declarations: [AppComponent],
  imports: [BrowserModule, IonicModule.forRoot(), AppRoutingModule],

  // highlight-next-line
  providers: [File, { provide: RouteReuseStrategy, useClass: IonicRouteStrategy }],
  bootstrap: [AppComponent],
})
export class AppModule {}
  1. Download home.page.ts and replace:
curl -o src/app/home/home.page.ts -L https://docs.sheetjs.com/ionic/home.page.ts

iOS

  1. Enable file sharing and make the documents folder visible in the iOS app. Add the following lines to platforms/ios/SheetJSIonic/SheetJSIonic-Info.plist:
<plist version="1.0">
<dict>
<!-- highlight-start -->
  <key>UIFileSharingEnabled</key>
  <true/>
  <key>LSSupportsOpeningDocumentsInPlace</key>
  <true/>
<!-- highlight-end -->
  <key>CFBundleDevelopmentRegion</key>

(The root element of the document is plist and it contains one dict child)

  1. Build the app and start the simulator
ionic cordova emulate ios

When the app is loaded, a list of Presidents should be displayed. This list is dynamically generated by fetching and parsing a test file.

:::caution pass

In some test runs, the cordova build ios --emulator step failed with error:

> cordova build ios --emulator
Could not load API for ios project

This was resolved by forcefully installing cordova-ios:

npm i --save cordova-ios

:::

:::info pass

In the most recent test, the native-run ios command failed with

[native-run] ERR_UNKNOWN: Path 'platforms/ios/build/emulator/SheetJSIonic.app' not found

Inspecting platforms/ios/build/, the actual folder name was:

% ls platforms/ios/build
#highlight-next-line
Debug-iphonesimulator

The iOS simulator can be launched manually:

native-run ios --app platforms/ios/build/Debug-iphonesimulator/SheetJSIonic.app --virtual

:::

Android

  1. Enable file reading and writing in the Android app.

Edit platforms/android/app/src/main/AndroidManifest.xml and add the following two lines before the application tag:

    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

In the application tag, add the attribute android:requestLegacyExternalStorage="true".

  1. Build the app and start the emulator
ionic cordova emulate android

When the app is loaded, a list of Presidents should be displayed. This list is dynamically generated by fetching and parsing a test file.

:::caution pass

In some test runs, cordova build android --emulator step failed with error:

Could not find or parse valid build output file

This was resolved by forcefully installing cordova-android:

npm i --save cordova-android

:::

:::caution pass

In some tests, the build failed with a Gradle error:

Could not find an installed version of Gradle either in Android Studio,
or on your system to install the gradle wrapper. Please include gradle
in your path or install Android Studio

On macOS, this issue was resolved by installing gradle with Homebrew manager:

brew install gradle

:::

:::warning pass

When the demo was last tested on Android, reading files worked as expected. However, the generated files were not externally visible from the Files app.

This is a known bug with Android SDK 33 and the underlying file plugins!

:::


  1. See "Array of Arrays" in the API reference ↩︎

  2. See ion-grid in the Ionic documentation. ↩︎

  3. See ngFor in the Angular documentation. ↩︎

  4. See read in "Reading Files" ↩︎

  5. See "Array Output" in "Utility Functions" ↩︎

  6. See aoa_to_sheet in "Utilities" ↩︎

  7. See "Workbook Helpers" in "Utilities" for details on book_new and book_append_sheet. ↩︎

  8. See write in "Writing Files" ↩︎

  9. See "Developing for iOS" and "Developing for Android" in the v6 Ionic framework documentation. ↩︎