Faça upload de arquivos com Cloud Storage no Android

O Cloud Storage para Firebase permite fazer upload de arquivos de forma rápida e fácil 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 do arquivo.

Kotlin+KTX

// Create a storage reference from our app
val storageRef = storage.reference

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

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

// While the file names are the same, the references point to different files
mountainsRef.name == mountainImagesRef.name // true
mountainsRef.path == mountainImagesRef.path // false

Java

// Create a storage reference from our app
StorageReference storageRef = storage.getReference();

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

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

// While the file names are the same, the references point to different files
mountainsRef.getName().equals(mountainImagesRef.getName());    // true
mountainsRef.getPath().equals(mountainImagesRef.getPath());    // false

Depois de criar uma referência apropriada, chame o método putBytes() , putFile() ou putStream() para fazer upload do arquivo para o Cloud Storage.

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

Upload de dados na memória

O método putBytes() é a maneira mais simples de fazer upload de um arquivo para o Cloud Storage. putBytes() pega um byte[] e retorna um UploadTask que você pode usar para gerenciar e monitorar o status do upload.

Kotlin+KTX

// Get the data from an ImageView as bytes
imageView.isDrawingCacheEnabled = true
imageView.buildDrawingCache()
val bitmap = (imageView.drawable as BitmapDrawable).bitmap
val baos = ByteArrayOutputStream()
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos)
val data = baos.toByteArray()

var uploadTask = mountainsRef.putBytes(data)
uploadTask.addOnFailureListener {
    // Handle unsuccessful uploads
}.addOnSuccessListener { taskSnapshot ->
    // taskSnapshot.metadata contains file metadata such as size, content-type, etc.
    // ...
}

Java

// Get the data from an ImageView as bytes
imageView.setDrawingCacheEnabled(true);
imageView.buildDrawingCache();
Bitmap bitmap = ((BitmapDrawable) imageView.getDrawable()).getBitmap();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
byte[] data = baos.toByteArray();

UploadTask uploadTask = mountainsRef.putBytes(data);
uploadTask.addOnFailureListener(new OnFailureListener() {
    @Override
    public void onFailure(@NonNull Exception exception) {
        // Handle unsuccessful uploads
    }
}).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
    @Override
    public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
        // taskSnapshot.getMetadata() contains file metadata such as size, content-type, etc.
        // ...
    }
});

Como putBytes() aceita byte[] , é necessário que seu aplicativo mantenha todo o conteúdo de um arquivo na memória de uma só vez. Considere usar putStream() ou putFile() para usar menos memória.

Fazer upload de um stream

O método putStream() é a maneira mais versátil de fazer upload de um arquivo para o Cloud Storage. putStream() pega um InputStream e retorna um UploadTask que você pode usar para gerenciar e monitorar o status do upload.

Kotlin+KTX

val stream = FileInputStream(File("path/to/images/rivers.jpg"))

uploadTask = mountainsRef.putStream(stream)
uploadTask.addOnFailureListener {
    // Handle unsuccessful uploads
}.addOnSuccessListener { taskSnapshot ->
    // taskSnapshot.metadata contains file metadata such as size, content-type, etc.
    // ...
}

Java

InputStream stream = new FileInputStream(new File("path/to/images/rivers.jpg"));

uploadTask = mountainsRef.putStream(stream);
uploadTask.addOnFailureListener(new OnFailureListener() {
    @Override
    public void onFailure(@NonNull Exception exception) {
        // Handle unsuccessful uploads
    }
}).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
    @Override
    public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
        // taskSnapshot.getMetadata() contains file metadata such as size, content-type, etc.
        // ...
    }
});

Carregar de um arquivo local

Você pode fazer upload de arquivos locais no dispositivo, como fotos e vídeos da câmera, com o método putFile() . putFile() pega um File e retorna um UploadTask que você pode usar para gerenciar e monitorar o status do upload.

Kotlin+KTX

var file = Uri.fromFile(File("path/to/images/rivers.jpg"))
val riversRef = storageRef.child("images/${file.lastPathSegment}")
uploadTask = riversRef.putFile(file)

// Register observers to listen for when the download is done or if it fails
uploadTask.addOnFailureListener {
    // Handle unsuccessful uploads
}.addOnSuccessListener { taskSnapshot ->
    // taskSnapshot.metadata contains file metadata such as size, content-type, etc.
    // ...
}

Java

Uri file = Uri.fromFile(new File("path/to/images/rivers.jpg"));
StorageReference riversRef = storageRef.child("images/"+file.getLastPathSegment());
uploadTask = riversRef.putFile(file);

// Register observers to listen for when the download is done or if it fails
uploadTask.addOnFailureListener(new OnFailureListener() {
    @Override
    public void onFailure(@NonNull Exception exception) {
        // Handle unsuccessful uploads
    }
}).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
    @Override
    public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
        // taskSnapshot.getMetadata() contains file metadata such as size, content-type, etc.
        // ...
    }
});

Obtenha um URL de download

Depois de fazer upload de um arquivo, você pode obter uma URL para fazer download do arquivo chamando o método getDownloadUrl() em StorageReference :

Kotlin+KTX

val ref = storageRef.child("images/mountains.jpg")
uploadTask = ref.putFile(file)

val urlTask = uploadTask.continueWithTask { task ->
    if (!task.isSuccessful) {
        task.exception?.let {
            throw it
        }
    }
    ref.downloadUrl
}.addOnCompleteListener { task ->
    if (task.isSuccessful) {
        val downloadUri = task.result
    } else {
        // Handle failures
        // ...
    }
}

Java

final StorageReference ref = storageRef.child("images/mountains.jpg");
uploadTask = ref.putFile(file);

Task<Uri> urlTask = uploadTask.continueWithTask(new Continuation<UploadTask.TaskSnapshot, Task<Uri>>() {
    @Override
    public Task<Uri> then(@NonNull Task<UploadTask.TaskSnapshot> task) throws Exception {
        if (!task.isSuccessful()) {
            throw task.getException();
        }

        // Continue with the task to get the download URL
        return ref.getDownloadUrl();
    }
}).addOnCompleteListener(new OnCompleteListener<Uri>() {
    @Override
    public void onComplete(@NonNull Task<Uri> task) {
        if (task.isSuccessful()) {
            Uri downloadUri = task.getResult();
        } else {
            // Handle failures
            // ...
        }
    }
});

Adicionar metadados de arquivo

Você também pode incluir metadados ao fazer upload de arquivos. Esses metadados contêm propriedades típicas de metadados de arquivo, como name , size e contentType (comumente chamado de tipo MIME). O método putFile() infere automaticamente o tipo MIME da extensão File , mas você pode substituir o tipo detectado automaticamente especificando contentType nos metadados. Se você não fornecer um contentType e o Cloud Storage não puder inferir um padrão da extensão do arquivo, o Cloud Storage usará application/octet-stream . Consulte a seção Usar metadados de arquivo para obter mais informações sobre metadados de arquivo.

Kotlin+KTX

// Create file metadata including the content type
var metadata = storageMetadata {
    contentType = "image/jpg"
}

// Upload the file and metadata
uploadTask = storageRef.child("images/mountains.jpg").putFile(file, metadata)

Java

// Create file metadata including the content type
StorageMetadata metadata = new StorageMetadata.Builder()
        .setContentType("image/jpg")
        .build();

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

Gerenciar envios

Além de iniciar uploads, você pode pausar, retomar e cancelar uploads usando os métodos pause() , resume() e cancel() . Os eventos de pausa e retomada geram 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.

Kotlin+KTX

uploadTask = storageRef.child("images/mountains.jpg").putFile(file)

// Pause the upload
uploadTask.pause()

// Resume the upload
uploadTask.resume()

// Cancel the upload
uploadTask.cancel()

Java

uploadTask = storageRef.child("images/mountains.jpg").putFile(file);

// Pause the upload
uploadTask.pause();

// Resume the upload
uploadTask.resume();

// Cancel the upload
uploadTask.cancel();

Monitore o progresso do upload

Você pode adicionar ouvintes para lidar com sucesso, falha, progresso ou pausas em sua tarefa de upload:

Tipo de ouvinte Uso típico
OnProgressListener Esse ouvinte é chamado periodicamente à medida que os dados são transferidos e pode ser usado para preencher um indicador de upload/download.
OnPausedListener Esse ouvinte é chamado sempre que a tarefa é pausada.
OnSuccessListener Este ouvinte é chamado quando a tarefa é concluída com êxito.
OnFailureListener Este ouvinte é chamado sempre que o upload falha. Isso pode acontecer devido a tempos limite de rede, falhas de autorização ou se você cancelar a tarefa.

OnFailureListener é chamado com uma instância Exception . Outros ouvintes são chamados com um objeto UploadTask.TaskSnapshot . Este objeto é uma visão imutável da tarefa no momento em que o evento ocorreu. Um UploadTask.TaskSnapshot contém as seguintes propriedades:

Propriedade Tipo Descrição
getDownloadUrl String Uma URL que pode ser usada para fazer download do objeto. Este é um URL público indecifrável que pode ser compartilhado com outros clientes. Este valor é preenchido quando o upload é concluído.
getError Exception Se a tarefa falhar, isso terá como causa uma Exceção.
getBytesTransferred long O número total de bytes que foram transferidos quando esse instantâneo foi obtido.
getTotalByteCount long O número total de bytes que se espera que sejam carregados.
getUploadSessionUri String Um URI que pode ser usado para continuar esta tarefa por meio de outra chamada para putFile.
getMetadata StorageMetadata Antes da conclusão de um upload, estes são os metadados que estão sendo enviados ao servidor. Após a conclusão do upload, estes são os metadados retornados pelo servidor.
getTask UploadTask A tarefa que criou este instantâneo. Use esta tarefa para cancelar, pausar ou retomar o upload.
getStorage StorageReference O StorageReference usado para criar o UploadTask .

Os ouvintes de eventos UploadTask fornecem uma maneira simples e poderosa de monitorar eventos de upload.

Kotlin+KTX

// Observe state change events such as progress, pause, and resume
// You'll need to import com.google.firebase.storage.component1 and
// com.google.firebase.storage.component2
uploadTask.addOnProgressListener { (bytesTransferred, totalByteCount) ->
    val progress = (100.0 * bytesTransferred) / totalByteCount
    Log.d(TAG, "Upload is $progress% done")
}.addOnPausedListener {
    Log.d(TAG, "Upload is paused")
}

Java

// Observe state change events such as progress, pause, and resume
uploadTask.addOnProgressListener(new OnProgressListener<UploadTask.TaskSnapshot>() {
    @Override
    public void onProgress(UploadTask.TaskSnapshot taskSnapshot) {
        double progress = (100.0 * taskSnapshot.getBytesTransferred()) / taskSnapshot.getTotalByteCount();
        Log.d(TAG, "Upload is " + progress + "% done");
    }
}).addOnPausedListener(new OnPausedListener<UploadTask.TaskSnapshot>() {
    @Override
    public void onPaused(UploadTask.TaskSnapshot taskSnapshot) {
        Log.d(TAG, "Upload is paused");
    }
});

Lidar com mudanças no ciclo de vida da atividade

Os uploads continuam em segundo plano mesmo após alterações no ciclo de vida da atividade (como apresentar uma caixa de diálogo ou girar a tela). Todos os ouvintes que você anexou também permanecerão anexados. Isso poderá causar resultados inesperados se eles forem chamados após a interrupção da atividade.

Você pode resolver esse problema inscrevendo seus ouvintes em um escopo de atividade para cancelar o registro automaticamente quando a atividade for interrompida. Em seguida, use o método getActiveUploadTasks quando a atividade for reiniciada para obter tarefas de upload que ainda estão em execução ou concluídas recentemente.

O exemplo abaixo demonstra isso e também mostra como persistir o caminho de referência de armazenamento utilizado.

Kotlin+KTX

override fun onSaveInstanceState(outState: Bundle) {
    super.onSaveInstanceState(outState)

    // If there's an upload in progress, save the reference so you can query it later
    outState.putString("reference", storageRef.toString())
}

override fun onRestoreInstanceState(savedInstanceState: Bundle) {
    super.onRestoreInstanceState(savedInstanceState)

    // If there was an upload in progress, get its reference and create a new StorageReference
    val stringRef = savedInstanceState.getString("reference") ?: return

    storageRef = Firebase.storage.getReferenceFromUrl(stringRef)

    // Find all UploadTasks under this StorageReference (in this example, there should be one)

    val tasks = storageRef.activeUploadTasks

    if (tasks.size > 0) {
        // Get the task monitoring the upload
        val task = tasks[0]

        // Add new listeners to the task using an Activity scope
        task.addOnSuccessListener(this) {
            // Success!
            // ...
        }
    }
}

Java

@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);

    // If there's an upload in progress, save the reference so you can query it later
    if (mStorageRef != null) {
        outState.putString("reference", mStorageRef.toString());
    }
}

@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
    super.onRestoreInstanceState(savedInstanceState);

    // If there was an upload in progress, get its reference and create a new StorageReference
    final String stringRef = savedInstanceState.getString("reference");
    if (stringRef == null) {
        return;
    }
    mStorageRef = FirebaseStorage.getInstance().getReferenceFromUrl(stringRef);

    // Find all UploadTasks under this StorageReference (in this example, there should be one)
    List<UploadTask> tasks = mStorageRef.getActiveUploadTasks();
    if (tasks.size() > 0) {
        // Get the task monitoring the upload
        UploadTask task = tasks.get(0);

        // Add new listeners to the task using an Activity scope
        task.addOnSuccessListener(this, new OnSuccessListener<UploadTask.TaskSnapshot>() {
            @Override
            public void onSuccess(UploadTask.TaskSnapshot state) {
                // Success!
                // ...
            }
        });
    }
}

getActiveUploadTasks recupera todas as tarefas de upload ativas na referência fornecida e abaixo dela, portanto, você pode precisar lidar com várias tarefas.

Continuando uploads em reinicializações de processos

Se o seu processo for encerrado, todos os uploads em andamento serão interrompidos. No entanto, você pode continuar o upload assim que o processo for reiniciado, retomando a sessão de upload com o servidor. Isso pode economizar tempo e largura de banda ao não iniciar o upload desde o início do arquivo.

Para fazer isso, comece o upload via putFile . No StorageTask resultante, chame getUploadSessionUri e salve o valor resultante em armazenamento persistente (como SharedPreferences).

Kotlin+KTX

uploadTask = storageRef.putFile(localFile)
uploadTask.addOnProgressListener { taskSnapshot ->
    sessionUri = taskSnapshot.uploadSessionUri
    if (sessionUri != null && !saved) {
        saved = true
        // A persisted session has begun with the server.
        // Save this to persistent storage in case the process dies.
    }
}

Java

uploadTask = mStorageRef.putFile(localFile);
uploadTask.addOnProgressListener(new OnProgressListener<UploadTask.TaskSnapshot>() {
    @Override
    public void onProgress(UploadTask.TaskSnapshot taskSnapshot) {
        Uri sessionUri = taskSnapshot.getUploadSessionUri();
        if (sessionUri != null && !mSaved) {
            mSaved = true;
            // A persisted session has begun with the server.
            // Save this to persistent storage in case the process dies.
        }
    }
});

Depois que o processo for reiniciado com um upload interrompido, chame putFile novamente. Mas dessa vez passe também pelo Uri que foi salvo.

Kotlin+KTX

// resume the upload task from where it left off when the process died.
// to do this, pass the sessionUri as the last parameter
uploadTask = storageRef.putFile(
    localFile,
    storageMetadata { },
    sessionUri,
)

Java

//resume the upload task from where it left off when the process died.
//to do this, pass the sessionUri as the last parameter
uploadTask = mStorageRef.putFile(localFile,
        new StorageMetadata.Builder().build(), sessionUri);

As sessões duram uma semana. Se você tentar retomar uma sessão após ela ter expirado ou se houver um erro, você receberá um retorno de chamada de falha. É sua responsabilidade garantir que o arquivo não tenha sido alterado entre os uploads.

Manipulação de erros

Há vários motivos pelos quais podem ocorrer erros no upload, incluindo a inexistência do arquivo local ou o usuário não ter permissão para fazer upload do arquivo desejado. Você pode encontrar mais informações sobre erros na seção Tratar erros dos documentos.

Exemplo completo

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

Kotlin+KTX

// File or Blob
file = Uri.fromFile(File("path/to/mountains.jpg"))

// Create the file metadata
metadata = storageMetadata {
    contentType = "image/jpeg"
}

// Upload file and metadata to the path 'images/mountains.jpg'
uploadTask = storageRef.child("images/${file.lastPathSegment}").putFile(file, metadata)

// Listen for state changes, errors, and completion of the upload.
// You'll need to import com.google.firebase.storage.component1 and
// com.google.firebase.storage.component2
uploadTask.addOnProgressListener { (bytesTransferred, totalByteCount) ->
    val progress = (100.0 * bytesTransferred) / totalByteCount
    Log.d(TAG, "Upload is $progress% done")
}.addOnPausedListener {
    Log.d(TAG, "Upload is paused")
}.addOnFailureListener {
    // Handle unsuccessful uploads
}.addOnSuccessListener {
    // Handle successful uploads on complete
    // ...
}

Java

// File or Blob
file = Uri.fromFile(new File("path/to/mountains.jpg"));

// Create the file metadata
metadata = new StorageMetadata.Builder()
        .setContentType("image/jpeg")
        .build();

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

// Listen for state changes, errors, and completion of the upload.
uploadTask.addOnProgressListener(new OnProgressListener<UploadTask.TaskSnapshot>() {
    @Override
    public void onProgress(UploadTask.TaskSnapshot taskSnapshot) {
        double progress = (100.0 * taskSnapshot.getBytesTransferred()) / taskSnapshot.getTotalByteCount();
        Log.d(TAG, "Upload is " + progress + "% done");
    }
}).addOnPausedListener(new OnPausedListener<UploadTask.TaskSnapshot>() {
    @Override
    public void onPaused(UploadTask.TaskSnapshot taskSnapshot) {
        Log.d(TAG, "Upload is paused");
    }
}).addOnFailureListener(new OnFailureListener() {
    @Override
    public void onFailure(@NonNull Exception exception) {
        // Handle unsuccessful uploads
    }
}).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
    @Override
    public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
        // Handle successful uploads on complete
        // ...
    }
});

Agora que você fez upload dos arquivos, vamos aprender como baixá-los do Cloud Storage.