Fazer upload de arquivos com o Cloud Storage no Flutter

Com o Cloud Storage para Firebase, é possível fazer upload de arquivos com rapidez e facilidade para um bucket do Cloud Storage fornecido e gerenciado pelo Firebase.

Fazer upload de arquivos

Para fazer upload de um arquivo para o Cloud Storage, primeiro crie uma referência ao caminho completo do arquivo, incluindo o nome dele.

// Create a storage reference from our app
final storageRef = FirebaseStorage.instance.ref();

// Create a reference to "mountains.jpg"
final mountainsRef = storageRef.child("mountains.jpg");

// Create a reference to 'images/mountains.jpg'
final mountainImagesRef = storageRef.child("images/mountains.jpg");

// While the file names are the same, the references point to different files
assert(mountainsRef.name == mountainImagesRef.name);
assert(mountainsRef.fullPath != mountainImagesRef.fullPath);

Depois de criar uma referência adequada, chame os métodos putFile(), putString() ou putData() para fazer upload do arquivo no Cloud Storage.

Não é possível fazer o upload de dados com uma referência à raiz do bucket do Google Cloud Storage. Sua referência precisa apontar para um URL filho.

Fazer upload usando um arquivo

Para fazer upload de um arquivo, primeiro é necessário o caminho absoluto para a localização dele no dispositivo. Por exemplo, se houver um arquivo no diretório de documentos do aplicativo, use o pacote oficial path_provider para gerar um caminho de arquivo e transmiti-lo para putFile():

Directory appDocDir = await getApplicationDocumentsDirectory();
String filePath = '${appDocDir.absolute}/file-to-upload.png';
File file = File(filePath);

try {
  await mountainsRef.putFile(file);
} on firebase_core.FirebaseException catch (e) {
  // ...
}

Fazer upload de uma string

É possível fazer o upload de dados como uma string bruta codificada base64, base64url ou data_url usando o método putString(). Por exemplo, para fazer upload de uma string de texto codificada como URL de dados, faça o seguinte:

String dataUrl = 'data:text/plain;base64,SGVsbG8sIFdvcmxkIQ==';

try {
  await mountainsRef.putString(dataUrl, format: PutStringFormat.dataUrl);
} on FirebaseException catch (e) {
  // ...
}

Como fazer upload de dados brutos

É possível fazer o upload de dados digitados de nível inferior na forma de Uint8List nos casos em que o upload de uma string ou File não é prático. Nesse caso, chame o método putData() com seus dados:

try {
  // Upload raw data.
  await mountainsRef.putData(data);
} on firebase_core.FirebaseException catch (e) {
  // ...
}

Gerar um URL de download

Depois de fazer upload de um arquivo, é possível gerar um URL para fazer o download dele chamando o método getDownloadUrl() no Reference:

await mountainsRef.getDownloadURL();

Adicionar metadados de arquivo

Você também pode incluir metadados ao fazer upload de arquivos. Em geral, esses metadados contêm propriedades típicas de metadados de arquivos, como contentType (frequentemente chamadas de tipo MIME). O método putFile() infere automaticamente o tipo MIME da extensão File, mas é possível substituir o tipo detectado automaticamente especificando contentType nos metadados. Se você não fornecer um contentType e o Cloud Storage não conseguir inferir um padrão pela extensão do arquivo, o Cloud Storage usará application/octet-stream. Consulte Usar metadados de arquivo.

try {
  await mountainsRef.putFile(file, SettableMetadata(
    contentType: "image/jpeg",
  ));
} on firebase_core.FirebaseException catch (e) {
  // ...
}

Gerenciar uploads

Além de iniciar os uploads, você pode pausar, retomar e cancelar uploads usando os métodos pause(), resume() e cancel(). Eventos de pausa e retomada provocam as mudanças de estado pause e progress, respectivamente. Cancelar um upload faz com que ele falhe com um erro indicando que o upload foi cancelado.

final task = mountainsRef.putFile(largeFile);

// Pause the upload.
bool paused = await task.pause();
print('paused, $paused');

// Resume the upload.
bool resumed = await task.resume();
print('resumed, $resumed');

// Cancel the upload.
bool canceled = await task.cancel();
print('canceled, $canceled');

Monitorar o andamento do upload

É possível detectar o streaming de eventos de uma tarefa para processar êxitos, falhas, progresso ou pausas na tarefa de upload:

Tipo de evento Uso típico
TaskState.running Emitido periodicamente à medida que os dados são transferidos e podem ser usados para preencher um indicador de upload/download.
TaskState.paused Enviado sempre que a tarefa é pausada.
TaskState.success Emitido quando a tarefa é concluída com sucesso.
TaskState.canceled Enviado sempre que a tarefa é cancelada.
TaskState.error Emitido em caso de falha no upload. Isso pode acontecer devido ao tempo limite da rede, falhas de autorização ou se você cancelar a tarefa.
mountainsRef.putFile(file).snapshotEvents.listen((taskSnapshot) {
  switch (taskSnapshot.state) {
    case TaskState.running:
      // ...
      break;
    case TaskState.paused:
      // ...
      break;
    case TaskState.success:
      // ...
      break;
    case TaskState.canceled:
      // ...
      break;
    case TaskState.error:
      // ...
      break;
  }
});

Tratamento de erros

Há diversos motivos pelos quais erros podem ocorrer, como arquivo não existente ou usuário sem permissão para fazer upload do arquivo desejado. Encontre mais informações sobre erros na seção Como lidar com erros da documentação.

Exemplo completo

Um exemplo completo de upload com monitoramento de andamento e tratamento de erros é mostrado abaixo:

final appDocDir = await getApplicationDocumentsDirectory();
final filePath = "${appDocDir.absolute}/path/to/mountains.jpg";
final file = File(filePath);

// Create the file metadata
final metadata = SettableMetadata(contentType: "image/jpeg");

// Create a reference to the Firebase Storage bucket
final storageRef = FirebaseStorage.instance.ref();

// Upload file and metadata to the path 'images/mountains.jpg'
final uploadTask = storageRef
    .child("images/path/to/mountains.jpg")
    .putFile(file, metadata);

// Listen for state changes, errors, and completion of the upload.
uploadTask.snapshotEvents.listen((TaskSnapshot taskSnapshot) {
  switch (taskSnapshot.state) {
    case TaskState.running:
      final progress =
          100.0 * (taskSnapshot.bytesTransferred / taskSnapshot.totalBytes);
      print("Upload is $progress% complete.");
      break;
    case TaskState.paused:
      print("Upload is paused.");
      break;
    case TaskState.canceled:
      print("Upload was canceled");
      break;
    case TaskState.error:
      // Handle unsuccessful uploads
      break;
    case TaskState.success:
      // Handle successful uploads on complete
      // ...
      break;
  }
});

Agora que você já sabe fazer upload de arquivos, veja como fazer o download no Cloud Storage.