目的
- firestoreでテキストベースのデータ保存はできるようになったものの、最近のアプリは何かしらのメディアを利用することが多く、それのためのインフラが必要
- cloud storageをメディア用のストアとして、アップロード・ダウンロードできるようになればそれなりのアプリを作れそう
やったこと
事前準備
- firestoreと同様にセキュリティルールを設定した。認証ありの場合のみ許可
- ローカルでのファイル選択のために
image_picker
を、ファイル保存のためにpath_provider
を利用した - 画像保存の権限取得のために、
permission_handler
を利用した
ファイルのRead
- アップロード済みの画像を画面に表示してみた。
FutureBuilder
で通信完了後に表示するようにした。 - ファイルアップロード後に違いがわかるように、ファイル数も表示させた
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との連携も視野に入れておきたい