Ionic 应用中的数据传导
Ionic 是一个移动应用框架,用于使用 Cordova 平台构建 iOS 和 Android 应用。
¥Ionic is a mobile app framework for building iOS and Android apps with the Cordova platform.
SheetJS 是一个用于从电子表格读取和写入数据的 JavaScript 库。
¥SheetJS is a JavaScript library for reading and writing data from spreadsheets.
该演示使用 Ionic 和 SheetJS 处理数据并生成电子表格。我们将探讨如何在 Ionic 应用中加载 SheetJS,并使用 Ionic API 和插件从设备上的电子表格文件中提取数据并向其中写入数据。
¥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 |
---|---|
该演示涵盖使用 Cordova 平台的 Ionic 应用。
¥This demo covers Ionic apps using the Cordova platform.
CapacitorJS 演示 涵盖 CapacitorJS 应用。
¥The CapacitorJS demo covers CapacitorJS apps.
本 demo 在以下环境下进行了测试:
¥This demo was tested in the following environments:
真实设备
¥Real Devices
OS | 设备 | 配置 | 日期 |
---|---|---|---|
安卓 30 | 英伟达盾 | A | 2024-05-30 |
iOS 15.1 | iPad Pro | A | 2024-05-30 |
模拟器
¥Simulators
OS | 设备 | 配置 | 开发平台 | 日期 |
---|---|---|---|---|
安卓 34 | 像素 3a | A | darwin-arm | 2024-05-30 |
iOS 17.5 | iPhone SE(第 3 代) | A | darwin-arm | 2024-05-30 |
Configurations (click to show)
Configuration A:
- Ionic:
@ionic/angular 8.2.0
,@ionic/angular-toolkit 11.0.1
- Cordova:
cordova-lib@12.0.1
,android 13.0.0, ios 7.1.0
- File Integration:
@awesome-cordova-plugins/file
version6.7.0
在开始此演示之前,请手动禁用遥测。在 Linux 和 MacOS 上:
¥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
SheetJS NodeJS 模块 可以从应用中的任何组件或脚本导入。
¥The SheetJS NodeJS Module can be imported from any component or script in the app.
内部状态
¥Internal State
"Angular" 演示 讨论了一些状态表示和预览策略。
¥The "Angular" demo discusses a number of state representations and preview strategies.
对于此演示,内部状态是 "数组的数组"[^1] (any[][]
):
¥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-grid
[^2] 是一个显示网格组件。Angular ngFor
指令 [^3] 简化了数组数组的迭代:
¥ion-grid
[^2] is a display grid component. The Angular ngFor
directive[^3]
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
cordova-plugin-file
插件在设备上读取和写入文件。
¥The cordova-plugin-file
plugin reads and writes files on devices.
对于 Android 30+,由于范围存储规则,标准文件模块会写入无法从文件应用访问的私有文件。
¥For Android 30+, due to scoped storage rules, the standard file module writes private files that cannot be accessed from the Files app.
必须使用存储访问框架插件来写入外部文件。
¥A Storage Access Framework plugin must be used to write external files.
@awesome-cordova-plugins/file
是一个专为 Ionic + Angular 应用设计的封装器。
¥@awesome-cordova-plugins/file
is a wrapper designed for Ionic + Angular apps.
@ionic-native
范围内的插件已被弃用。应使用 @awesome-cordova-plugins
范围内的社区模块。
¥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
从指定的 URL 读取文件数据并解析为 ArrayBuffer
对象。
¥this.file.readAsArrayBuffer
reads file data from a specified URL and resolves
to ArrayBuffer
objects.
这些对象可以使用 SheetJS read
方法 [^4] 进行解析。带有选项 header: 1
的 SheetJS sheet_to_json
方法 [^5] 生成一个可以分配给页面状态的数组数组:
¥These objects can be parsed with the SheetJS read
method[^4]. The SheetJS
sheet_to_json
method[^5] 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
将存储在 Blob
对象中的文件数据写入设备。
¥this.file.writeFile
writes file data stored in Blob
objects to the device.
SheetJS aoa_to_sheet
方法 [^6] 从数组的数组中生成一个工作表对象。book_new
和 book_append_sheet
辅助程序 [^7] 生成一个工作簿对象。带有选项 type: "array"
的 SheetJS write
方法 [^8] 将生成 ArrayBuffer
,从中可以创建 Blob
:
¥From the array of arrays, the SheetJS aoa_to_sheet
method[^6] generates a
worksheet object. The book_new
and book_append_sheet
helpers[^7] generate a
workbook object. The SheetJS write
method[^8] 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
此演示中的应用将在表格中显示数据。
¥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.
"导入数据" 将尝试从已知位置读取 SheetJSIonic.xlsx
。警报将显示预期位置。
¥"Import Data" will attempt to read SheetJSIonic.xlsx
from a known location. An
alert will display the expected location.
"导出数据" 将尝试将表数据导出到已知位置的 SheetJSIonic.xlsx
。写入后,警报将显示文件的位置。
¥"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
-
按照警告中的说明禁用遥测。
¥Disable telemetry as noted in the warning.
-
遵循 iOS 和 Android 开发的官方说明 [^9]。
¥Follow the official instructions for iOS and Android development[^9].
Installation Notes (click to show)
Ionic requires Java 17.
-
安装所需的全局依赖:
¥Install required global dependencies:
npm i -g cordova cordova-res @angular/cli native-run @ionic/cli
在某些系统中,必须以 root 用户身份运行该命令:
¥In some systems, the command must be run as the root user:
sudo npm i -g cordova cordova-res @angular/cli native-run @ionic/cli
基础项目
¥Base Project
-
创建一个新项目:
¥Create a new project:
ionic start SheetJSIonic blank --type angular --cordova --quiet --no-git --no-link --confirm
当要求选择 NgModules
或 Standalone Components
时,选择 NgModules
¥When asked to select NgModules
or Standalone Components
, select NgModules
如果提示要求确认使用 Cordova,请输入 Yes
继续。
¥If a prompt asks to confirm Cordova use, enter Yes
to continue.
如果提示询问是否创建 Ionic 账户,请输入 N
以选择退出。
¥If a prompt asks about creating an Ionic account, enter N
to opt out.
由于依赖树中的冲突,该命令在某些测试运行中失败。
¥Due to conflicts in the dependency tree, the command failed in some test runs.
如果包安装失败,请强制安装所有模块:
¥If the package installation fails, forcefully install all modules:
cd SheetJSIonic
npm i --force @angular/cli
npm i --force
cd ..
-
设置科尔多瓦:
¥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
如果在平台之前添加 cordova-plugin-file
,安装可能会失败:
¥If cordova-plugin-file
is added before the platforms, installation may fail:
CordovaError: Could not load API for ios project
这可以通过删除并重新安装 ios
平台来解决:
¥This can be resolved by removing and reinstalling the ios
platform:
ionic cordova platform rm ios
ionic cordova platform add ios --confirm
如果 npm i
步骤由于 rxjs
解析而失败,请将高亮的行添加到 package.json
以强制解析:
¥If the npm i
step fails due to rxjs
resolution, add the highlighted lines
to package.json
to force a resolution:
"private": true,
"overrides": {
"rxjs": "~7.5.0"
},
"dependencies": {
请注意,错误日志中将显示所需的 rxjs
版本。
¥Note that the required rxjs
version will be displayed in the error log.
添加这些行后,npm i
命令将成功。
¥After adding the lines, the npm i
command will succeed.
-
安装依赖:
¥Install dependencies:
npm i --save https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz
-
将
@awesome-cordova-plugins/file
添加到模块中。下面高亮差异:¥Add
@awesome-cordova-plugins/file
to the module. Differences highlighted below:
import { AppComponent } from './app.component';
import { AppRoutingModule } from './app-routing.module';
import { File } from '@awesome-cordova-plugins/file/ngx';
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule, IonicModule.forRoot(), AppRoutingModule],
providers: [File, { provide: RouteReuseStrategy, useClass: IonicRouteStrategy }],
bootstrap: [AppComponent],
})
export class AppModule {}
-
下载
home.page.ts
并替换:¥Download
home.page.ts
and replace:
curl -o src/app/home/home.page.ts -L https://xlsx.nodejs.cn/ionic/home.page.ts
iOS
-
启用文件共享并使文档文件夹在 iOS 应用中可见。将以下行添加到
platforms/ios/SheetJSIonic/SheetJSIonic-Info.plist
:¥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>
<key>UIFileSharingEnabled</key>
<true/>
<key>LSSupportsOpeningDocumentsInPlace</key>
<true/>
<key>CFBundleDevelopmentRegion</key>
(文档的根元素是 plist
,它包含一个 dict
子元素)
¥(The root element of the document is plist
and it contains one dict
child)
-
构建应用并启动模拟器
¥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.
在某些测试运行中,cordova build ios --emulator
步骤失败并出现错误:
¥In some test runs, the cordova build ios --emulator
step failed with error:
> cordova build ios --emulator
Could not load API for ios project
通过强制安装 cordova-ios
解决了这个问题:
¥This was resolved by forcefully installing cordova-ios
:
npm i --save cordova-ios
在最近的测试中,native-run ios
命令失败并显示
¥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
检查 platforms/ios/build/
,实际文件夹名称是:
¥Inspecting platforms/ios/build/
, the actual folder name was:
% ls platforms/ios/build
Debug-iphonesimulator
iOS 模拟器可以手动启动:
¥The iOS simulator can be launched manually:
native-run ios --app platforms/ios/build/Debug-iphonesimulator/SheetJSIonic.app --virtual
在某些测试中,emulate
命令失败并显示:
¥In some tests, the emulate
command failed with:
Error: Unknown argument: platform
[ERROR] An error occurred while running subprocess ng.
ng run app:ionic-cordova-build --platform=ios exited with exit code 1.
修复方法是手动添加 @ionic/cordova-builders
:
¥The fix is to manually add @ionic/cordova-builders
:
ng add @ionic/cordova-builders
安卓
¥Android
-
在 Android 应用中启用文件读写。
¥Enable file reading and writing in the Android app.
编辑 platforms/android/app/src/main/AndroidManifest.xml
并在 application
标记之前添加以下两行:
¥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"/>
在 application
标签中,添加属性 android:requestLegacyExternalStorage="true"
。
¥In the application
tag, add the attribute android:requestLegacyExternalStorage="true"
.
-
构建应用并启动模拟器
¥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.
在某些测试运行中,cordova build android --emulator
步骤失败并出现错误:
¥In some test runs, cordova build android --emulator
step failed with error:
Could not find or parse valid build output file
通过强制安装 cordova-android
解决了这个问题:
¥This was resolved by forcefully installing cordova-android
:
npm i --save cordova-android
在某些测试中,构建失败并出现 Gradle 错误:
¥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
在 macOS 上,通过使用 Homebrew 管理器安装 gradle 解决了此问题:
¥On macOS, this issue was resolved by installing gradle with Homebrew manager:
brew install gradle
上次在 Android 上测试演示时,读取文件按预期工作。但是,生成的文件在“文件”应用中无法从外部看到。
¥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.
这是 Android SDK 33 和底层文件插件的一个已知错误!
¥This is a known bug with Android SDK 33 and the underlying file plugins!
[^1]: 见 API 参考中的 "数组的数组"
¥See "Array of Arrays" in the API reference
[^2]: 请参阅 Ionic 文档中的 ion-grid
。
¥See ion-grid
in the Ionic documentation.
[^3]: 请参阅 Angular 文档中的 ngFor
。
¥See ngFor
in the Angular documentation.
[^4]: 见 read
于 "读取文件"
[^5]: 见 "数组输出" 于 "实用函数"
¥See "Array Output" in "Utility Functions"
[^6]: 见 aoa_to_sheet
于 "实用工具"
¥See aoa_to_sheet
in "Utilities"
[^7]: 有关 book_new
和 book_append_sheet
的详细信息,请参阅 "工作簿助手" 于 "实用工具"。
¥See "Workbook Helpers" in "Utilities" for details on book_new
and book_append_sheet
.
[^8]: 见 write
于 "写入文件"
[^9]: 查看 "为 iOS 开发" 和 "为 Android 开发"。Ionic 团队从官方文档站点中删除了这些页面,并推荐 vercel.app
文档站点。
¥See "Developing for iOS" and "Developing for Android". The Ionic team removed these pages from the official docs site and recommend the vercel.app
docs site.
[^10]: 请参阅 JDK 存档 for Java 17 JDK 下载链接。
¥See the JDK Archive for Java 17 JDK download links.