🦖

ピュアDart / Flutter で Excel ファイルを生成・保存する

2021/10/24に公開

エクセルの写真
photo from Unsplash/@impelling

excelライブラリpath_providerライブラリを使用してエクセルファイルを生成、保存する方法です。

エクセルファイルの生成
エクセルファイルの生成

(使用バージョン)
excel: ^2.0.0-null-safety-3
path_provider: ^2.0.5

ピュアDart (Macのみ検証)

import 'dart:io';

import 'package:excel/excel.dart';

void main() {
  // OSのユーザー名を入れる
  const user = 'user'; 
  const fileName = 'test';
  // Macの場合
  const path = '/Users/$user/Desktop/$fileName.xlsx';

  // 1.
  final Excel excel = Excel.createExcel();
  final Sheet sheet1 = excel['Sheet1'];
  final Data cell = sheet1.cell(
    CellIndex.indexByColumnRow(columnIndex: 0, rowIndex: 0),
  );
  cell.value = 'アイウエオ';

  // 2.
  final List<int>? bytes = excel.encode();
  if (bytes != null) {
    File(path)
      ..createSync(recursive: true)
      ..writeAsBytesSync(bytes);
  }
}

1. エクセルオブジェクトの生成とセルデータの設定

Excel.createExcel() でExcelオブジェクトを生成します。

Excelオブジェクトは [ ] オペレーター が定義されており、シート名の文字列を指定することでSheetオブジェクトを取得できます。

Sheetオブジェクトの cellメソッド はDataオブジェクトを返します。

Dataオブジェクトはセルの値、スタイル、セルの種類(文字、数字、日付など)、番地などの情報をプロパティとして持ちます。

2. エクセルオブジェクトのデータ化とファイル生成

Excel().encode() でエクセルオブジェクトを dart:io の File に書き込める形式(バイト配列)に変換します。

File().createSync() でファイル生成、
File().writeAsBytesSync() でファイルにデータを書き込みます。

createSyncのrecursiveがtrueの場合はディレクトリが存在しない場合に生成します。

Flutter (Web, iOS, macOS, Androidのエミュレーターで検証)

class MyHomePage extends StatelessWidget {
  const MyHomePage({Key? key}) : super(key: key);

  void _create() async {
    final Excel excel = Excel.createExcel();
    final Sheet sheet1 = excel['Sheet1'];
    final CellStyle cellStyle = CellStyle(
      bold: true,
      underline: Underline.Double,
      fontSize: 100,
      fontColorHex: '#FF0000',
      backgroundColorHex: '#FFFF00',
    );

    final Data cell = sheet1.cell(CellIndex.indexByString('A1'));
    cell.cellStyle = cellStyle;
    cell.value = 'あいうえお';

    const fileName = 'test.xlsx';
    // 1. Flutter Web
    final List<int>? fileBytes = excel.save(fileName: fileName);

    // Web対応だけなら以降必要なし
    if (!kIsWeb && fileBytes != null) {
      late final String? path;
      if (defaultTargetPlatform == TargetPlatform.android) {
        // 2. Android
        path = '/storage/emulated/0/Download';
      } else if (defaultTargetPlatform == TargetPlatform.iOS) {
        // 3. iOS
        path = (await getApplicationDocumentsDirectory()).path;
      } else if (defaultTargetPlatform == TargetPlatform.macOS) {
        // 4. macOS
        path = (await getDownloadsDirectory())?.path;
      }
      if (path != null) {
        File('$path/$fileName')
          ..createSync(recursive: true)
          ..writeAsBytesSync(fileBytes);
      }
    }
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: ElevatedButton(
          child: const Text('create'),
          onPressed: _create,
        ),
      ),
    );
  }
}

1. Webの場合

Excel().save() を実行することで生成したデータをダウンロードします。Webだけに対応させる場合は以降の処理は必要ないです。

Web以外でも対応させる場合は、ファイル保存の処理に使うためにsaveメソッドが返すバイト配列を変数に保存しておきます。

2. Androidの場合 (APIレベル30と31で検証)

ここではpath_providerを使わずに、ファイルアプリの 「ダウンロード」フォルダ へのパスを直接指定しています。このフォルダにファイルを保存する場合は特別な設定は必要ないようです。

path_providerの getExternalStorageDirectory() を使っても良かったのですが、階層が深くなってユーザー目線的に不便かなと思いこのようにしています。

3. iOSの場合 (14.5で検証)

path_providerの getApplicationDocumentsDirectory() を使用。「ファイル」アプリからこのドキュメントフォルダへアクセスするには Info.plist で次のように指定する必要があります(参考)。

iOS > Runner 内の Info.plist
<plist version="1.0">
<dict>
//(省略)
	<key>UISupportsDocumentBrowser</key>
	<true/>
</dict>
</plist>

ファイルアプリ
ファイルアプリ

4. macOSの場合 (Big Surで検証)

path_providerの getDownloadsDirectory() を使用。entitlementsファイルを次のように指定して、書き込み許可を与える必要があります(参考)。

macOS > Runner 内の entitlementsファイル
<plist version="1.0">
<dict>
//(省略)
	<key>com.apple.security.files.downloads.read-write</key>
	<true/>
</dict>
</plist>

Flutterで作成するmacOSアプリはデフォルトでサンドボックス化されているとのことで、アプリ自身が読み書きできるフォルダは制限されているようです。

(参考)
https://flutter.dev/desktop#entitlements-and-the-app-sandbox
https://developer.apple.com/documentation/security/app_sandbox

最後に

Flutterにおけるエクセルファイル関連のライブラリはこちらも人気です。
https://pub.dev/packages/syncfusion_flutter_xlsio

excelライブラリより高機能みたいなのですが、ピュアDartでは使えないみたいなので今回は使用しませんでした。

syncfusion_flutter_xlsio を使うにはSyncfusion社のコミュニティライセンスが必要みたいです(一定規模の開発でのライセンス取得は無料)が、ライブラリの使用にあたりライセンスキーの入力などは必要ありません

Discussion