docs.sheetjs.com/docz/docs/03-demos/05-mobile/06-flutter.md
2023-06-01 00:47:33 -04:00

5.6 KiB

title pagination_prev pagination_next sidebar_position sidebar_custom_props
Flutter demos/static/index demos/desktop/index 5
summary
Dart + JS Interop

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

Dart + Flutter is a cross-platform alternative to JS + React Native.

For the iOS and Android targets, the flutter_js package wraps JavaScriptCore and QuickJS engines respectively.

The Standalone scripts can be parsed and evaluated in the wrapped engines.

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

iOS

iOS screenshot

:::warning Telemetry

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

dart --disable-telemetry
dart --disable-analytics
flutter config --no-analytics
flutter config --disable-telemetry

:::

Integration Details

This demo assumes familiarity with Dart and Flutter.

Loading SheetJS

Adding the scripts

The flutter.assets property in pubspec.yaml specifies assets. Assuming the standalone script and shim are placed in the scripts folder, the following snippet loads the scripts as assets:

flutter:
  assets:
    - scripts/xlsx.full.min.js
    - scripts/shim.min.js

Once loaded, the contents can be loaded with rootBundle.loadString:

import 'package:flutter/services.dart' show rootBundle;

String shim = await rootBundle.loadString("scripts/shim.min.js");
String sheetjs = await rootBundle.loadString("scripts/xlsx.full.min.js");

Initialization

It is strongly recommended to add the engine to the state of a StatefulWidget:

import 'package:flutter_js/flutter_js.dart';

class SheetJSFlutterState extends State<SheetJSFlutter> {
  // highlight-next-line
  late JavascriptRuntime _engine;

  @override void initState() {
    // highlight-next-line
    _engine = getJavascriptRuntime();
  }
}

Running SheetJS Scripts

Since fetching assets is asychronous, it is recommended to create a wrapper async function and sequentially await each script:

class SheetJSFlutterState extends State<SheetJSFlutter> {
  String _version = '0.0.0';

  @override void initState() {
    _engine = getJavascriptRuntime();
    _initEngine(); // note: this is not `await`-ed
  }

  Future<void> _initEngine() async {
    /* fetch and evaluate the shim */
    String shim = await rootBundle.loadString("scripts/shim.min.js");
    _engine.evaluate(shim);
    // highlight-start
    /* fetch and evaluate the main script */
    String sheetjs = await rootBundle.loadString("scripts/xlsx.full.min.js");
    _engine.evaluate(sheetjs);
    // highlight-end
    /* capture the version string */
    JsEvalResult vers = _engine.evaluate("XLSX.version");
    setState(() => _version = vers.stringResult);
  }
}

Reading data

The most common binary data type in Dart is Uint8List. It is the data type for http.Response#bodyBytes and the return type of File#readAsBytes().

The Flutter JS connector offers no simple interop for Uint8List data. The data should be converted to Base64 before parsing.

The csv package provides a special CsvToListConverter converter to generate List<List<dynamic>> (Dart's spiritual equivalent of the array of arrays):

import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:csv/csv.dart';

class SheetJSFlutterState extends State<SheetJSFlutter> {
  List<List<dynamic>> _data = [];

  void _processBytes(Uint8List bytes) {
    String base64 = base64Encode(bytes);
    JsEvalResult func = _engine.evaluate("""
      var wb = XLSX.read('$base64');
      XLSX.utils.sheet_to_csv(wb.Sheets[wb.SheetNames[0]]);
    """);
    String csv = func.stringResult;
    setState(() { _data = CsvToListConverter(eol: "\n").convert(csv); });
  }

Demo

:::note

This demo was tested on an Intel Mac on 2023 May 31 with Flutter 3.10.2, Dart 3.0.2, and flutter_js 0.7.0

The iOS simulator runs iOS 16.2 on an iPhone 14 Pro Max.

:::

Base Project

  1. Disable telemetry.
dart --disable-telemetry
dart --disable-analytics
flutter config --no-analytics
flutter config --disable-telemetry
  1. Create a new Flutter project:
flutter create sheetjs_flutter
cd sheetjs_flutter
  1. Open the iOS simulator

  2. While the iOS simulator is open, start the application:

flutter run

Once the app loads in the simulator, stop the terminal process.

  1. Install Flutter / Dart dependencies:
flutter pub add http csv flutter_js
  1. Open pubspec.yaml with a text editor. Search for the line that starts with flutter: (no whitespace) and add the highlighted lines:
# The following section is specific to Flutter packages.
flutter:
// highlight-start
  assets:
    - scripts/xlsx.full.min.js
    - scripts/shim.min.js
// highlight-end
  1. Download dependencies to the scripts folder:

{\ mkdir -p scripts cd scripts curl -LO https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js curl -LO https://cdn.sheetjs.com/xlsx-${current}/package/dist/shim.min.js cd ..}

  1. Download main.dart to lib/main.dart:
curl -L -o lib/main.dart https://docs.sheetjs.com/flutter/main.dart
  1. Launch the app:
flutter run

The app fetches https://sheetjs.com/pres.numbers, parses, converts data to an array of arrays, and presents the data in a Flutter Table widget.