forked from sheetjs/docs.sheetjs.com
		
	nativescript
This commit is contained in:
		
							parent
							
								
									683eb8c2ab
								
							
						
					
					
						commit
						b2ef80c897
					
				
							
								
								
									
										377
									
								
								docz/docs/04-getting-started/03-demos/19-mobile.md
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										377
									
								
								docz/docs/04-getting-started/03-demos/19-mobile.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,377 @@ | ||||
| --- | ||||
| sidebar_position: 19 | ||||
| title: iOS and Android Apps | ||||
| --- | ||||
| 
 | ||||
| Many mobile app frameworks mix JavaScript / CSS / HTML5 concepts with native | ||||
| extensions and libraries to create a hybrid development experience.  Developers | ||||
| well-versed in web technologies can now build actual mobile applications that | ||||
| run on iOS and Android! | ||||
| 
 | ||||
| :::warning | ||||
| 
 | ||||
| **The ecosystem has broken backwards-compatibility many times!** | ||||
| 
 | ||||
| iOS and Android, as well as the underlying JavaScript frameworks, make breaking | ||||
| changes regularly.  The demos were tested against emulators / real devices at | ||||
| some point in time.  A framework or OS change can render the demos inoperable. | ||||
| 
 | ||||
| Each demo section will mention test dates and platform versions. | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| The ["JavaScript Engines"](./engines) section includes samples for JavaScript | ||||
| engines used in the mobile app frameworks.  SheetJS libraries have been tested | ||||
| in the relevant engines and should "just work" with some caveats. | ||||
| 
 | ||||
| :::caution readFile and writeFile | ||||
| 
 | ||||
| `XLSX.readFile` and `XLSX.writeFile` do not work in mobile apps!  The demos | ||||
| include platform-specific details for fetching file data for `XLSX.read` and | ||||
| writing file data generated by `XLSX.write`. | ||||
| 
 | ||||
| Some platforms provide this functionality as part of the standard library. | ||||
| Other platforms, including React Native, do not.  When the platform does not | ||||
| provide, usually there are third-party modules to provide needed functionality. | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| ## NativeScript | ||||
| 
 | ||||
| :::note | ||||
| 
 | ||||
| This demo was tested on an Intel Mac on August 10 2022.  NativeScript version | ||||
| (as verified with `ns --version`) is `8.3.2`.  The iOS simulator runs iOS 15.5 | ||||
| on an iPhone SE 3rd generation. | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| :::warning Binary Data issues | ||||
| 
 | ||||
| NativeScript will not safely transmit binary or UTF8 strings. XLSB, NUMBERS, | ||||
| XLSX, XLS, ODS, SYLK, and DBF exports are known to be mangled. | ||||
| 
 | ||||
| [This is a known NativeScript bug](https://github.com/NativeScript/NativeScript/issues/9586) | ||||
| 
 | ||||
| This demo will focus on ASCII CSV files.  Once the bug is resolved, XLSX and | ||||
| other formats will be supported. | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| The `@nativescript/core/file-system` package provides classes for file access. | ||||
| 
 | ||||
| ### Integration Details | ||||
| 
 | ||||
| Reading and writing data require a file handle.  The following snippet searches | ||||
| typical document folders for a specified filename: | ||||
| 
 | ||||
| ```ts | ||||
| import { File, Folder, knownFolders, path } from '@nativescript/core/file-system'; | ||||
| 
 | ||||
| function get_handle_for_filename(filename: string): File { | ||||
|   const target: Folder = knownFolders.documents() || knownFolders.ios.sharedPublic(); | ||||
|   const url: string = path.normalize(target.path + "///" + filename); | ||||
|   return File.fromPath(url); | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| The encoding `ISO_8859_1` spiritually resembles the `"binary"` SheetJS type | ||||
| 
 | ||||
| **Reading data** | ||||
| 
 | ||||
| `File#readText(encoding.ISO_8859_1)` returns strings compatible with `"binary"` | ||||
| 
 | ||||
| ```ts | ||||
| /* get binary string */ | ||||
| const bstr: string = await file.readText(encoding.ISO_8859_1); | ||||
| 
 | ||||
| /* read workbook */ | ||||
| const wb = read(bstr, { type: "binary" }); | ||||
| ``` | ||||
| 
 | ||||
| **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: | ||||
| 
 | ||||
| ```ts | ||||
| /* generate binary string */ | ||||
| const bstr: string = write(wb, { bookType: 'csv', type: 'binary' }); | ||||
| 
 | ||||
| /* attempt to save binary string to file */ | ||||
| await file.writeText(bstr, encoding.ISO_8859_1); | ||||
| ``` | ||||
| 
 | ||||
| ### Demo | ||||
| 
 | ||||
| The demo builds off of the NativeScript + Angular example.  Familiarity with | ||||
| with Angular and TypeScript is assumed. | ||||
| 
 | ||||
| <details open><summary><b>Complete Example</b> (click to show)</summary> | ||||
| 
 | ||||
| 0) Follow the official Environment Setup instructions (tested with "macOS + iOS") | ||||
| 
 | ||||
| 1) Create a skeleton NativeScript + Angular app: | ||||
| 
 | ||||
| ```bash | ||||
| ns create SheetJSNS --ng | ||||
| ``` | ||||
| 
 | ||||
| 2) Launch the app in the iOS simulator to verify that the demo built properly: | ||||
| 
 | ||||
| ```bash | ||||
| cd SheetJSNS | ||||
| ns run ios | ||||
| ``` | ||||
| 
 | ||||
| (this may take a while) | ||||
| 
 | ||||
| Once the simulator launches and the test app is displayed, end the script by | ||||
| selecting the terminal and entering the key sequence `CTRL + C` | ||||
| 
 | ||||
| 3) From the project folder, install the library: | ||||
| 
 | ||||
| ```bash | ||||
| npm install --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: | ||||
| 
 | ||||
| ```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<Item> | ||||
|   // 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: | ||||
| 
 | ||||
| ```xml title="src/app/item/items.component.html" | ||||
| <!-- highlight-next-line --> | ||||
| <ActionBar [title]="version"></ActionBar> | ||||
| 
 | ||||
| <GridLayout> | ||||
|   <ListView [items]="items"> | ||||
|     <ng-template let-item="item"> | ||||
|       <StackLayout [nsRouterLink]="['/item', item.id]"> | ||||
|         <Label [text]="item.name"></Label> | ||||
|       </StackLayout> | ||||
|     </ng-template> | ||||
|   </ListView> | ||||
| </GridLayout> | ||||
| ``` | ||||
| 
 | ||||
| Relaunch the app with `ns run ios` and the title bar should show the version. | ||||
| 
 | ||||
|  | ||||
| 
 | ||||
| 5) Add the Import and Export buttons to the template: | ||||
| 
 | ||||
| ```xml title="src/app/item/items.component.html" | ||||
| <ActionBar [title]="version"></ActionBar> | ||||
| 
 | ||||
| <!-- highlight-start --> | ||||
| <StackLayout> | ||||
|   <StackLayout orientation="horizontal"> | ||||
|     <Button text="Import File" (tap)="import()" style="padding: 10px"></Button> | ||||
|     <Button text="Export File" (tap)="export()" style="padding: 10px"></Button> | ||||
|   </StackLayout> | ||||
| <!-- highlight-end --> | ||||
|   <ListView [items]="items"> | ||||
|     <ng-template let-item="item"> | ||||
|       <StackLayout [nsRouterLink]="['/item', item.id]"> | ||||
|         <Label [text]="item.name"></Label> | ||||
|       </StackLayout> | ||||
|     </ng-template> | ||||
|   </ListView> | ||||
| <!-- highlight-next-line --> | ||||
| </StackLayout> | ||||
| ``` | ||||
| 
 | ||||
| ```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'; | ||||
| // highlight-end | ||||
| import { Component, OnInit } from '@angular/core' | ||||
| 
 | ||||
| import { Item } from './item' | ||||
| import { ItemService } from './item.service' | ||||
| 
 | ||||
| // highlight-start | ||||
| 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]; | ||||
| } | ||||
| // highlight-end | ||||
| 
 | ||||
| @Component({ | ||||
|   selector: 'ns-items', | ||||
|   templateUrl: './items.component.html', | ||||
| }) | ||||
| export class ItemsComponent implements OnInit { | ||||
|   items: Array<Item> | ||||
|   version: string = `SheetJS - ${version}`; | ||||
| 
 | ||||
|   constructor(private itemService: ItemService) {} | ||||
| 
 | ||||
|   ngOnInit(): void { | ||||
|     this.items = this.itemService.getItems() | ||||
|   } | ||||
| 
 | ||||
|   // highlight-start | ||||
|   /* Import button */ | ||||
|   async import() { | ||||
|   } | ||||
| 
 | ||||
|   /* Export button */ | ||||
|   async export() { | ||||
|   } | ||||
|   // highlight-end | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| Restart the app process and two buttons should show up at the top: | ||||
| 
 | ||||
|  | ||||
| 
 | ||||
| 6) Implement import and export: | ||||
| 
 | ||||
| ```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<Item> | ||||
|   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"); | ||||
| 
 | ||||
|     try { | ||||
|       /* get binary string */ | ||||
|       const bstr: string = await file.readText(encoding.ISO_8859_1); | ||||
| 
 | ||||
|       /* read workbook */ | ||||
|       const wb = read(bstr, { type: "binary" }); | ||||
| 
 | ||||
|       /* grab first sheet */ | ||||
|       const wsname: string = wb.SheetNames[0]; | ||||
|       const ws = wb.Sheets[wsname]; | ||||
| 
 | ||||
|       /* update table */ | ||||
|       this.items = utils.sheet_to_json<Item>(ws); | ||||
|       Dialogs.alert(`Attempting to read to ${filename} in ${url}`); | ||||
|     } catch(e) { Dialogs.alert(e.message); } | ||||
|     // highlight-end | ||||
|   } | ||||
| 
 | ||||
|   /* Export button */ | ||||
|   async export() { | ||||
|     // highlight-start | ||||
|     /* find appropriate path */ | ||||
|     const [file, url] = get_handle_for_filename("SheetJSNS.csv"); | ||||
| 
 | ||||
|     try { | ||||
|       /* create worksheet from data */ | ||||
|       const ws = utils.json_to_sheet(this.items); | ||||
| 
 | ||||
|       /* create workbook from worksheet */ | ||||
|       const wb = utils.book_new(); | ||||
|       utils.book_append_sheet(wb, ws, "Sheet1"); | ||||
| 
 | ||||
|       /* generate binary string */ | ||||
|       const wbout: string = write(wb, { bookType: 'csv', type: 'binary' }); | ||||
| 
 | ||||
|       /* 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); } | ||||
|     // highlight-end | ||||
|   } | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| Restart the app process. | ||||
| 
 | ||||
| **Testing** | ||||
| 
 | ||||
| The app can be tested with the following sequence in the simulator: | ||||
| 
 | ||||
| - Hit "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: | ||||
| 
 | ||||
| ```csv | ||||
| id,name,role | ||||
| 1,Ter Stegen,Goalkeeper | ||||
| 3,Piqué,Defender | ||||
| 4,I. Rakitic,Midfielder | ||||
| ... | ||||
| ``` | ||||
| 
 | ||||
| After the header row, add the line `0,SheetJS,Library`: | ||||
| 
 | ||||
| ```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. | ||||
|   The first item in the list will change: | ||||
| 
 | ||||
|  | ||||
| 
 | ||||
| </details> | ||||
| @ -35,6 +35,7 @@ The demo projects include small runnable examples and short explainers. | ||||
| ### Platforms and Integrations | ||||
| 
 | ||||
| - [`Command-Line Tools`](./cli) | ||||
| - [`iOS / Android Mobile Applications`](./mobile) | ||||
| - [`NodeJS Server-Side Processing`](https://github.com/SheetJS/SheetJS/tree/master/demos/server/) | ||||
| - [`Electron`](./desktop#electron) | ||||
| - [`NW.js`](./desktop#nwjs) | ||||
| @ -49,7 +50,7 @@ The demo projects include small runnable examples and short explainers. | ||||
| - [`"serverless" functions`](https://github.com/SheetJS/SheetJS/tree/master/demos/function/) | ||||
| - [`Databases and Structured Data Stores`](./database) | ||||
| - [`NoSQL, K/V, and Unstructured Data Stores`](./nosql) | ||||
| - [`Legacy Internet Explorer`](https://github.com/SheetJS/SheetJS/tree/master/demos/oldie/) | ||||
| - [`Legacy Internet Explorer`](./legacy#internet-explorer) | ||||
| 
 | ||||
| ### Bundlers and Tooling | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										
											BIN
										
									
								
								docz/static/mobile/nativescript4.png
									
									
									
									
									
										Normal file
									
								
							
							
								
									
								
								
								
								
								
									
									
								
							
						
						
									
										
											BIN
										
									
								
								docz/static/mobile/nativescript4.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 6.3 KiB | 
							
								
								
									
										
											BIN
										
									
								
								docz/static/mobile/nativescript5.png
									
									
									
									
									
										Normal file
									
								
							
							
								
									
								
								
								
								
								
									
									
								
							
						
						
									
										
											BIN
										
									
								
								docz/static/mobile/nativescript5.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 23 KiB | 
							
								
								
									
										
											BIN
										
									
								
								docz/static/mobile/nativescript7.png
									
									
									
									
									
										Normal file
									
								
							
							
								
									
								
								
								
								
								
									
									
								
							
						
						
									
										
											BIN
										
									
								
								docz/static/mobile/nativescript7.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 73 KiB | 
		Loading…
	
		Reference in New Issue
	
	Block a user