hamburger

主に日記

FlutterでCloudStorageを使ってみた

firebase.google.com

firebase.flutter.dev

目的

  • firestoreでテキストベースのデータ保存はできるようになったものの、最近のアプリは何かしらのメディアを利用することが多く、それのためのインフラが必要
  • cloud storageをメディア用のストアとして、アップロード・ダウンロードできるようになればそれなりのアプリを作れそう

やったこと

事前準備

  • firestoreと同様にセキュリティルールを設定した。認証ありの場合のみ許可
  • ローカルでのファイル選択のためにimage_pickerを、ファイル保存のためにpath_providerを利用した
  • 画像保存の権限取得のために、 permission_handlerを利用した

pub.dev

pub.dev

pub.dev

ファイルのRead

  1. アップロード済みの画像を画面に表示してみた。FutureBuilderで通信完了後に表示するようにした。
  2. ファイルアップロード後に違いがわかるように、ファイル数も表示させた
  FirebaseStorage storage = FirebaseStorage.instance;
  FutureBuilder(
              future: storage.ref("sample.jpeg").getDownloadURL(),
              builder:
                  (BuildContext context, AsyncSnapshot<String> asyncSnapshot) {
                if (asyncSnapshot.hasError) {
                  return Text("error occuered!!");
                }
                if (asyncSnapshot.hasData) {
                  return Image.network(asyncSnapshot.data!);
                }
                return Text("no data");
              },
            ),
FutureBuilder(
            future: storage.ref().listAll(),
            builder: (BuildContext context,
                AsyncSnapshot<ListResult> asyncSnapshot) {
              if (asyncSnapshot.hasError) {
                return Text("error occuered!!");
              }
              if (asyncSnapshot.hasData) {
                final length = asyncSnapshot.data?.items.length ?? 0;
                return Text("data length = $length");
              }
              return Text("no data");
            },
          ),

ファイルのアップロード

ローカル画像を選択して、適当なファイル名でアップロードしてみた

  String get fileName =>
      DateTime.now().microsecondsSinceEpoch.toString() + ".jpg";

  void _upload() async {
    final picker = ImagePicker();
    final pickerFile = await picker.pickImage(
      source: ImageSource.gallery,
    );
    if (pickerFile == null) {
      return;
    }
    File file = File(pickerFile.path);
    try {
      setState(() {
        _isLoading = true;
      });
      await storage.ref(fileName).putFile(file);
    } catch (e) {
      print(e);
    } finally {
      setState(() {
        _isLoading = false;
      });
    }
  

ファイルのダウンロード

特定のファイルを適当なファイル名でダウンロードしてみた


  Future<void> _download() async {
    var status = await Permission.storage.status;
    if (status == PermissionStatus.denied) {
      // 一度もリクエストしてないので権限のリクエスト.
      status = await Permission.storage.request();
    }
    Directory? appDocDir = await getExternalStorageDirectory();
    if (appDocDir == null) return;
    File downloadToFile = File(appDocDir.path + "/" + fileName);

    try {
      setState(() {
        _isLoading = true;
      });
      final ref = storage.ref('sample.jpeg');
      await ref.writeToFile(downloadToFile);
    } on FirebaseException catch (e) {
      print("error occured!");
    } finally {
      setState(() {
        _isLoading = false;
      });
    }

所感

  • それほど苦労なく使えたので助かった。アップロード処理が抽象化されているのは助かる
  • 実際にはテキストデータとファイルアップロードを同時に行ったり、それの圧縮処理も走らせてサムネ作ったりするので、CloudFunctionとの連携も視野に入れておきたい

github.com