(Flutter-기초 강의) 21. Firebase Storage 사용하기: File 저장 

Firebase Storage 소개

개요

Firebase Storage는 구글의 Firebase 플랫폼에 속하는 강력한 클라우드 기반 파일 저장 서비스입니다.

이 서비스는 앱 개발자들이 사용자로부터 받은 사진, 동영상, 오디오 파일과 같은 대용량 파일을 안전하고 효율적으로 저장하고 관리할 수 있도록 설계되었습니다.

Firebase Storage는 Google Cloud Storage 위에 구축되어, Google의 클라우드 인프라의 확장성과 보안성을 그대로 활용할 수 있습니다.

firebase-storage-intro

주요 특징

  • 확장성:
    • 사용자의 증가나 데이터의 증가에 따라 자동으로 확장되므로, 어떤 규모의 프로젝트에도 적합합니다.
  • 보안:
    • Firebase Authentication과 함께 사용하면 사용자 인증 정보에 따라 파일 접근을 제어할 수 있어, 강력한 보안 체계를 구축할 수 있습니다.
  • 효율적인 데이터 전송:
    • 네트워크 상태가 불안정하거나 변동적인 환경에서도 데이터 전송이 중단되었을 경우, 이어서 전송할 수 있는 기능을 제공합니다.
  • 통합 개발 환경:
    • Firebase의 다른 서비스들과의 뛰어난 통합성을 자랑하여, 애널리틱스, 데이터베이스, 인증 등 다양한 기능을 함께 사용하여 앱 개발의 효율성을 높일 수 있습니다.

앞선 Firebase 포스팅들

Firebase Storage SDK 소개

Firebase Storage SDK는 Flutter, Android, iOS, Web 등 다양한 플랫폼에서 Firebase Storage 서비스를 사용할 수 있도록 제공하는 라이브러리입니다.

각 플랫폼마다 SDK의 구체적인 구현은 다르지만, 기본적인 기능은 비슷합니다.

주요 클래스

  • FirebaseStorage: 
    • Firebase Storage 서비스의 진입점입니다.
    • 이 클래스를 통해 스토리지 인스턴스를 관리할 수 있습니다.
    • FirebaseStorage.instance를 사용하여 인스턴스에 접근할 수 있습니다.
  • StorageReference: 
    • 저장된 파일을 참조하는 객체입니다.
    • 파일 경로를 나타내며, 파일 업로드, 다운로드, 메타데이터 조회 및 삭제 작업을 수행할 수 있습니다.
    • FirebaseStorage 인스턴스에서 ref() 함수를 호출하여 생성할 수 있습니다.
  • UploadTask: 
    • 파일 업로드를 비동기적으로 처리하는 작업입니다.
    • putFile, putData, putBlob 함수를 통해 업로드 작업을 시작할 수 있으며, 업로드 상태를 모니터링하고 결과를 처리할 수 있습니다.
  • DownloadTask: 
    • 파일 다운로드 작업을 비동기적으로 처리합니다.
    • StorageReferencewriteToFile 또는 getData 메서드를 사용하여 다운로드 작업을 시작할 수 있습니다.
  • TaskSnapshot:
    • 업로드 또는 다운로드 작업의 상태와 결과를 포함합니다.
    • 작업이 완료된 후, 이 클래스의 인스턴스를 통해 작업 결과에 접근할 수 있습니다.

주요 함수

  • uploadFile(): 
    • 파일을 업로드합니다.
import 'package:firebase_storage/firebase_storage.dart';

// Create Firebase Storage Instance
final storage = FirebaseStorage.instance;

// 파일 업로드
Future<void> uploadFile(String filePath, String fileName) async {
  // Create reference object
  final ref = storage.ref().child(fileName);

  // Upload File
  final task = ref.putFile(File(filePath));

  // Check Progress
  task.snapshotEvents.listen((snapshot) {
    print('Progress: ${snapshot.bytesTransferred} / ${snapshot.totalBytes}');
  });

  // Complete
  await task.whenComplete(() => print('Upload complete'));
}

// Use Example
uploadFile('path/to/image.jpg', 'image.jpg');
  • downloadFile(): 
    • 파일을 다운로드합니다.
// Download File
Future<void> downloadFile(String fileName) async {
  // Create Object
  final ref = storage.ref().child(fileName);

  // Download file
  final task = ref.writeToFile(File('path/to/file'));

  // Check download progress
  task.snapshotEvents.listen((snapshot) {
    print('Progress: ${snapshot.bytesTransferred} / ${snapshot.totalBytes}');
  });

  // Complete download
  await task.whenComplete(() => print('Download complete'));
}

// Use Example
downloadFile('image.jpg');
  • getDownloadURL(): 
    • 파일의 다운로드 URL을 가져옵니다.
// Get File URL
Future<String> getFileUrl(String fileName) async {
  // Create reference object
  final ref = storage.ref().child(fileName);

  // Get Download URL
  final url = await ref.getDownloadURL();

  return url;
}

// Use Example
final url = await getFileUrl('image.jpg');
print(url);
  • deleteFile(): 
    • 파일을 삭제합니다.
// Delete File
Future<void> deleteFile(String fileName) async {
  // Create reference object
  final ref = storage.ref().child(fileName);

  // Delete File
  await ref.delete();

  print('File deleted');
}

// Use Example
deleteFile('image.jpg');
  • listAll(): 
    • 버킷에 저장된 모든 파일 목록을 가져옵니다.
// Get All File List Stored in the bucket
Future<List<StorageReference>> listAll() async {
  // Create reference object
  final ref = storage.ref();

  // Get All File list
  final list = await ref.listAll();

  // List up all files
  for (final item in list.items) {
    print('File: ${item.name}');
  }

  return list.items;
}

// Use Example
listAll();
  • list(): 
    • 버킷에 저장된 파일 목록을 쿼리합니다.
// Query file list stored in the bucket
Future<List<StorageReference>> list() async {
  // Create reference object
  final ref = storage.ref();

  // Setting query param
  final query = Query.orderBy('name');

  // query to get list
  final list = await ref.list(query);

  // display items
  for (final item in list.items) {
    print('File: ${item.name}');
  }

  return list.items;
}

// Use example
list();

사용하기

본 예제는 앞선 포스팅 예제에서 사용하던 _7_firebase 프로젝트에 이어서 사용합니다.

1. Console에서 Storage 서비스 활성화

firebase console에서 Storage 섹션으로 이동합니다.

[Build] -> [Storage] -> (Get Started) 를 클릭후 인증 방법 및 생성할 Location을 설정합니다.

2. Firebase Storage 사용을 위한 패키지 설치

Firebase Storage를 사용하기 위한 패키지들을 추가합니다.

$ flutter pub add firebase_core firebase_storage

사용하고자 하는 곳에 다음을 import 합니다.

import 'package:firebase_storage/firebase_storage.dart';

3. Memo 파일 생성

MemoDetailPage에서 Memo를 파일 형태로 만들기 위해 path_provider 패키지를 추가합니다.

$ flutter pub add path_provider

path_provider패키지를 import합니다.

import 'package:path_provider/path_provider.dart';

Application Document 폴더에 Memo의 Title과 Contents를 파일형태로 저장하는 함수를 정의합니다.

  Future<File> _writeMemoToLocalFile(String fileName, String content) async {
    final directory = await getApplicationDocumentsDirectory();
    final file = File('${directory.path}/$fileName');

    // Write the file (File Name and Content)
    final fileContent = 'Title: $fileName\n\nContents: $content';
    return file.writeAsString(fileContent);
  }

4. Memo 파일 저장 및 업로드

앞서 정의한 _writeMemoToLocalFile() 를 이용하여, 파일 형태로 저장하고,

FirebaseStorage.instance.ref()를 이용하여 Firebase Storage 서비스에 putFile()를 이용해 업로드 하는 함수를 정의합니다.

위 동작의 결과를 ScaffoldMessagershowSnackBar()를 통해 표시합니다.

  Future<void> saveMemoToFileAndUpload() async {
    final dateTime = DateTime.now();
    final fileName = '${dateTime.toIso8601String()}_memo.txt';
    final localFile =
        await _writeMemoToLocalFile(fileName, widget.memo.content);

    try {
      await FirebaseStorage.instance.ref('memos/$fileName').putFile(localFile);
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(content: Text('Save memo as file and upload success!')),
      );
    } catch (e) {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('Error occured: $e')),
      );
    }
  }

Floating Button을 클릭하여 위 함수를 수행합니다.

      floatingActionButton: FloatingActionButton(
        onPressed: () {
          saveMemoToFileAndUpload();
        },
        child: const Icon(Icons.save_alt),
      ),

결과

example_firebase_storage_result
example_firebase_storage_console

참고 링크

Leave a Comment