diff --git a/docz/docs/03-demos/05-mobile/02-nativescript.md b/docz/docs/03-demos/05-mobile/02-nativescript.md index 4d1680f..1297b2a 100644 --- a/docz/docs/03-demos/05-mobile/02-nativescript.md +++ b/docz/docs/03-demos/05-mobile/02-nativescript.md @@ -10,78 +10,83 @@ sidebar_custom_props: The [NodeJS Module](/docs/getting-started/installation/nodejs) can be imported from the main entrypoint or any script in the project. -:::warning Binary Data issues +The "Complete Example" creates an app that looks like the screenshots below: -NativeScript will not safely transmit binary or UTF-8 strings. XLSB, NUMBERS, -XLSX, XLS, ODS, SYLK, and DBF exports are known to be mangled. + + +
iOS
-This is a known NativeScript bug. +![iOS screenshot](pathname:///mobile/nsios.png) -This demo will focus on ASCII CSV files. Once the bug is resolved, XLSX and -other formats will be supported. - -::: +
## Integration Details -The `@nativescript/core/file-system` package provides classes for file access. +The discussion covers the NativeScript + Angular integration. Familiarity with +Angular and TypeScript is assumed. -Reading and writing data require a file handle. The following snippet searches -typical document folders for a specified filename: +The `@nativescript/core/file-system` package provides classes for file access. +The `File` class does not support binary data, but the file access singleton +from `@nativescript/core` does support reading and writing `ArrayBuffer`. + +Reading and writing data require a URL. The following snippet searches typical +document folders for a specified filename: ```ts -import { File, Folder, knownFolders, path } from '@nativescript/core/file-system'; +import { Folder, knownFolders, path } from '@nativescript/core/file-system'; -function get_handle_for_filename(filename: string): File { +function get_url_for_filename(filename: string): string { const target: Folder = knownFolders.documents() || knownFolders.ios.sharedPublic(); - const url: string = path.normalize(target.path + "///" + filename); - return File.fromPath(url); + return path.normalize(target.path + "///" + filename); } ``` -The encoding `ISO_8859_1` spiritually resembles the `"binary"` SheetJS type +#### Reading data -**Reading data** - -`File#readText(encoding.ISO_8859_1)` returns strings compatible with `"binary"` +`getFileAccess().readBufferAsync` can read data: ```ts -/* get binary string */ -const bstr: string = await file.readText(encoding.ISO_8859_1); +import { getFileAccess } from '@nativescript/core'; + +/* find appropriate path */ +const url = get_url_for_filename("SheetJSNS.xls"); + +/* get data */ +const ab: ArrayBuffer = await getFileAccess().readBufferAsync(url); /* read workbook */ -const wb = read(bstr, { type: "binary" }); +const wb = read(ab); ``` -**Writing data** +#### Writing data -`File#writeText` with the `ISO_8859_1` encoding accepts `"binary"` strings with -the caveat listed in the warning at the top of this section: +`getFileAccess().writeBufferAsync` can write data: ```ts -/* generate binary string */ -const bstr: string = write(wb, { bookType: 'csv', type: 'binary' }); +import { getFileAccess } from '@nativescript/core'; -/* attempt to save binary string to file */ -await file.writeText(bstr, encoding.ISO_8859_1); +/* find appropriate path */ +const url = get_url_for_filename("SheetJSNS.xls"); + +/* generate Uint8Array */ +const u8: Uint8Array = write(wb, { bookType: 'xls', type: 'binary' }); + +/* attempt to save Uint8Array to file */ +await getFileAccess().writeBufferAsync(url, u8); ``` ## Demo -The demo builds off of the NativeScript + Angular example. Familiarity with -Angular and TypeScript is assumed. - :::note -This demo was tested on an Intel Mac on 2022 August 10. NativeScript version -(as verified with `ns --version`) is `8.3.2`. The iOS simulator runs iOS 15.5 -on an iPhone SE 3rd generation. +This demo was tested on an Intel Mac on 2023 April 03. NativeScript version +(as verified with `ns --version`) is `8.5.1`. + +The iOS simulator runs iOS 16.2 on an iPhone 14 Pro Max. ::: -
Complete Example (click to show) - -0) Follow the official Environment Setup instructions (tested with "MacOS + iOS") +0) Follow the official Environment Setup instructions 1) Create a skeleton NativeScript + Angular app: @@ -110,48 +115,32 @@ npm i --save https://cdn.sheetjs.com/xlsx-latest/xlsx-latest.tgz 4) To confirm the library was loaded, change the title to show the version. The differences are highlighted. -`src/app/item/items.component.ts` imports the version string to the component: +`src/app/item/items.component.ts` should import the version string: ```ts title="src/app/item/items.component.ts" // highlight-next-line import { version } from 'xlsx'; import { Component, OnInit } from '@angular/core' -import { Item } from './item' -import { ItemService } from './item.service' +// ... -@Component({ - selector: 'ns-items', - templateUrl: './items.component.html', -}) export class ItemsComponent implements OnInit { items: Array // highlight-next-line version = `SheetJS - ${version}`; constructor(private itemService: ItemService) {} - - ngOnInit(): void { - this.items = this.itemService.getItems() - } -} +// ... ``` -`src/app/item/items.component.html` references the version in the title: +`src/app/item/items.component.html` should use the version in the title: ```xml title="src/app/item/items.component.html" - - - - - - - - + ``` Relaunch the app with `ns run ios` and the title bar should show the version. @@ -171,11 +160,7 @@ Relaunch the app with `ns run ios` and the title bar should show the version. - - - - - + @@ -184,9 +169,8 @@ Relaunch the app with `ns run ios` and the title bar should show the version. ```ts title="src/app/item/items.component.ts" // highlight-start import { version, utils, read, write } from 'xlsx'; -import { Dialogs } from '@nativescript/core'; -import { encoding } from '@nativescript/core/text'; -import { File, Folder, knownFolders, path } from '@nativescript/core/file-system'; +import { Dialogs, getFileAccess } from '@nativescript/core'; +import { Folder, knownFolders, path } from '@nativescript/core/file-system'; // highlight-end import { Component, OnInit } from '@angular/core' @@ -194,10 +178,9 @@ import { Item } from './item' import { ItemService } from './item.service' // highlight-start -function get_handle_for_filename(filename: string): [File, string] { +function get_url_for_filename(filename: string): string { const target: Folder = knownFolders.documents() || knownFolders.ios.sharedPublic(); - const url: string = path.normalize(target.path + "///" + filename); - return [File.fromPath(url), url]; + return path.normalize(target.path + "///" + filename); } // highlight-end @@ -231,50 +214,22 @@ Restart the app process and two buttons should show up at the top: ![NativeScript Step 5](pathname:///mobile/nativescript5.png) -6) Implement import and export: +6) Implement import and export by adding the highlighted lines: ```ts title="src/app/item/items.component.ts" -import { version, utils, read, write } from 'xlsx'; -import { Dialogs } from '@nativescript/core'; -import { encoding } from '@nativescript/core/text'; -import { File, Folder, knownFolders, path } from '@nativescript/core/file-system'; -import { Component, OnInit } from '@angular/core' - -import { Item } from './item' -import { ItemService } from './item.service' - -function get_handle_for_filename(filename: string): [File, string] { - const target: Folder = knownFolders.documents() || knownFolders.ios.sharedPublic(); - const url: string = path.normalize(target.path + "///" + filename); - return [File.fromPath(url), url]; -} - -@Component({ - selector: 'ns-items', - templateUrl: './items.component.html', -}) -export class ItemsComponent implements OnInit { - items: Array - version: string = `SheetJS - ${version}`; - - constructor(private itemService: ItemService) {} - - ngOnInit(): void { - this.items = this.itemService.getItems() - } - /* Import button */ async import() { // highlight-start /* find appropriate path */ - const [file, url] = get_handle_for_filename("SheetJSNS.csv"); + const url = get_url_for_filename("SheetJSNS.xls"); try { - /* get binary string */ - const bstr: string = await file.readText(encoding.ISO_8859_1); + await Dialogs.alert(`Attempting to read from SheetJSNS.xls at ${url}`); + /* get data */ + const ab: ArrayBuffer = await getFileAccess().readBufferAsync(url); /* read workbook */ - const wb = read(bstr, { type: "binary" }); + const wb = read(ab); /* grab first sheet */ const wsname: string = wb.SheetNames[0]; @@ -282,8 +237,7 @@ export class ItemsComponent implements OnInit { /* update table */ this.items = utils.sheet_to_json(ws); - Dialogs.alert(`Attempting to read to ${filename} in ${url}`); - } catch(e) { Dialogs.alert(e.message); } + } catch(e) { await Dialogs.alert(e.message); } // highlight-end } @@ -291,7 +245,7 @@ export class ItemsComponent implements OnInit { async export() { // highlight-start /* find appropriate path */ - const [file, url] = get_handle_for_filename("SheetJSNS.csv"); + const url = get_url_for_filename("SheetJSNS.xls"); try { /* create worksheet from data */ @@ -301,50 +255,41 @@ export class ItemsComponent implements OnInit { const wb = utils.book_new(); utils.book_append_sheet(wb, ws, "Sheet1"); - /* generate binary string */ - const wbout: string = write(wb, { bookType: 'csv', type: 'binary' }); + /* generate Uint8Array */ + const u8: Uint8Array = write(wb, { bookType: 'xls', type: 'buffer' }); - /* attempt to save binary string to file */ - await file.writeText(wbout, encoding.ISO_8859_1); - Dialogs.alert(`Wrote to ${filename} in ${url}`); - } catch(e) { Dialogs.alert(e.message); } + /* attempt to save Uint8Array to file */ + await getFileAccess().writeBufferAsync(url, u8); + await Dialogs.alert(`Wrote to SheetJSNS.xls at ${url}`); + } catch(e) { await Dialogs.alert(e.message); } // highlight-end } -} ``` -Restart the app process. +### iOS -**Testing** +Relaunch the app with `ns run ios` The app can be tested with the following sequence in the simulator: -- Hit "Export File". A dialog will print where the file was written +- Tap "Export File". A dialog will print where the file was written -- Open that file with a text editor. It will be a 3-column CSV: +- Open the file with a spreadsheet editor. -```csv -id,name,role -1,Ter Stegen,Goalkeeper -3,Piqué,Defender -4,I. Rakitic,Midfielder +After the header row, insert a row with cell A2 = 0, B2 = SheetJS, C2 = Library: + +``` +id | name | role + 0 | SheetJS | Library + 1 | Ter Stegen | Goalkeeper + 3 | Piqué | Defender ... ``` -After the header row, add the line `0,SheetJS,Library`: +Restart the app after saving the file. -```csv -id,name,role -0,SheetJS,Library -1,Ter Stegen,Goalkeeper -3,Piqué,Defender -... -``` - -- Hit "Import File". A dialog will print the path of the file that was read. +- Tap "Import File". A dialog will print the path of the file that was read. The first item in the list will change: ![NativeScript Step 7](pathname:///mobile/nativescript7.png) -
- diff --git a/docz/docs/03-demos/05-mobile/index.md b/docz/docs/03-demos/05-mobile/index.md index 7329d80..7a80273 100644 --- a/docz/docs/03-demos/05-mobile/index.md +++ b/docz/docs/03-demos/05-mobile/index.md @@ -56,7 +56,4 @@ should support and investigate community modules. If there are popular modules for features that must be included, or for teams that are comfortable with native app development, React Native is the obvious choice. -NativeScript is not recommended at this time. There are known bugs related to -binary data processing. The demo only supports plaintext file formats like CSV. - ::: diff --git a/docz/docs/03-demos/11-bigdata/02-worker.md b/docz/docs/03-demos/11-bigdata/02-worker.md index d836145..91b0c56 100644 --- a/docz/docs/03-demos/11-bigdata/02-worker.md +++ b/docz/docs/03-demos/11-bigdata/02-worker.md @@ -521,7 +521,7 @@ sequenceDiagram deactivate Page end Worker->>User: finish download - Worker->>Page: send competion message + Worker->>Page: send completion message deactivate Worker activate Page Page->>User: download complete diff --git a/docz/static/mobile/nativescript4.png b/docz/static/mobile/nativescript4.png index df09f4e..87ba579 100644 Binary files a/docz/static/mobile/nativescript4.png and b/docz/static/mobile/nativescript4.png differ diff --git a/docz/static/mobile/nativescript5.png b/docz/static/mobile/nativescript5.png index 90c3807..67bba8e 100644 Binary files a/docz/static/mobile/nativescript5.png and b/docz/static/mobile/nativescript5.png differ diff --git a/docz/static/mobile/nativescript7.png b/docz/static/mobile/nativescript7.png index 9d83a1d..8660bc7 100644 Binary files a/docz/static/mobile/nativescript7.png and b/docz/static/mobile/nativescript7.png differ diff --git a/docz/static/mobile/nsios.png b/docz/static/mobile/nsios.png new file mode 100644 index 0000000..2280c79 Binary files /dev/null and b/docz/static/mobile/nsios.png differ