📥

【Flutter】katana_modelの様にシステムを簡単に切り替えることが可能なファイルストレージパッケージ

2023/01/17に公開

こんにちは。広瀬マサルです。

後々リリース予定の総合フレームワークのために利用されるパッケージをいくつか紹介します。

今回はファイルストレージ周りのパッケージとなります。

Cloud Storage for Firebaseを後々利用するためのテスト用のパッケージとなります。

使い方をまとめたので興味ある方はぜひ使ってみてください!

katana_storage

https://pub.dev/packages/katana_storage

はじめに

画像ファイルを代表したファイルをアップロードする機能は様々なアプリで利用されます。

SNSやマッチングアプリなど画像ファイルをアップロードすることでコミュニケーションを円滑にすることが可能です。

ファイルをアップロードしてアプリで利用可能にするクラウドサービスは数多くありますが、Flutterを利用しかつFirestoreなどを利用している場合はCloud Storage for Firebaseを利用することが最も適しているかと思います。

このパッケージではkatana_modelで実装したときと同じ様にアダプターを利用してFirebaseやローカルでのファイルストレージを切り替えることが可能になるようなパッケージを実装しました。

インストール

下記パッケージをインポートします。

flutter pub add katana_storage

Cloud Storage for Firebaseを利用する場合は下記のパッケージを合わせてインポートします。

flutter pub add katana_storage_firebase

実装

事前準備

必ずStorageAdapterScopeのWidgetをアプリのルート近くに配置します。

adapterのパラメーターにLocalStorageAdapterといったStorageAdapterを渡します。

// main.dart
import 'package:flutter/material.dart';
import 'package:katana_storage/katana_storage.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    return StorageAdapterScope(
      adapter: const LocalStorageAdapter(),
      child: MaterialApp(
        home: const StoragePage(),
        title: "Flutter Demo",
        theme: ThemeData(
          primarySwatch: Colors.blue,
        ),
      ),
    );
  }
}

ストレージオブジェクトの作成

まず、ファイル1つにつき1つのStorageオブジェクトを作成します。

作成時にリモート側の相対パスを記述したStorageQueryを渡します。

StorageオブジェクトはChangeNotifierを継承しているので、addListenerやriverpodのChangeNotifierProviderなどを合わせて利用し状態を監視することができます。

final storage = Storage(const StorageQuery("test/file"));
class StoragePage extends StatefulWidget {
  const StoragePage({super.key});

  
  State<StatefulWidget> createState() => StoragePageState();
}

class StoragePageState extends State<StoragePage> {
  final storage = Storage(const StorageQuery("test/file"));
  final controller = TextEditingController();

  
  void initState() {
    super.initState();
    storage.addListener(_handledOnUpdate);
  }

  void _handledOnUpdate() {
    setState(() {});
  }

  
  void dispose() {
    super.dispose();
    storage.removeListener(_handledOnUpdate);
    storage.dispose();
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("App Demo")),
      body: TextField(
        controller: controller,
        expands: true,
        textAlignVertical: TextAlignVertical.top,
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () async {
          final text = controller.text;
          final bytes = Uint8List.fromList(text.codeUnits);
          await storage.uploadWithBytes(bytes);
        },
        child: const Icon(Icons.upload_file),
      ),
    );
  }
}

アップロード

アップロードを行うには下記のメソッドが利用可能です。

  • upload:ローカルにあるファイルパスを指定してアップロード。
  • uploadWithBytes:バイトデータを渡して直接アップロード。

戻り値にStorageValueが渡されます。ここにアップロードしたファイルのリモートのフルパスが格納されています。

final bytes = Uint8List.fromList(text.codeUnits);
final storageValue = await storage.uploadWithBytes(bytes);
print("Remote path is: ${storageValue.remote.path}");

ダウンロード

すでにストレージにアップロードされているファイルをダウンロードするにはdownloadのメソッドを利用します。

引数にローカルに保存するファイルの相対パスを指定することも可能です。

戻り値にStorageValueが渡され、ここにダウンロードしたファイルのローカルのフルパスやファイルの実データが格納されています。

ローカルファイルへの保存はWebでは対応していません。

final bytes = Uint8List.fromList(text.codeUnits);
final storageValue = await storage.download("file.jpg");
print("Local path is: ${storageValue.local.path}");
print("Local data is: ${storageValue.local.bytes}");

StorageAdapter

StorageAdapterScopeを定義する際に渡すことでストレージのシステムを変更することが可能です。

  • RuntimeStorageAdapter:アプリのメモリ上のみにデータがアップロードされます。実際には保存されません。テスト時に利用してください。
  • LocalStorageAdapter:端末のローカルにファイルを保存するためのストレージアダプター。downloadやuploadにおけるローカルリモートはどちらも端末内にあることに注意してください。画面モックを実装する際に便利です。Webでは利用できません。
  • FirebaseStorageAdapter:Cloud Storage for Firebaseを利用するストレージアダプター。アプリ間で利用可能です。Firebaseの初期設定が必要です。

おわりに

自分で使う用途で作ったものですが実装の思想的に合ってそうならぜひぜひ使ってみてください!

また、こちらにソースを公開しているのでissueやPullRequestをお待ちしてます!

また仕事の依頼等ございましたら、私のTwitterWebサイトで直接ご連絡をお願いいたします!

https://mathru.net/ja/contact

GitHub Sponsors

スポンサーを随時募集してます。ご支援お待ちしております!

https://github.com/sponsors/mathrunet

Discussion