From 28570a8fbd4452b211b7acf41fce8834539c21eb Mon Sep 17 00:00:00 2001 From: SheetJS Date: Sun, 7 May 2023 13:43:21 -0400 Subject: [PATCH] ns-android --- docz/docs/02-getting-started/02-example.mdx | 40 +++++-------- .../03-demos/05-mobile/02-nativescript.md | 55 ++++++++++++++++-- docz/static/mobile/nsand.png | Bin 0 -> 63696 bytes 3 files changed, 66 insertions(+), 29 deletions(-) create mode 100644 docz/static/mobile/nsand.png diff --git a/docz/docs/02-getting-started/02-example.mdx b/docz/docs/02-getting-started/02-example.mdx index 0df6cb4..8b69063 100644 --- a/docz/docs/02-getting-started/02-example.mdx +++ b/docz/docs/02-getting-started/02-example.mdx @@ -721,38 +721,30 @@ The Android demo has been tested in Windows 10 and in macOS. Test the app in the Android simulator: ```bash -npm run android +npx react-native start ``` +Once Metro is ready, it will display the commands: + +``` +r - reload the app +d - open developer menu +i - run on iOS +a - run on Android +``` + +Press `a` to run on android. + After clicking "Press to Export", the app will show an alert with the location -to the generated file. +to the generated file (`/data/user/0/com.sheetjspres/files/Presidents.xlsx`) -In the Android simulator, pulling the file requires additional steps. This -command will pull a Base64-encoded string from the simulator: +In the Android simulator, pulling the file requires additional steps: ```bash -adb exec-out run-as com.sheetjspres base64 files/Presidents.xlsx > pres.b64 +adb root +adb pull /data/user/0/com.sheetjspres/files/Presidents.xlsx Presidents.xlsx ``` -Decoding the file requires an OS-specific command: - - - - -```powershell -certutil -decode .\pres.b64 .\Presidents.xlsx -``` - - - - -```bash -base64 -D pres.b64 > Presidents.xlsx -``` - - - - This command generates `Presidents.xlsx` which can be opened. :::info Device Testing diff --git a/docz/docs/03-demos/05-mobile/02-nativescript.md b/docz/docs/03-demos/05-mobile/02-nativescript.md index c889f0d..a0a3c56 100644 --- a/docz/docs/03-demos/05-mobile/02-nativescript.md +++ b/docz/docs/03-demos/05-mobile/02-nativescript.md @@ -17,10 +17,15 @@ The "Complete Example" creates an app that looks like the screenshots below: +
iOSAndroid
![iOS screenshot](pathname:///mobile/nsios.png) + + +![Android screenshot](pathname:///mobile/nsand.png) +
## Integration Details @@ -63,7 +68,8 @@ const wb = read(ab); #### Writing data -`getFileAccess().writeBufferAsync` can write data: +`getFileAccess().writeBufferAsync` can write data. iOS supports `Uint8Array` +directly but Android requires a true array of numbers: ```ts import { getFileAccess } from '@nativescript/core'; @@ -75,15 +81,15 @@ const url = get_url_for_filename("SheetJSNS.xls"); const u8: Uint8Array = write(wb, { bookType: 'xls', type: 'binary' }); /* attempt to save Uint8Array to file */ -await getFileAccess().writeBufferAsync(url, u8); +await getFileAccess().writeBufferAsync(url, global.isAndroid ? (Array.from(u8) as any) : u8); ``` ## Demo :::note -This demo was tested on an Intel Mac on 2023 April 03. NativeScript version -(as verified with `ns --version`) is `8.5.1`. +This demo was tested on an Intel Mac on 2023 May 07. NativeScript version +(as verified with `ns --version`) is `8.5.3`. The iOS simulator runs iOS 16.2 on an iPhone 14 Pro Max. @@ -91,6 +97,8 @@ The iOS simulator runs iOS 16.2 on an iPhone 14 Pro Max. 0) Follow the official Environment Setup instructions +### Base Project + 1) Create a skeleton NativeScript + Angular app: ```bash @@ -262,7 +270,7 @@ Restart the app process and two buttons should show up at the top: const u8: Uint8Array = write(wb, { bookType: 'xls', type: 'buffer' }); /* attempt to save Uint8Array to file */ - await getFileAccess().writeBufferAsync(url, u8); + await getFileAccess().writeBufferAsync(url, global.isAndroid ? (Array.from(u8) as any) : u8); await Dialogs.alert(`Wrote to SheetJSNS.xls at ${url}`); } catch(e) { await Dialogs.alert(e.message); } // highlight-end @@ -296,3 +304,40 @@ Restart the app after saving the file. ![NativeScript Step 7](pathname:///mobile/nativescript7.png) +### Android + +Launch the app with `ns run android`. If the app does not automatically launch, +manually open the `SheetJSNS` app. + +The app can be tested with the following sequence in the simulator: + +- Tap "Export File". A dialog will print where the file was written. Typicaly +the URL is `/data/user/0/org.nativescript.SheetJSNS/files/SheetJSNS.xls` + +- Pull the file from the simulator: + +```bash +adb root +adb pull /data/user/0/org.nativescript.SheetJSNS/files/SheetJSNS.xls SheetJSNS.xls +``` + +- Open `SheetJSNS.xls` with a spreadsheet editor. + +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 +... +``` + +- Push the file back to the simulator: + +```bash +adb push SheetJSNS.xls /data/user/0/org.nativescript.SheetJSNS/files/SheetJSNS.xls +``` + +- Tap "Import File". A dialog will print the path of the file that was read. + The first item in the list will change. \ No newline at end of file diff --git a/docz/static/mobile/nsand.png b/docz/static/mobile/nsand.png new file mode 100644 index 0000000000000000000000000000000000000000..f91197f00f7ae3a2e57b9c3c1861946705eaf3b3 GIT binary patch literal 63696 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